What the agent does
The agent reads the failure before it reads any code. From the workflow_run event it runs gh run view <run id> --log-failed and names the job that failed. That matters in a Rails repository like lobsters/lobsters, whose .github/workflows/check.yml has four jobs with different failure modes: test runs bundle exec rspec, lint runs bundle exec standardrb, security runs bundle exec brakeman --ensure-ignore-notes, and database-consistency loads the schema and runs the database_consistency gem against the models. A red lint job is a formatting diff, a red security job is usually a Brakeman warning whose ignore entry lacks a note, and only the test job needs a spec reproduced. The agent quotes the failing block and says which case it is.
Then it builds the same environment. .ruby-version pins Ruby 4.0.0 and the Gemfile resolves to Rails 8.1.3.1 and rspec-rails 8.0.2. The workflow installs libvips for ruby-vips, copies the test credentials with cp .github/workflows/check/* config/, installs config/database.yml.sample as config/database.yml, which puts the primary, cache, queue and rack_attack databases on SQLite files under db/test, and runs ./bin/rails db:schema:load db:migrate. Every job sets RUBYOPT to --yjit --enable-frozen-string-literal --debug-frozen-string-literal, so a spec that passes locally but fails in CI is often a string mutated in place. lib/tasks/build.rake is the maintainers' local copy of those steps, and the agent reads it when a step is unclear.
With the environment in place it runs the exact failing command, narrowed first: bundle exec rspec spec/requests/stories_spec.rb -e "returns previous discussions for an existing story" for one example, with the same RUBYOPT, so the failure is on record before any change. It then reads the code the spec covers, such as StoriesController#show, which redirects merged stories, renders a 404 when the story may not be seen and canonicalizes the title path, or CommentsController#create, which answers 400 for a missing story, rejects a parent comment from another story, and skips a duplicate submission. It reads the commit that broke the job as well, because the fix belongs where that commit changed behavior.
The fix goes in the application code. A test is changed only when the test itself is wrong, and the pull request says so. Before pushing, the agent runs the whole bundle exec rspec, then bundle exec standardrb and bundle exec brakeman --ensure-ignore-notes, so a fix for the test job does not turn the lint or security job red in the next run. Each job has timeout-minutes: 15, and the agent notes when a spec it added is slow enough to matter.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "codex",
"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 (test, lint, security or database-consistency), and quote the failing example, standardrb offense or Brakeman warning. Use the Ruby in .ruby-version, install libvips, copy the test credentials from .github/workflows/check/ and config/database.yml.sample into config/ as the workflow does, run bin/rails db:schema:load db:migrate, and reproduce the failure with the same command and the workflow's RUBYOPT, narrowed to the failing spec first. Fix the cause in the application code (change a test only if the test is wrong, and say so), then run bundle exec rspec, bundle exec standardrb and bundle exec brakeman --ensure-ignore-notes until all three pass, and 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"
}
]
}- 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.
- 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.
- 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 in app/ and the job name and quoted failure in the description. For a test failure the description shows the single example failing and then passing, then the full rspec run; for a lint failure it shows the standardrb offense; for a security failure it shows the Brakeman warning and the note it added or the code it changed. Every command the agent ran in its sandbox is listed, and the session's trajectory keeps each with its output.
When the log shows a failure the sandbox cannot reproduce, such as a flaky example that passes on rerun, the agent says so, runs the example several times, and either fixes the order dependence it finds or reports that it found none rather than retrying CI blindly. When there is no code cause, it opens nothing and its answer explains what the log shows.
A reviewer checks that an edited spec was really wrong, that a Brakeman ignore entry carries a real note, that the change keeps the frozen string literal option happy, and that config/ and the workflow are untouched.
Run it on every failed Rails 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 then starts one run with the event under the prompt; the trigger fires only for work by owners, members and collaborators, so a fork's red build does not start one. Alternatively, send GitHub's workflow_run webhook to your own server and send this request yourself with https://github.com/<owner>/<repo>/tree/<head_branch> as the resource.
Exclude branches the agent opened so its own pull request's failure does not start a second run, keep each workflow_run.id with the returned 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.
The use case this job follows, with its automation and trigger: Fix a bug from an alert.
Why run it on Rush?
A red Rails build with four jobs is tedious on a laptop: you scroll the log to find which job failed, install the right Ruby and libvips, copy credentials, load the schema, and only then rerun the spec with the flags CI used. The agent does that in its own sandbox from the workflow file, without touching your checkout or your local databases.
What it hands back is checkable: the quoted failure, the trajectory with every rspec, standardrb and brakeman run and its output, and the workflow rerunning on the pull request. Failures on several branches each get their own run at the same time, and nothing merges without a reviewer.
Frequently asked questions
Will it fix a lint failure by changing the standardrb config?
No. It runs bundle exec standardrb --fix on the offending files only where the fix is mechanical, and otherwise edits the code by hand. A change to .standard.yml would show in the diff and the prompt does not ask for one.
Does it need MySQL?
Not in this repository: config/database.yml.sample puts every connection on SQLite under db/test, so db:schema:load runs in the sandbox with no server. A Rails app on MySQL or Postgres gets that server started the way its workflow's services block does.
What about the database-consistency job?
It copies the same credentials and schema steps as the test job and then runs the database_consistency gem. The agent reproduces that command and fixes the model or migration it complains about, with the same rule that a check is silenced only with a stated reason.
Will it touch the credentials in .github/workflows/check/?
No. It copies them into config/ for the run, exactly as CI does, and the pull request never includes config/credentials.yml.enc, config/master.key or config/database.yml.