What the agent does
A Spring Boot exception in Sentry arrives with the exception class, the message, the request path and a Java stack trace where the in-app frames name a controller or service method and the rest is the framework. The agent reads the alert payload after the prompt, fetches the issue and its latest event through the Sentry connection, and keeps the in-app frames, the request method and path, and the tags. Then it opens its clone and reads the methods the frames name.
In a Spring Boot app like spring-projects/spring-petclinic, pom.xml inherits spring-boot-starter-parent 4.1.0 with java.version 17, and build.gradle mirrors it; the maven-build.yml workflow runs ./mvnw -B verify on JDK 17 and gradle-build.yml runs ./gradlew build. The validate phase runs spring-javaformat:validate, so a file that is not formatted fails the build before any test runs, and checkstyle with nohttp runs too. The controllers under owner/ are small: OwnerController.showOwner loads the owner with findById and throws IllegalArgumentException through orElseThrow when there is none, processFindForm strips the last name, redirects when page is out of range and rejects the field with notFound on an empty result, and VisitController.loadPetWithVisit, a @ModelAttribute method that runs before both visit handlers, throws IllegalArgumentException for a missing owner or pet and otherwise adds a new Visit to the pet. processNewVisitForm rejects a date that is not in the future with the typeMismatch.visitDate message. CrashController maps /oups to a deliberate RuntimeException; the agent recognises it as the showcase it is and does not fix it.
The test goes in the matching @WebMvcTest class. OwnerControllerTests and VisitControllerTests use MockMvc with the repository as a @MockitoBean, so a new test stubs owners.findById to return the owner the Sentry event implies, or empty, performs the request from the event's path and method, and asserts the status and view the code should produce. The agent runs ./mvnw -Dtest=VisitControllerTests test and keeps the failure as the reproduction. Tests that need a database, PetClinicIntegrationTests on H2, MySqlIntegrationTests on Testcontainers and PostgresIntegrationTests through Docker Compose, stay out of the loop unless the fix reaches a repository or an entity.
Then it fixes the controller or the model, formats with ./mvnw spring-javaformat:apply, reruns the test until it passes and runs ./mvnw -B verify, the workflow's command, which runs format validation, checkstyle, the full test suite and jacoco. If an exception should become a 404 rather than a 500, the agent adds a @ResponseStatus or an @ExceptionHandler next to the controller instead of catching it inside the handler, and it does not change the ModelAttribute order that VisitController relies on.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "A Sentry alert fired for this Spring Boot app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request path and the in-app stack frames. Find the failing method, starting with OwnerController and VisitController in src/main/java/org/springframework/samples/petclinic/owner. Add a test to the matching @WebMvcTest class under src/test/java, stubbing the repository as a @MockitoBean and performing the request from the event, that reproduces the exception. Fix the code until the test passes, run `./mvnw spring-javaformat:apply`, then `./mvnw -B verify`. Open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Leave CrashController alone; it throws on purpose. Change nothing unrelated to this error.\n\nAlert payload:\n{payload}",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
],
"connections": [
"sentry"
]
}- 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
You get a pull request with the fix in one controller or model class and a new @Test method in its @WebMvcTest class. The description links the Sentry issue, quotes the exception and the in-app frames, shows the new test failing before the fix and passing after, and reports that ./mvnw -B verify passed with the format and checkstyle validation included. Your own workflows run on the branch as they do on any pull request.
The session's transcript keeps the Sentry reads, each mvnw command with its full Surefire output, and the files the agent opened. The run.completed webhook carries the agent's final summary as data.result and a session_url, so a handler can post the pull request link to the issue or to the team.
Before merging, a reviewer checks that the stubbed repository state matches what the Sentry event showed, that a status change is declared at the controller level rather than hidden in a catch, and that the Thymeleaf view the handler returns still receives the model attributes it reads. A follow-up message to the same session asks for a different approach and the branch is updated in place.
Run it on every Sentry issue alert
Add an alert rule to the Sentry project with a webhook action and aim it at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the Sentry issue id as Idempotency-Key, so retries from Sentry map to the one run. One issue becomes one sandbox and one pull request.
Give the API key a webhook URL and Rush POSTs run.completed with session_url when the pull request is ready. Or have that handler call a webhook trigger on an automation in the Project with this prompt: it forwards the alert's JSON as the body with the trigger's secret as Authorization: Bearer, because Sentry signs its own webhooks and cannot send that header. The body becomes the event text after the prompt, and max_runs_per_hour caps an issue that keeps firing.
The use case this job follows, with its automation and trigger: Fix a bug from an alert.
Why run it on Rush?
A Spring Boot fix on a laptop is mostly waiting: the Maven build, the format plugin rejecting a tab, the full suite with Testcontainers. The agent does that in its own sandbox with JDK 17, runs the one test first and the whole verify last, and keeps every line of output, so the reviewer sees a green build instead of reading that there was one.
The pull request carries its proof, a test that failed and now passes, and the transcript shows each command behind the claim. Issues run in parallel in separate clones, up to the key's max_concurrent limit, so the exceptions a release left in Sentry become several small reviewed branches instead of one person's queue.
Frequently asked questions
Maven or Gradle?
Both builds exist and CI runs both; the agent uses ./mvnw, the wrapper the Maven workflow runs, and keeps the change buildable with ./gradlew build too. If your project has only one, it uses that.
Will the format plugin fail my build after the fix?
No. spring-javaformat:validate runs in the validate phase, so the agent runs ./mvnw spring-javaformat:apply before verify and the diff arrives formatted. Checkstyle with nohttp runs in the same build.
Does it start MySQL or Postgres for the tests?
Only when the fix touches a repository or entity. The @WebMvcTest classes mock the repository, and PetClinicIntegrationTests runs on H2 from application.properties; MySqlIntegrationTests uses Testcontainers and PostgresIntegrationTests uses Docker Compose, both of which the sandbox can run when the prompt allows it.
What if the exception is the one /oups throws on purpose?
CrashController exists to demonstrate the error page, and the prompt tells the agent to leave it alone. It opens no pull request for that issue and says so, and you can mute the issue in Sentry.