# Fix Jira Bug Tickets With Pull Requests in a Rails App

Yes. An agent reads the Jira bug, reproduces it with a Minitest test in your Rails app, fixes the job or model, opens a pull request and links it on the ticket.

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

## 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`

```json
{
  "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"
    }
  ]
}
```

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 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.

## 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.
