What the agent does
The incident is specific: Grafana shows the API's heap growing by about 200 MB an hour until the container is OOM-killed every 6 hours, starting after the last two releases. The agent starts the run with the Grafana connection named so it can query the heap panels itself, the repository cloned, and a full-history checkout, because a shallow clone would leave the last-30-commits read empty.
In a codebase like brocoders/nestjs-boilerplate it first maps what can hold memory. The app is NestJS 11 on Node, choosing between TypeORM with Postgres and Mongoose at boot from databaseConfig().isDocumentDatabase, so either path can be live depending on the deployment. The TypeORM config service sets keepConnectionAlive: true and a pool sized by DATABASE_MAX_CONNECTIONS with a default of 100, the Mongoose config registers the mongoose-autopopulate plugin in its connectionFactory, and sessions are database-backed rows rather than in-memory maps, which clears the usual session-store suspect. There are no websocket gateways, no Bull or BullMQ processors, no in-process caches and no setInterval listeners in src/, so the report does not waste a page on them.
The suspects it does rank come from what is actually there. The global ResolvePromisesInterceptor in main.ts merges and deep-resolves promises on every response; if a handler returns a stream or a query builder that never settles, mergeMap chains hold their buffers, so the agent reads each interceptor and pipe with that lens. File uploads go through multer with local disk storage or multer-s3, and an S3 client constructed per request in the uploader module factory would leak connections under upload traffic. The i18n loader runs with watch: true, which holds file watchers that grow with locale files. nodemailer transporters are created once per MailerService instance, fine unless the module is request-scoped somewhere new. Each suspect goes into incident.md with file and line, and the check that would confirm or clear it.
For the check column the agent writes what it would run, not what it assumes: a reproduction with a load tool against the sandbox build, node --heap-prof snapshots an hour apart, and a retainer comparison that names the growing object class; for the pool, pg_stat_activity counts against DATABASE_MAX_CONNECTIONS; for watchers, the process watcher count under load. The two releases that started it narrow the commit read: with git log --oneline -30 it lists what changed in each and marks which suspect a commit touches. 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": "Incident: Grafana shows the API's heap growing by about 200 MB an hour until the container is OOM killed every 6 hours, starting after the last two releases. Read the code, the configuration and the last 30 commits, find the most likely causes, and write incident.md with a timeline, each suspect with file and line evidence, and the check that would confirm or clear it. 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 incident.md, the run's artifact. It opens with a timeline: when the heap curve started climbing, the two releases in that window, and the Grafana query behind each point on the curve. Then the suspect list, each with file:line evidence from the repository, the commit that introduced or touched it where one exists, and the confirming check written as a runnable command.
The checks are the part an on-call engineer actually uses. Confirming the interceptor suspect means heap snapshots under load and a retainer diff; clearing the connection-pool suspect means watching pg_stat_activity while the heap grows; the watcher suspect shows up in the descriptor count. The trajectory of the run keeps every read, query and command with its output, so each line of the report traces back to something the agent actually saw.
Before paging anyone, the reviewer checks that the file:line citations resolve in the current code, that the timeline matches the Grafana panels, and that at least the top suspect's check has been run or is cheap to run. The report is a first pass with evidence, not a verdict; it exists so the human who owns the service starts from suspects ranked with checks, not from a blank Grafana screen.
Run it on every memory alert fires
Wire a Grafana alert on container memory with a webhook to your server, and when it fires have your server post this same request with the alert window and the current heap numbers in the prompt. One alert starts one run in one sandbox, so every OOM cycle gets its own incident.md while the heap curve and the recent commits are still fresh.
Set a webhook URL on the API key and Rush posts run.completed or run.failed when the run's turn finishes, carrying the session URL; your server can thread the report into the incident channel or attach it to the alert. Name the Grafana 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?
A memory leak punishes shallow investigation: the obvious suspects, session maps and missing cache eviction, are usually not it, and ruling them out properly means reading config files and module lifecycles across the whole tree. On Rush the agent does that read end to end in one sandbox, with the Grafana connection live to check the curve itself, and it writes the report with file:line evidence instead of a list of possibilities.
The other laptop problem is evidence that evaporates. The agent's trajectory keeps every query, file read and git log line with its output, and the report's check column turns each suspect into an action a human can run in minutes. Because a run is one request, every service on the dashboard that starts climbing gets its own investigation in parallel, each landing as a report with sources rather than a hunch.
Frequently asked questions
How does the agent read my Grafana panels?
You connect Grafana once from the console and name the connection on the run; a key run reads only the connections it names. The agent queries the heap and container-memory panels for the incident window and quotes the queries in the report so you can re-run them.
My deployment uses MongoDB, not Postgres. Does the investigation still work?
Yes. The boilerplate's dual-database design means the agent reads which branch is live from your config first, then follows the Mongoose path instead of the TypeORM one: the autopopulate plugin, connection factory and session collections. The suspect list matches your actual deployment, not the template's default.
Will it fix the leak?
No, this run changes no code by design; it delivers incident.md with ranked suspects and the check for each. Once a suspect is confirmed, start a follow-up run describing the fix and it works from the same repository and evidence.
Can it reproduce the OOM in the sandbox?
It can try: the sandbox builds the app, runs it, and drives load with a benchmark tool while taking heap profiles, which is how the check column gets real answers for the top suspects. If a suspect needs your production data volume to show itself, the report says so and names the production check instead of a sandbox substitute.
The shallow clone on my CI shows one commit. Does the last-30-commits read work?
Rush clones the full history for the run, so git log covers real recent history. If your repository genuinely has few commits, the agent reads what exists and leans on the Grafana timeline and code evidence instead, saying plainly where the commit history runs out.