All jobs

Turn Linear Issues Into Pull Requests for a Rails App

Yes. Give the run a Linear issue and your Rails repository: the agent changes the push or API controller, runs bin/rails test and opens a linked pull request.

Run this on RushIn a Project that has your repository.

What the agent does

The issue goes in as a resource. https://linear.app/<workspace>/issue/<ID> in resources puts the issue in the prompt through your Linear connection, beside the repository URL that clones the code, and the agent reads description, comments and acceptance criteria before touching a file.

In a Rails application like rubygems/rubygems.org, .ruby-version is 4.0.6 and the Gemfile pins rails 8.1 with clearance for sessions, good_job for jobs and flipper for flags. The gem push is Api::V1::RubygemsController#create in app/controllers/api/v1/rubygems_controller.rb, guarded by authenticate_with_api_key, verify_with_otp and a Pundit authorize Rubygem, :create?, then a scope check @api_key.can_push_rubygem?. It accepts a raw body or a multipart upload with a gem file and an attestations array, hands both to Pusher.new(@api_key, gem_body, request:, attestations:) and renders gemcutter.message with gemcutter.code. app/models/pusher.rb does the work in process: authorize, verify_gem_scope, verify_mfa_requirement, validate, save, with pull_spec, verify_sigstore, write_gem and persist_version below.

A ticket about push behaviour lands in one of those methods; a ticket about an API response lands in the controller or its policy in app/policies/rubygem_policy.rb. The agent changes the method that owns the behaviour, keeps the API key scope and MFA checks as they are unless the ticket says otherwise, and writes the test in the repository's style: Minitest with shoulda-context, so context "On POST to create for new gem" blocks with should assertions, factories from test/factories/ and gem_file from test/helpers/gem_helpers.rb, which reads test-0.0.0.gem and whose happy path expects the response Successfully registered gem: test (0.0.0).

The suite needs PostgreSQL, which .github/actions/setup-rubygems.org provides with docker compose up -d --wait, a copy of config/database.yml.sample and bundle exec rake db:setup assets:precompile; test/test_helper.rb also loads WebMock, Mocha and Capybara. The agent reproduces that setup in the sandbox, runs the focused file and then bin/rails test, the General leg of .github/workflows/test.yml, plus bundle exec rubocop on the files it changed, and opens the pull request with the issue URL and the test output in its description.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Implement the Linear issue given as a resource in this Rails codebase. Read the issue and its comments first. Make the change in the gem push path or the API controller the issue concerns, keeping the API key scope, MFA and Pundit checks unless the issue changes them, and keep the diff small. Add Minitest tests in the repository's shoulda-context style next to the existing ones, using the factories and gem helpers. Set up the test database the way .github/actions/setup-rubygems.org does: PostgreSQL reachable as config/database.yml.sample expects, then `bundle exec rake db:setup`. Run the changed test files and `bin/rails test`, and `bundle exec rubocop` on the files you touched; fix what fails. Open a pull request whose description links the issue, explains the change and quotes the test result. Do not merge.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    },
    {
      "url": "https://linear.app/your-org/issue/ENG-42"
    }
  ]
}
  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

A pull request on its own branch comes back, its description linking the Linear issue, naming the controller or Pusher method it changed, and quoting the Minitest summary from bin/rails test. The diff holds the change and its tests.

The pull request URL is on the session and in the run.completed webhook; your handler posts it as a comment on the issue, because the sandbox has no Linear tools of its own. The transcript keeps the database setup, each test command and every file the agent opened, so a reviewer can see that a change to verify_mfa_requirement was read against the existing MFA tests before it was made.

Before merging, a reviewer checks the change against the acceptance criteria and against what the push path protects: API key scopes, OTP verification, ownership. The System leg of CI, bin/rails test:system with Playwright, and the lint.yml checks, rubocop, herb analyze, brakeman, importmap:verify and bin/prettier, still run on the pull request.

Run it on every Linear issue labeled agent

Create an automation with a linear trigger on linear.issue.labeled, the hand-off label in config.labels and your team keys in config.teams. Labeling an issue starts one run with the issue as its context and this prompt; a label added by an app integration never fires it.

Add a linear.issue.state_changed trigger with config.states mapping a ready state to plan, so the first run only reads the code and posts a plan on the issue, and a later state to exec for the run that opens the pull request. For a codebase with this much around a push, the plan step is where a maintainer says which checks the ticket may touch.

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

Why run it on Rush?

The rubygems.org suite wants PostgreSQL, a seeded database, precompiled assets and, for system tests, a Playwright browser. Setting that up on a laptop for a one-method ticket is the reason such tickets wait. On Rush the agent does it in a sandbox that is discarded afterwards, and every command's output stays with the run.

Changes to a gem push need proof more than most. The pull request quotes the suite and the transcript shows the rubygems_controller_test.rb contexts the agent ran, so a reviewer sees that the MFA and scope checks still pass rather than reading that they should. Several tickets run at once, each in its own sandbox with its own database.

Frequently asked questions

How does the agent read the Linear issue?

From the resources entry with its URL. Rush reads it through your Linear connection and puts it in the prompt before the run starts. Connect Linear once with POST /me/connections {"type": "app", "name": "linear"}; an issue URL with no connection answers 422 RESOURCE_NOT_ACCESSIBLE.

Can it post the pull request link back on the issue?

Not from the sandbox; a Linear sign-in cannot yet be named in connections. Read the URL from the session or the webhook and post it from your handler.

Does it run the system tests?

bin/rails test is the General leg. Add bin/rails test:system to the prompt when the ticket changes a view; it needs the Chromium that bin/playwright install --with-deps chromium fetches, which bin/setup runs.

What about the Avo admin and the secrets CI uses?

CI runs a third leg, test test/*/avo, and sets REQUIRE_AVO_PRO only on the upstream repository. A fork without those secrets runs the general suite the same way, which is what the sandbox does.