# Fix Failing GitHub Actions Checks in a Phoenix App

Yes. When your Phoenix build goes red, an agent reads the failed job's log, reruns the same mix command against Postgres, fixes the cause and opens a pull request.

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

## What the agent does

The agent reads the failed job first. From the `workflow_run` event it runs `gh run view <run id> --log-failed` and names the job, because a Phoenix repository like hexpm/hexpm fails in different ways per job. `.github/workflows/main.yml` has `format`, which runs `mix compile --warnings-as-errors`, `mix format --check-formatted` and `mix ecto.setup` to prove the seeds still load; `test-hexpm`, which runs `mix test` with `MIX_ENV=test`; `test-hex`, which clones the Hex client at `main`, `v2.5` and `v2.4` and runs its suite with `--include integration` against this server; and `docker`, which builds the image. A compile warning, a formatting diff, a broken seed, an ExUnit failure and a client-compatibility break are five different fixes, and the agent quotes the block that says which one it has.

Then it matches the toolchain. The workflow pins Elixir 1.20.4 on OTP 29.1 and starts `postgres:18` with user, password and database all `postgres`; `mix.exs` requires Elixir 1.20 and depends on Phoenix `~> 1.6`, `ecto_sql`, `postgrex`, Oban `~> 2.23` and Sentry `~> 13.0`. The `test` alias runs `ecto.create --quiet`, `ecto.load --skip-if-loaded`, `ecto.migrate` and then `test`, so the database schema comes from `priv/repo/structure.sql` and needs the `pg_trgm` and `pgcrypto` modules the README names. `test/test_helper.exs` installs the `Hexpm.LogLines` logger handler, starts the in-memory store from `config/test.exs`, builds the registry for the `hexpm` repository and puts the SQL sandbox in manual mode. The agent reproduces with the failing file alone, such as `mix test test/hexpm_web/controllers/api/release_controller_test.exs:310`, with `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` set as the workflow sets it.

With the failure on record it reads what the test covers. For publishing that is `lib/hexpm_web/controllers/api/release_controller.ex`: `publish` on `POST /api/publish` and `create` on `POST /api/packages/:name/releases`, behind plugs that fetch the body under a size limit, parse the tarball, fetch the package and authorize with the `api:write` or `package` domains, with workload identity allowed; `publish` then reads the release metadata and checksums, logs the tarball under the repository, name and version, and calls `Releases.publish`. The tests in `test/hexpm_web/controllers/api/release_controller_test.exs` build tarballs with `test/support/tarball_helpers.ex` and cover escaping symlinks and paths, more than 10,000 files, unexpected outer files, metadata names over 255 bytes and refusing an unauthenticated caller before the body is read. `package_controller.ex` with `index`, `show` and `audit_logs` has its own test file beside it. The agent reads the commit that broke the job as well.

The fix goes in `lib/`. A test is changed only when the test is wrong, and the pull request says so. Before pushing, the agent runs the full `mix test`, then `mix format --check-formatted` and `mix compile --warnings-as-errors` for the `format` job, and when the change touched a controller the Hex client calls, it clones `hexpm/hex` as the `test-hex` job does and runs that suite with `HEXPM_PATH=..` and `MIX_OS_CONCURRENCY_LOCK=0`, so a fix for one job does not break the next.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "The GitHub Actions workflow on this branch failed; the workflow_run event is at the end of this prompt. Read the failed job's log with gh run view <run id> --log-failed, name the job that failed (format, test-hexpm, test-hex or docker) and quote the failing test, warning or diff. Use the Elixir and OTP the workflow pins, start Postgres with the pg_trgm and pgcrypto modules, run mix deps.get, and reproduce the failure with the same command narrowed to the failing file and line first. Fix the cause in lib/ (change a test only if the test is wrong, and say so), then run mix test, mix format --check-formatted and mix compile --warnings-as-errors; if you changed an API controller the Hex client calls, clone hexpm/hex and run its suite with --include integration and HEXPM_PATH set as the test-hex job does. Open a pull request against the failing branch that quotes the error it fixed.\n\nEvent: <workflow_run payload>",
  "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

A pull request against the failing branch, with the fix under `lib/` and the job and quoted failure in the description. It shows the single test failing and then passing, then the full `mix test`, the format check and the warnings-as-errors compile, and the Hex client suite when it ran; the session's trajectory keeps every command with its output. The workflow reruns all four jobs on the pull request.

When the failing job is `format` because `mix ecto.setup` broke, the pull request fixes the seed or the migration and the description shows `ecto.setup` passing again. When the failure is only in `test-hex` for one client version, the description names that version and the request the client sends. When there is no code cause, it opens nothing and its answer explains what the log shows.

A reviewer checks that a change to `publish` or `create` still refuses what the tarball tests refuse, that no test lost a `@tag` or an assertion, and that `mix.exs`, `config/test.exs` and the workflow are untouched.

## Run it on every failed Phoenix workflow run

Add an automation to the Project with this prompt and a `github` trigger on `workflow_run.failure`; each failed run of the `CI` workflow starts one run with the event under the prompt, and only work by owners, members and collaborators fires it. Or send GitHub's `workflow_run` webhook to your own server and send this request with `https://github.com/<owner>/<repo>/tree/<head_branch>` as the resource.

Exclude the agent's own branches so a failed fix does not trigger itself, keep each `workflow_run.id` with the `execution_id` to drop redeliveries, and use the `run.completed` webhook from Rush to post the pull request link on the contributor's pull request.

## Why run it on Rush?

A red Phoenix build with a Postgres schema file, a registry build in the test helper and a second repository's suite in the matrix is more setup than most developers keep on a laptop. The agent builds it from the workflow file in its own sandbox, with the pinned Elixir and OTP, and runs the failing file the way the runner did.

What it hands back is checkable: the quoted failure, the trajectory with every `mix` command and its output, and all four jobs rerunning on the pull request. Failures on several branches each get their own run in parallel, and nothing merges without a reviewer.

## Frequently asked questions

### Does it run the Hex client's suite every time?

Only when the failing job was `test-hex` or the fix touched an API controller the client calls. That suite clones a second repository and runs with `--include integration`, so the agent runs it when it matters and says in the pull request whether it did.

### Why does it need pg_trgm and pgcrypto?

Because `priv/repo/structure.sql`, loaded by the `test` alias through `ecto.load`, uses them, and the README says the migrations fail without them. The agent starts a Postgres image that ships both, as the workflow's `postgres:18` does.

### Will it fix a compile warning by turning off --warnings-as-errors?

No. The flag lives in the workflow, which the prompt leaves alone, and a change there would show in the diff. It fixes the warning in the module that raised it.

### Which Elixir and OTP does it use?

The ones the workflow's `env` pins, Elixir 1.20.4 on OTP 29.1, installed the way `erlef/setup-beam` installs them. `mix.exs` requires Elixir 1.20, so an older local version would not even compile.
