What the agent does
The agent clones the repository into its own sandbox and gets the service running the way production runs it, because a leak found under ts-node or a dev server can be the dev server's. In an Express API like gothinkster/node-express-realworld-example-app, package.json has Express ~4.18.1, express-jwt 8, @prisma/client ^4.16.1 and an Nx 17 workspace: nx build compiles src/main.ts with esbuild into dist/api, and the Nx-generated Dockerfile runs node api from there. The Prisma schema at src/prisma/schema.prisma uses postgresql, with four migrations under src/prisma/migrations/ and a seed in src/prisma/seed.ts that generates data with @ngneat/falso. The agent starts Postgres in the sandbox, runs prisma migrate deploy and prisma db seed, builds, and starts node --heapsnapshot-signal=SIGUSR2 dist/api with NODE_ENV=production.
Before generating load it reads the code for things that hold memory across requests. In this service the candidates are few and specific: src/prisma/prisma-client.ts keeps one PrismaClient and stores it on global only when NODE_ENV is development; src/app/routes/auth/auth.ts builds the two express-jwt middlewares once at import time; and article.service.ts passes take: Number(query.limit) || 10 to findMany with no upper bound, so one request with a large limit loads that many articles with their included authors and tags. That last one is a spike, not a leak, and telling the two apart is half of the report.
Then it puts the service under steady load for ten minutes with a load generator such as autocannon, against a mix of the 19 routes the controllers register: GET /api/articles and /api/tags without a token, and GET /api/user, article creation, comments and favorites with a JWT from POST /api/users. It sends SIGUSR2 for a heap snapshot after a warm-up, again at the end, and once more after the load stops and a forced garbage collection, and it samples process.memoryUsage() every few seconds so the report can show heapUsed and rss over time rather than two points.
Last, it compares the snapshots: which constructors grew in count and retained size between the first and the last, and, for the ones that grew, the retainer path from a GC root to the object, which is what names the line of code. If memory comes back after the load stops, the report says the service does not leak under this traffic and names what drove the peak. If it does not come back, the report names the object, the retainer chain and the file and line that keep it reachable. The prompt says change no code, so the fix is written as a suggestion with the diff it would make.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Find out whether this Express service leaks memory and, if it does, what holds it. Build it the way production does, start its database in the sandbox, run migrations and seed data, and start the compiled server with heap snapshots on a signal. Before load, read the code for anything that keeps state across requests: module-level caches, maps and arrays, clients, event listeners, timers and unbounded queries. Put the service under steady load for ten minutes across its main routes, with and without auth. Take heap snapshots after warm-up, at the end, and after the load stops and garbage collection runs, and sample heapUsed and rss every few seconds. Compare the snapshots: which objects grew, their retainer paths, and the file and line that keeps them alive. Tell a leak apart from a spike that returns. Write memory-leak.md with the memory curve, the snapshot comparison, the cause or a clear statement that there is no leak under this load, and a suggested fix as a diff. Change no code.",
"resources": [
{
"url": "https://github.com/your-org/your-api"
}
]
}- 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 memory-leak.md, attached to the session as an artifact with a download link, and no change to the repository. Its sections are: how the service was built and started, with the exact commands and Node flags; the load, with routes, rates and duration; a table of heapUsed and rss over the ten minutes and after the load stopped; the snapshot comparison, listing the constructors whose count and retained size grew; for each one, the retainer path and the file and line it leads to; the verdict, leak or no leak under this load; and the suggested fix as a diff that nobody has applied.
The heap snapshots themselves are attached beside the report, so an engineer can open them in Chrome DevTools' Memory tab and check the retainer path instead of taking it on trust. The session's transcript keeps every command with its output: the Postgres start, the migrate and seed, the build, the load generator's summary and each signal that wrote a snapshot.
Before acting on it, a reviewer checks that the load resembles production traffic (a leak on a route nobody calls is not the one paging you), that memory was measured after a garbage collection and not only at peak, and that the suggested fix removes the retainer the report names rather than raising a limit.
Run it on every memory alert on the service
Point your alerting at your own endpoint and have it send one POST /o/{org}/sessions when the service's memory alert fires, with the repository in resources and the alert's details, such as the commit deployed and the routes with the most traffic, in input. An Idempotency-Key built from the alert's id keeps a re-fired alert from starting a second run.
A webhook on the API key posts run.completed with the session_url when the report is ready, so the on-call engineer gets a link to memory-leak.md and the snapshots before they open a profiler. In the console, an automation can start the same run on a schedule against the latest main, to catch growth before it reaches production.
The use case this job follows, with its automation and trigger: Investigate an incident.
Why run it on Rush?
A leak hunt needs the service running long enough to show a trend, with its database, under load, with the inspector on, and snapshots that can run to hundreds of megabytes. On a laptop that is ten minutes of a fan at full speed and a dev database full of load-test rows, and it is easy to measure the debugger instead of the service. A Rush sandbox gives the agent its own Postgres, its own build and its own load generator, with nothing else on the machine to skew rss.
The report comes with its evidence: the snapshots attached, the memory curve, and every command in the transcript, so the claim "this map in this file holds every request" can be checked in DevTools in a minute. Because the prompt says change no code, the run is safe to start from an alert at night; the fix waits for a person to read the diff.
Frequently asked questions
Will it change my code?
No. The prompt says change no code, so the result is memory-leak.md and the heap snapshots. The suggested fix is written as a diff inside the report. To turn it into a pull request, send a follow-up message to the same session asking for one.
What if there is no leak?
Then the report says so, with the evidence: memory returning to its starting level after the load stops and garbage collection runs, and no constructor growing between snapshots. It also names what drove the peak, such as an unbounded limit on a list query, which looks like a leak on a dashboard but is a spike.
Can it reproduce the traffic that triggers my leak?
Put what you know in input: the routes, the request shapes, the rate, or a sample of access logs attached as a file block. The agent drives load to match. Without it, the agent spreads load across the service's main routes with and without auth.
Does it work with TypeScript builds like Nx or esbuild?
Yes. It builds the service the way the repository's own build does, nx build to dist/api in this case, and profiles the compiled JavaScript with source maps where the build emits them, so the file and line in the report point back to the TypeScript source.