All jobs

Turn Sentry Errors Into Fix Pull Requests for a Phoenix App

Yes. A Sentry alert starts a run; the agent reads the Elixir stack trace, reproduces it with an ExUnit test against your Phoenix app and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

A Phoenix app that uses the sentry package reports an exception with the module, function and arity of each frame, the Plug route, and the request id, so the agent has an exact starting point. It reads the alert payload after the prompt, fetches the issue and its latest event through the Sentry connection, and keeps the exception, the frames, the route and the breadcrumbs. Then it opens its clone of the repository and reads the controller action and the context functions the frames name.

In a Phoenix app like hexpm/hexpm, mix.exs requires Elixir ~> 1.20 and lists {:sentry, "~> 13.0"}; config/config.exs points the SDK at Hexpm.SentryClient, a Finch-based HTTP client, and config/prod.exs turns on source code context and a before_send in Hexpm.Application that drops websocket protocol errors, anything whose Plug.Exception.status is under 500 and a list of metric-only classes, with Oban errors captured through the integration. That tells the agent what reached Sentry was a real 500 or a job failure. The publish path is lib/hexpm_web/controllers/api/release_controller.ex: publish/2 runs behind fetch_body with a tarball size limit, parse_tarball, maybe_fetch_package and an authorize plug that allows workload identities, calls release_metadata/2, which checks Hexpm.TarballLimits and unpacks the metadata into a temporary directory, logs the tarball under debug/tarballs with a random id, and hands the result to Releases.publish/8, an Ecto.Multi in lib/hexpm/repository/releases.ex that creates the package and release, matches security advisories, recomputes dependants and writes the audit log inside one transaction. publish_result/2 renders 201 with a location header, a validation failure or a changeset error. create/2, show/2 and delete/2 sit beside it, and package_controller.ex serves index, show and audit_logs.

The test goes next to the existing ones in test/hexpm_web/controllers/api/release_controller_test.exs, which uses HexpmWeb.ConnCase with async: true, ex_machina insert/2 factories for users, repositories, packages and releases, and create_tar/1 from test/support/tarball_helpers.ex to build a publishable tarball from a metadata map. The agent writes a test that posts the tarball or request the Sentry event implies, a metadata map with the field that broke, or a package name that does not match the URL, and asserts the response the code should give. mix test test/hexpm_web/controllers/api/release_controller_test.exs:<line> runs that one case; test/test_helper.exs starts the in-memory store, puts the SQL sandbox in manual mode and builds the registry, and config/test.exs keeps every bucket in Hexpm.Store.Memory.

Then it fixes the controller or the context, reruns the test until it passes, and runs mix format --check-formatted and mix test, the two commands the main.yml workflow runs on OTP 29.1 and Elixir 1.20.4 with a Postgres service. The suite needs Postgres with the pg_trgm and pgcrypto modules, as the README says, and mix setup creates and seeds it; the sandbox runs Postgres for this. The agent does not add a rescue in the action to turn an exception into a 422; it validates the input where release_metadata/2 already validates, or fixes the function that assumed a field was present.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "A Sentry alert fired for this Phoenix app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request route and the stack frames with their module, function and arity. Find the failing code, starting with the API controllers under lib/hexpm_web/controllers/api, in particular release_controller.ex and package_controller.ex, and the context functions they call under lib/hexpm. Add an ExUnit test to the matching *_controller_test.exs under test/hexpm_web/controllers/api, using the ConnCase, the ex_machina factories and the tarball helpers already there, that reproduces the exception. Start Postgres, run `mix setup`, fix the code until the test passes, then run `mix format --check-formatted` and `mix test`. Open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Change nothing unrelated to this error.\n\nAlert payload:\n{payload}",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ],
  "connections": [
    "sentry"
  ]
}
  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

What comes back is a pull request that changes one controller or context module and adds one test block to the controller test that already covers it. The description links the Sentry issue, quotes the exception and the frames with their module and function, shows the test failing before the fix and passing after, and reports the mix format --check-formatted and mix test results. Your own CI runs on the branch as on any pull request.

The session keeps the transcript: the Sentry reads, the mix setup and mix test commands with their full output, and the files the agent opened, so a reviewer sees the suite's own summary line rather than a sentence about it. The run.completed webhook carries the agent's final message as data.result and a session_url for the rest.

Before merging, a reviewer checks that the new test sends what the Sentry request showed and not a convenient variant, that a validation added in the controller does not duplicate one the changeset in lib/hexpm already performs, and that a change inside the publish Multi still runs in the one transaction. A follow-up message to the same session changes the approach on the same branch.

Run it on every Sentry issue alert

Give the Sentry project an alert rule with a webhook action and point it at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the Sentry issue id as Idempotency-Key, so retries return the run already started. One issue, one sandbox, one pull request.

With a webhook URL on the key, Rush POSTs run.completed to your handler with session_url when the turn finishes, and the handler can comment the pull request link on the issue. Or have that handler call a webhook trigger on an automation in the Project with this prompt: it forwards the alert's JSON as the body with the trigger's secret as Authorization: Bearer, because Sentry signs its own webhooks and cannot send that header. The body becomes the event text after the prompt, and max_runs_per_hour caps an issue that keeps firing.

The use case this job follows, with its automation and trigger: Fix a bug from an alert.

Why run it on Rush?

Reproducing a Phoenix exception by hand means a Postgres with the right extensions, mix setup, a tarball built the way the test helpers build it, and the patience to wait for the suite. In a Rush sandbox the agent does all of that on its own disk with the OTP and Elixir versions the workflow names, and your checkout and database stay as they were.

The pull request arrives with its proof, a test that failed and now passes, and the session transcript shows every command behind it. Each Sentry issue is its own run in its own clone, in parallel up to the key's max_concurrent limit, so the errors a deploy leaves behind are several small reviews instead of one long triage.

Frequently asked questions

Does the sandbox need Postgres to run mix test?

Yes. The suite uses Ecto.Adapters.SQL.Sandbox against a real database, and the README asks for the pg_trgm and pgcrypto modules. The agent starts Postgres in the sandbox and runs mix setup first, the same shape as the main.yml workflow's Postgres service.

Which Elixir and OTP versions does it use?

The ones the workflow pins, Elixir 1.20.4 on OTP 29.1, which satisfy the ~> 1.20 requirement in mix.exs. The agent reads both files and says in the pull request which versions ran the tests.

What if the error came from an Oban job rather than a request?

The Sentry event says so, because config/prod.exs captures Oban errors through the integration with report_oban_error?/2 as the filter. The agent then tests the worker module directly, with the job args the event carried, instead of a controller.

Will it change the Sentry configuration itself?

No. before_send already filters 4xx responses and known noise, and that is a decision for you. If the agent finds that the exception should have been filtered, it says so in the pull request and leaves config/prod.exs alone.