What the agent does
A plan run reads and does not write. The agent clones the repository into its own sandbox, reads the issue, then reads the code it touches. Take a feature request against the conversations API of a support platform like chatwoot/chatwoot: a new filter or a new action on a conversation. The agent starts at the project's own guide, AGENTS.md, which says to run a single spec with bundle exec rspec spec/path/to/file_spec.rb, to validate parameters at the controller boundary so bad input answers 422, to write queries in ActiveRecord rather than raw SQL, and to create migrations with bundle exec rails g migration so the version is a real timestamp. .ruby-version pins Ruby 3.4.4 and the Gemfile pins rails 7.2.3.1 and sidekiq 7.3, with rspec-rails and factory_bot_rails in the test group.
Then it follows the request path. config/routes.rb declares resources :conversations under the account API with collection routes for meta, search, unread_counts and filter and member routes for mute, unmute, transcript, toggle_status, toggle_priority, custom_attributes and attachments, so a new endpoint is a line there first. app/controllers/api/v1/accounts/conversations_controller.rb is 240 lines and mostly delegates: index, meta and search go through ConversationFinder in app/finders, which returns the conversations plus mine, assigned, unassigned and all counts; filter goes through Conversations::FilterService and rescues the four CustomExceptions::CustomFilter errors into a 422; create wraps ConversationBuilder and Messages::MessageBuilder in one transaction. The before_action list at the top loads the conversation for every member action and validates assignment targets, inbox, contact and contact_inbox on create. app/models/conversation.rb holds the status enum (open, resolved, pending, snoozed) and the priority enum (low to urgent), the scopes such as unassigned and unattended, and the validations on account, inbox and contact.
It checks how tests are written before naming new ones. spec/controllers/api/v1/accounts/conversations_controller_spec.rb is a 1,521-line request spec: it creates an account and an agent with factory_bot, signs requests with create_new_auth_token, and asserts expect(response).to conform_schema(200), so every response is checked against the OpenAPI document under swagger/. A new endpoint therefore needs a swagger path as well as a spec. The finder and the builder have their own specs under spec/finders and spec/builders. .github/workflows/run_foss_spec.yml runs the suite on PostgreSQL and Redis services after bundle exec rake db:create and db:schema:load, strips the enterprise directory first, and splits the spec files across nodes, so a slow spec shows up in the --profile output.
The plan it posts names each file with the reason it changes, the request specs to add with the cases each covers (the happy path, an unauthenticated call, an agent outside the inbox, invalid parameters), the swagger path to add, the risks, and the questions only the issue's author can answer. Risks the code makes plain: a new conversation column is a migration and a change to the jbuilder views, the enterprise directory may override the same controller, and an action that touches many conversations belongs in a Sidekiq job rather than the request.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Read the Linear issue in this run's resources and the code it touches in the conversations API: config/routes.rb, app/controllers/api/v1/accounts/conversations_controller.rb, the finders, builders and services it calls, app/models/conversation.rb and the matching specs under spec/. Change no code. Reply with an implementation plan: the files to change with the reason for each, the RSpec request and unit specs to add with the cases each covers, the swagger path to add if the API changes, the risks, and the open questions for the author.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
},
{
"url": "https://linear.app/your-workspace/issue/ENG-42"
}
]
}- 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 the plan as the run's answer: the session read returns it as result, and a run started by the Linear state trigger posts it as a comment on the issue. It is organised as the prompt asks. A file list with one reason per file, for a conversations change typically config/routes.rb, the controller, a finder or service, a jbuilder view, a swagger path file and a migration when a column is needed. A spec list naming each case and the file it belongs in. Then risks and open questions.
The questions are where a plan earns its keep. For a new conversation filter they include whether it applies to the agent's inboxes only or the whole account, whether it should count toward the meta counts, whether the enterprise edition needs the same change, and whether the public API under the platform routes should expose it too. The issue's author answers those on the issue before anyone writes code.
Nothing is pushed and no branch is created. The session's record keeps every file the agent opened and every command it ran, so a reader can check a claim like 'filter rescues the custom filter exceptions into a 422' against the controller the agent actually read.
Run it on every Linear issue moved to Planning
Add an automation to the Project with a linear trigger on linear.issue.state_changed and map a state, such as Planning, to plan in its states. Moving an issue into that state starts a read-only run that posts its plan as a comment on the issue through the runner's Linear connection. Map a later state, such as Ready, to exec, and moving the issue on starts an ordinary run that builds it.
From your own server, the same plan comes from this request with the issue's URL in resources; read it from the session's result when the run.completed webhook arrives.
The use case this job follows, with its automation and trigger: Turn a Linear label into a PR.
Why run it on Rush?
A plan is only as good as the code read behind it. On Rush the agent reads the real repository in its own sandbox, can run bundle exec rspec on the conversations spec to see how the API behaves today, and every file and command is kept on the session, so the plan's claims can be checked rather than trusted.
Planning stops waiting on the one engineer who knows the conversations code. Every issue moved into the planning state gets its own run at the same time, the plans land on the issues where the team already discusses work, and the people who know the product answer the open questions before the build starts.
Frequently asked questions
Can a plan run change my code?
A run started by a state mapped to plan is read-only and posts a comment. A run started from the API follows its prompt, which here says to change no code and to reply with the plan, and it opens no pull request.
Does the plan account for the swagger contract?
Yes. The request spec asserts conform_schema against the OpenAPI document, so a response change without a swagger change fails the suite. The plan lists the path file to edit alongside the controller.
What if the issue is too vague to plan?
Then most of the plan is open questions, which is still useful: it shows the author exactly what is missing. Answer them on the issue and move it back into the planning state to get a revised plan.
Will it suggest raw SQL or a hand-written migration version?
No. The repository's AGENTS.md forbids both, and the plan follows it: ActiveRecord queries, and a migration generated with rails g migration so the timestamp is real.