What the agent does
Each new bug in Jira fires an automation rule that posts the key and summary to a handler on your server, and the handler sends the request on this page. The agent clones the repository into its own cloud sandbox and reads the ticket through your Atlassian connection, comments included. Bugs in background work rarely come with a stack trace; the ticket says something like "I got the same issue in my triage email two days running" or "my email limit is 3 but I got 5 issues", and the agent turns that into a precise expectation before it reads code.
In a Rails app like codetriage/CodeTriage, issue assignment is a short chain. SendSingleTriageEmailJob calls IssueAssigner.new(repo_sub.user, [repo_sub]).assign!. IssueAssigner in app/models/issue_assigner.rb is a plain Ruby object: for each subscription it selects candidate issues with SQL, calls issue.valid_for_user? on each, creates an IssueAssignment for valid ones and a delivered: true assignment for rejected ones so they are not picked again, counts against sub.email_limit, and recurses until it stops. SendDailyTriageEmailJob then skips a user for reasons such as "Not time to send", "No subscriptions", "Sent email within 24 hours" or "Email backoff", and otherwise delivers user.issue_assignments_to_deliver with deliver_later and marks them delivered. A repeated or over-limit email is a bug in one of those steps, and the agent works out which.
It reproduces the bug with Minitest where the project already tests that code: test/jobs/ has send_daily_triage_email_job_test.rb and send_single_triage_email_job_test.rb (ActiveJob::TestCase with test "..." do blocks), and test/unit/ has issue_assignment_test.rb. IssueAssigner takes can_access_network: !Rails.env.test?, so in tests it skips the GitHub fetch inside valid_for_user?, and test/test_helper.rb configures VCR with allow_http_connections_when_no_cassette = false, so a test that would call GitHub fails loudly instead of reaching the network. The agent writes its test inside those rules.
The test database is Postgres: CI copies config/database.ci.yml to config/database.yml and runs rake db:create db:schema:load against a postgres:16 service, so the agent starts Postgres in the sandbox and does the same. It fixes the code, runs bin/rails test and bundle exec standardrb (the CI lint step), opens a pull request with the ticket key in its title and branch, and comments on the ticket with the link.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "codex",
"input": "A Jira bug ticket was created; its key and summary follow this prompt. Use the Atlassian connection to read the ticket, its description and all comments. Find the cause in the issue-assignment jobs: SendSingleTriageEmailJob, SendDailyTriageEmailJob, IssueAssigner in app/models/issue_assigner.rb and Issue#valid_for_user?. Start Postgres, copy config/database.ci.yml to config/database.yml and run RAILS_ENV=test bundle exec rake db:create db:schema:load. Reproduce the bug with a failing Minitest test in test/jobs/ or test/unit/ in the existing style, with no live GitHub calls. Fix the code and run bin/rails test and bundle exec standardrb until both pass. Open a pull request with the ticket key in its title and branch name, then comment on the ticket with the pull request link and the cause in one sentence. If you cannot reproduce it, comment with what you tried and open no pull request.",
"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
What comes back is a pull request named after the ticket. In CodeTriage it usually changes app/models/issue_assigner.rb, a job under app/jobs/ or a method on Issue or User, and adds a test "..." do block to the matching file in test/jobs/ or test/unit/. The description explains the cause in terms of the chain (which step assigned or sent the wrong thing), quotes the test that failed before the change and gives the bin/rails test and standardrb results.
The ticket gets one comment with the pull request link. On GitHub the pull request runs CodeTriage's workflow: standardrb, the schema load against postgres:16, bin/rake test, and a final bin/rails db:seed to check the seeds still load. The session transcript keeps each command the agent ran and its output, including the database setup.
Before merging, a reviewer checks that the fix does not change how many emails everyone else gets (an off-by-one in stop? or the recursion can do that), that the test controls time where the job depends on it (the time-of-day and 24-hour checks), and that no new code path calls GitHub from tests. When the agent could not reproduce the report, there is no pull request and the comment on the ticket says what it tried.
Run it on every new Jira bug
In Jira, add an automation rule: trigger "Work item created", condition issue type is Bug, action "Send web request" to your handler with {{issue.key}} and {{issue.summary}}. The handler appends them to input, names your Atlassian connection in connections and sends one request per ticket. A label condition such as agent-fix lets the team choose which bugs go to the agent.
Set a webhook URL on the API key so Rush POSTs run.completed or run.failed with the session_url when each run's turn finishes. A key has at most max_concurrent runs in progress (4 by default) and answers 429 to one more.
The use case this job follows, with its automation and trigger: Fix a bug from an alert.
Why run it on Rush?
A Rails bug in background jobs needs the right Ruby (.ruby-version says 4.0.5), Bundler, Postgres with the schema loaded, and tests that control time and the network. In a Rush sandbox the agent sets all of that up on its own machine and keeps it to itself, so the ticket gets a real reproduction without a developer stopping work to rebuild their test database.
What comes back can be checked rather than taken on trust: the failing and passing runs are in the transcript, the same suite and lint run again on the pull request, and the Jira comment tells the reporter where the fix is. When several tickets arrive at once, each gets its own sandbox and branch.
Frequently asked questions
Will its test call the GitHub API?
No. IssueAssigner skips the network in the test environment, and VCR in test/test_helper.rb refuses any HTTP request with no cassette. The agent writes its test so it needs neither, and says so in the pull request if it had to record a new cassette.
Does it need Redis or Sidekiq running?
Not for the tests. The job tests use ActiveJob::TestCase, which runs jobs and checks enqueued mail in process. Postgres is the one service the agent starts, as the CI workflow does.
CI runs bin/rake test. Why does the prompt say bin/rails test?
Both run the same Minitest suite in a Rails app; bin/rails test also takes a single file or line, which the agent uses while reproducing. The pull request's workflow runs bin/rake test as before, so nothing about CI changes.
Can I pass the Jira URL in resources?
No. resources takes a GitHub repository or a Linear issue; anything else is 422 RESOURCE_UNSUPPORTED. Put the ticket key in the prompt and name your Atlassian connection.