What the agent does
The agent starts in Datadog. Through the Datadog connection named on the run, it compares APM traces for the service before and after the rise, groups span duration by resource name, and isolates the one whose p95 grew. It reads that span's flame graph to see whether the extra time is in the controller, the repository query, or an external call, and it copies the queries it ran into the report.
Mapping a span to code in a repository like spring-projects/spring-petclinic is direct because the repository is conventional. It runs on Spring Boot 4.1.0 with Java 17, and the request path is VetController and OwnerController in the vet and owner packages calling JPA repositories; a grown resource named after a repository method points at one of a small number of files. The agent opens the named file and reads the annotations before theorising.
PetClinic carries several latency suspects an experienced investigator checks in order. VetRepository.findAll and its paginated overload are annotated @Cacheable("vets") and @Transactional(readOnly = true) over a JCache manager backed by Caffeine, so the agent compares cache hit ratio across the window: a cache that silently stopped being hit shows up as this span growing while traffic stays flat. OwnerController's @ModelAttribute findOwner runs a findById before every owner route, an extra query per request. The mappings are eager in both directions that hurt: Owner.pets, Pet.visits and Vet.specialties all use FetchType.EAGER, and with spring.jpa.open-in-view set to false and default_batch_fetch_size 16, a page that touches collections can fan out into repeated batch queries the flame graph will show as one wide block.
The agent also rules out the cheap explanations: the HikariCP pool has no explicit sizing in application.properties, so it reports the defaults it actually ran under; with database=h2 and ddl-auto none, schema comes from db/h2/schema.sql, so a schema change between the windows would be visible in the commit diff. It writes the report with the queries, the before and after numbers, the suspect code at file and line, and the check that confirms each one. The prompt says to change no code, and it doesn't.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "p95 latency for the service below rose this week. Through the Datadog connection, compare traces before and after the rise, find the span that grew, map it to the code in this repository, and write a report with the queries, the numbers and the likely cause. Change no code.",
"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 report, the run's artifact. It opens with the Datadog queries and their time windows, then the per-span comparison that isolates the grown span. The middle of the report maps that span to the code: the controller or repository method it names, the annotations on it such as @Cacheable or @Transactional(readOnly = true), the fetch mappings behind it, and the pool and cache configuration the service actually runs with.
Each suspect carries the check that would confirm or clear it, written so the on-call engineer can run it without the agent: re-run the quoted APM query with a cache-hits overlay, count the queries per owner request, or compare pool wait time against query time. The run's trajectory keeps every query and its raw answer, plus the repository reads behind each mapping.
Before acting, the reviewer checks that the cited files and lines match the checked-out code, that the quoted queries reproduce the numbers, and that the timeline lines up: a cache invalidation, a config change or a traffic shift should be visible in the evidence. The report is blameless by construction; it names the change that made the span grow, not the person who merged it.
Run it on every latency alert fires
Point a Datadog monitor at the service's p95 with a webhook to your server, and when it fires have your server post this same request with the alert window in the prompt. Every alert starts one run in its own sandbox, so a regression gets its investigation while the traces are still fresh and the deploy that caused it is still recent history.
Set a webhook URL on the API key and Rush posts run.completed or run.failed when each run's turn finishes, carrying the session URL; your server can attach the report to the alert. Name the Datadog connection on every run, since a key run reads only the connections it names.
The use case this job follows, with its automation and trigger: Investigate an incident.
Why run it on Rush?
This investigation is exactly the kind of work that dies in browser tabs on a laptop: an APM query here, a flame graph there, a checkout of the service somewhere else, and the thread lost between each. On Rush the agent holds all of it in one sandbox: the repository cloned, the Datadog connection live, and every query it runs recorded with its output in the trajectory.
The report is built to be checked, which is what an on-call handoff needs. The numbers come from quoted queries, the code claims come with file and line, and the trajectory holds the raw answers behind both, so the engineer who picks it up verifies rather than re-runs. And because one request starts one run, every service whose p95 moved this week gets its own report in parallel, each waiting for a human decision, not a human tab.
Frequently asked questions
How does the agent reach my Datadog traces?
You connect Datadog once from the console and name the connection on the run; a key run reads only the connections it names. The agent searches APM traces and metrics and reads the flame graph through it, and the report quotes every query so you can re-run them yourself.
Will it change any code?
No. The prompt says to change no code, and the report is the whole result. A follow-up run with the same repository and a described fix works from the report's evidence.
What are the usual suspects in a Spring Boot latency regression?
The report-style checks that matter: a @Cacheable method whose cache stopped being hit, an extra query per request from @ModelAttribute or open session patterns, eager fetch mappings fanning out into batch queries, and a connection pool left at defaults under new traffic. The agent checks the ones your flame graph actually shows rather than working down a generic list.
Does it work with Maven and Gradle?
The investigation reads code and traces; it does not need to build the service. PetClinic ships both pom.xml with the Maven wrapper and a Gradle build, and the agent reads whichever your repository has to pin versions such as the Spring Boot and Java releases.
What if the regression started before my Datadog retention window?
The comparison needs traces from both before and after the rise. If the rise is older than retention covers, say so in the prompt and the agent compares what exists, then leans harder on the commit history between the windows; it says plainly which claims the trace data can no longer support.