# Upgrade Phoenix 1.7 to Phoenix 1.8

Send one request and an agent moves your app from Phoenix 1.7 to 1.8, works through the changelog's breaking changes, runs mix test, and opens a PR.

[Run this on Rush](https://cloud.getrush.ai/run/upgrade-framework-major/phoenix/), in a Project that has your repository.

## What the agent does

In a LiveView app like fly-apps/live_beats, the agent starts with mix.exs and mix.lock. The app asks for {:phoenix, "~> 1.7.1"} and the lockfile resolves 1.7.12. phoenix_live_view comes straight from its GitHub repository with override: true, phoenix_html is held at ~> 3.3 with another override, and the rest includes ecto_sql 3.11.1, postgrex 0.17.5, plug_cowboy 2.7.1 and gettext 0.20.0. The agent changes the requirement to ~> 1.8, runs mix deps.update phoenix, and lets Mix report which other packages have to move with it, rather than raising everything at once.

The v1.8 changelog states that the release requires Erlang/OTP 25 or later. live_beats' Dockerfile builds on hexpm/elixir:1.14.0-erlang-24.0.1, so the image has to change before a 1.8 release will run in production. The agent picks a builder and runner image with OTP 25 or newer and an Elixir that the rest of the dependency tree supports, and runs the tests on that same version in its sandbox, so the pull request does not pass locally and then fail in the image.

Then it goes through the changelog's deprecations and potential breaking changes against the code. lib/live_beats_web.ex calls use Phoenix.Controller with namespace: LiveBeatsWeb, and the :namespace option now emits a deprecation warning; formats: [:html, :json] is already there, which 1.8 requires. The router's browser pipeline uses put_secure_browser_headers, which in 1.8 sets a content-security-policy of base-uri 'self'; frame-ancestors 'self' when none is set, so the agent checks whether anything embeds the app in a frame. It also searches for the endpoint's removed config variable and for put_layout calls without a module. Generator changes such as daisyUI, the single root layout and scopes affect new apps only, so the agent does not rewrite existing layouts to match them.

After each step it runs mix compile --warnings-as-errors to surface deprecations and mix test, which in this project's aliases first runs ecto.create and ecto.migrate against the Postgres in config/test.exs (user postgres, database live_beats_test). There are nine test files under test/, covering accounts, the media library, MP3 parsing, auth controllers and the profile and settings LiveViews. Compiling bumblebee and exla, which the app uses for speech-to-text, takes the longest part of each build, and the agent keeps the _build directory between steps rather than starting clean each time.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Upgrade this app from Phoenix 1.7 to Phoenix 1.8 following the official upgrade notes in the Phoenix v1.8 CHANGELOG step by step. Phoenix 1.8 requires Erlang/OTP 25 or later, so update the Dockerfile's builder and runner images and use the same OTP and Elixir in your own build. Change the phoenix requirement in mix.exs and run mix deps.update phoenix, moving only the dependencies Mix requires. Handle each deprecation and potential breaking change that applies to this code (use Phoenix.Controller options, put_layout, the endpoint config variable, put_secure_browser_headers). Start Postgres as config/test.exs expects. After each step run mix compile --warnings-as-errors and mix test, and fix what breaks. Open a pull request that lists each change with the changelog item it answers, and anything you left for a person to decide.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

The pull request changes mix.exs and mix.lock, the Dockerfile's two image arguments, and the source files a changelog item touched, such as lib/live_beats_web.ex for the controller options. Its description is a checklist in changelog order: each item, whether it applied, and the commit or file that handled it. It ends with a section for decisions it did not make, for example whether the default frame-ancestors policy is right if the app is embedded anywhere, or whether to replace the GitHub-pinned phoenix_live_view with a Hex release.

A reviewer checks that mix compile --warnings-as-errors and mix test are the commands quoted in the transcript, deploys the branch to a staging app to confirm the new image boots with the OTP version the Dockerfile names, and opens the browser to check LiveView pages and the response headers. The session record, from GET /o/{org}/sessions/{id}/messages, has each step's compiler warnings and test output.

## Run it on every new Phoenix minor release

A framework major or minor upgrade does not belong on a fixed weekly timer, but it can follow the release. A small job that polls hex.pm for the phoenix package, or a weekly scheduled check, can send POST /o/{org}/sessions with this request for each Phoenix app when a new 1.x appears, with the target version in the prompt and in the Idempotency-Key.

With a webhook on the API key, the run.completed event tells your service the turn ended. It reads the session, posts the pull request to the owning team and keeps the session id, so a follow-up such as asking the agent to also move LiveView to a Hex release can be sent to the same run with POST /o/{org}/sessions/{id}/messages.

## Why run it on Rush?

A Phoenix upgrade needs the right OTP and Elixir, a Postgres server, and in an app like this a long native build for EXLA. Setting up a second OTP version next to the one a laptop uses for daily work is how environments drift. The agent does it in its own Rush sandbox, with its own database, and the output of each mix command is kept in the session, so the upgrade can be checked step by step.

This kind of change is also a good one to run across several services at the same time. Each app gets its own run and its own pull request, each run states which changelog items applied to that code, and you can ask any one of them a follow-up question about a change before you merge it, within the API key's limit on concurrent runs.

## Frequently asked questions

### Do I have to adopt the new generators, daisyUI or scopes?

No. Those changes are to what mix phx.new and the generators produce for new code. An existing app keeps its layouts and core components, and the agent leaves them unless a deprecation forces a change.

### Will it upgrade LiveView too?

Only if Mix requires it. live_beats takes phoenix_live_view from GitHub with override: true, so the agent reports whether that pin still resolves and lists moving to a Hex release as a decision for a person.

### What breaks most often going from 1.7 to 1.8?

From the changelog: the OTP 25 requirement, the removal of the config variable inside Phoenix.Endpoint, and new deprecation warnings for controller options such as :namespace. With --warnings-as-errors those warnings fail the compile, which is how the agent finds every place to change.

### Does it change response headers?

Phoenix 1.8's put_secure_browser_headers adds a default content-security-policy and stops setting x-frame-options and x-download-options. The agent keeps the framework default and names it in the pull request, so you can decide whether your app needs a different policy.
