All jobs

Turn Labeled GitHub Issues Into Pull Requests for a Phoenix App

Yes. Label a GitHub issue on a Phoenix app and an agent reproduces it with an ExUnit test, fixes the code, runs mix test and opens a pull request that closes it.

Run this on RushIn a Project that has your repository.

What the agent does

The agent starts from the labelled issue, not from a generic Phoenix layout. In a package registry shaped like hexpm/hexpm it reads mix.exs first: elixir ~> 1.20, bandit as the HTTP server, ecto_sql with PostgreSQL, broadway and broadway_sqs for background work, ex_aws for storage, hex_core for the registry format, ex_machina for factories, and lasso only in test. The aliases matter: setup runs deps.get, ecto.setup and the asset installers, and ecto.setup runs ecto.reset and the seeds, so the agent uses those rather than hand-rolling a database. The README adds that PostgreSQL needs the pg_trgm and pgcrypto modules or the migrations fail, and config/test.exs points the test repo at a hexpm_test database on localhost.

The issue text decides the controller. The API lives under lib/hexpm_web/controllers/api, and the router splits it into two scopes: an upload pipeline that takes POST /api/publish and POST /api/packages/:name/releases into ReleaseController, and a json pipeline for the reads, GET /api/packages, GET /api/packages/:name and GET /api/packages/:name/releases/:version, each repeated under /api/repos/:repository for private repositories. A publish bug leads to lib/hexpm_web/controllers/api/release_controller.ex, 322 lines of plugs and actions: fetch_body with a 16 MB tarball limit, parse_tarball, maybe_fetch_package, and an authorize plug per action that requires the api write or package domain and runs package_owner and organization_billing_active checks, with require_authentication placed before the body is read for publish. A listing bug leads to package_controller.ex, 73 lines where index parses page, search, sort and per_page, caps per_page at 100 and answers through when_stale and api_cache.

The test comes before the fix. test/hexpm_web/controllers/api/release_controller_test.exs is the pattern: use HexpmWeb.ConnCase with async true, a setup block that inserts a user, a repository, a package with the user as owner and a release with ex_machina, then a test that inserts a key, builds a conn with the content-type and authorization headers, posts a tarball made by create_tar to the releases path and asserts json_response with the expected status. ConnCase checks out the Ecto SQL sandbox, resets the in-memory store and stubs the Geo lookup through Mox. The agent adds a test to the describe block for the route it changes, confirms it fails with the reported behaviour, then changes the controller, or the Releases or Packages context under lib/hexpm/repository, until it passes.

It runs what CI runs. .github/workflows/main.yml uses OTP 29.1 and Elixir 1.20.4 with a postgres:18 service, runs mix deps.get, mix compile --warnings-as-errors, mix format --check-formatted and mix ecto.setup, then mix test; a second job runs the hex client's own suite against this server. The agent installs that OTP and Elixir pair, runs the same commands in order, and runs mix format on the files it changed because the check job fails on formatting. The pull request body starts with Closes and the issue number and explains the cause.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Fix GitHub issue #ISSUE in this Phoenix repository. Read the issue and its comments first. Start from mix.exs, its aliases and config/test.exs, then find the route in lib/hexpm_web/router.ex and the controller under lib/hexpm_web/controllers/api the report names, reading its plug chain before changing an action. Add a test to the matching module under test/hexpm_web/controllers/api that reproduces the reported behaviour with HexpmWeb.ConnCase and the existing factories, confirm it fails, then fix the controller or the context under lib/hexpm/repository until mix test passes after mix ecto.setup, and mix compile --warnings-as-errors and mix format --check-formatted pass, as .github/workflows/main.yml runs them. Do not change the Elixir requirement, mix.lock or any workflow file. Open a pull request whose body starts with Closes #ISSUE, explains the cause, lists the files and quotes the mix test summary.",
  "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

What comes back is a pull request on a new branch. The diff is the controller the issue pointed at under lib/hexpm_web/controllers/api, sometimes a context module under lib/hexpm/repository, plus one test added to the matching file under test/hexpm_web/controllers/api. The body starts with Closes and the issue number, names the cause in a sentence, lists the files, and quotes the mix test summary from the sandbox with the compile and format checks. mix.lock and the workflows are unchanged unless the issue itself asked for them.

The session read names the repository and the pull request URL. The transcript at GET /o/{org}/sessions/{id}/messages keeps each tool call: the issue read, the files opened, the database setup, and each mix invocation with its output, including the first run where the new test fails. A reviewer does not have to re-run the suite to see what the agent ran.

Before merging, a reviewer checks that the new test fails on the old code and passes on the branch, that an authorization fix went into the authorize plug and its AuthHelpers function rather than a conditional inside the action, that the tarball limit and the require_authentication ordering on publish are untouched, and that the GitHub keyword in the body points at the right issue, since it closes the issue on merge.

Run it on every labelled GitHub issue

Add an automation to the Project with this prompt and a github trigger on issues.labeled, with the label you reserve for the agent in its labels. Only a label applied by an owner, member or collaborator fires it. Each labelled issue starts one run on its own branch, and the trigger adds the issue event after the prompt, so the agent reads the number from it. From your own server, the same run starts with this request when your GitHub webhook handler sees the label, with an Idempotency-Key derived from the delivery id so a retried delivery returns the same session.

Give the API key a webhook URL and Rush POSTs run.completed, run.failed or run.cancelled when the turn ends, signed with the whsec_ secret, with data.session_url to read for the pull request. A key runs at most max_concurrent sessions at once, 4 by default, and answers 429 past that.

The use case this job follows, with its automation and trigger: Turn a Linear label into a PR.

Why run it on Rush?

Reproducing a registry bug on a laptop means the exact OTP and Elixir pair, a PostgreSQL with pg_trgm and pgcrypto, a seeded database and a tarball built the way the client builds one. The agent does that in its own sandbox with its own clone, and the sandbox parks with its disk when the turn ends, so a follow-up from the review picks up the same environment.

The proof is the pull request plus the transcript, not a claim that the tests passed. The exact mix test output, the failing first run and the test module the new case landed in are kept on the session. Several labelled issues run at once, each in its own sandbox with its own pull request, up to the key's concurrency limit.

Frequently asked questions

Does it run the hex client suite against the server too?

CI does, in its test-hex job, and the pull request's checks show the result. In the sandbox the agent runs mix test; ask for the client job in the prompt when a change to the publish path needs it before review.

Will it loosen the authorize plug to make a request succeed?

No. The domains and the package_owner and organization_billing_active checks are the contract of the API, and a fix that needs a wider domain is reported in the pull request as a question, not applied.

What if the bug is in a context module rather than the controller?

Then the fix goes under lib/hexpm/repository, where Releases.publish and Packages.search_with_versions live, with a test under test/hexpm/repository beside releases_test.exs and packages_test.exs. The controller test still reproduces the report end to end.

How does the issue text reach the agent?

A handler you run writes the issue number into input in place of #ISSUE; an automation's github trigger instead adds the issue event after the prompt and replaces nothing, and resources clones the repository through the Rush GitHub App installation. The agent then reads the issue and its comments from the repository's issue tracker with the credentials the installation provides.