What the agent does
The agent starts in PostHog. Through your PostHog connection it lists the project's error-tracking issues from the last 7 days, takes the one with the most occurrences, and reads its exception type and message, the sample stack frames, the URL of each event and when it was first seen. Events that all come from /dashboard and began after one deploy already narrow the search to one route group and one diff.
Then it maps the frames to a clone of your repository in its own sandbox. In nextjs/saas-starter (Next.js 15.6 canary, React 19.1, Drizzle on Postgres, Stripe 18, pnpm) the team settings page is the client component app/(dashboard)/dashboard/page.tsx: it fetches /api/team and /api/user with SWR, renders teamData.teamMembers with initials built by getUserDisplayName(user).split(' ').map((n) => n[0]), shows a remove button only for index > 1, and binds removeTeamMember and inviteTeamMember from app/(login)/actions.ts with useActionState. app/api/team/route.ts returns whatever getTeamForUser in lib/db/queries.ts finds, which is null for a visitor with no session. The billing side is lib/payments/actions.ts, whose checkoutAction and customerPortalAction are wrapped by withTeam from lib/auth/middleware.ts and throw Team not found when the user has no team; lib/payments/stripe.ts redirects to /pricing when the team has no stripeCustomerId, throws when the team's product is inactive or has no active prices, and in handleSubscriptionChange reads (plan?.product as Stripe.Product).name on the assumption that the product was expanded. app/api/stripe/checkout/route.ts turns every unexpected shape in the completed session into a thrown error and redirects to /error, and app/api/stripe/webhook/route.ts verifies the signature with STRIPE_WEBHOOK_SECRET before handling customer.subscription.updated and deleted.
Reading the code the frames point at, the agent looks for the assumption that real data broke: a member whose name and email are both empty, a team response of null reaching .teamMembers, a Stripe subscription whose product came back as an id string, a form that posted a role outside member and owner so validatedActionWithUser returned result.error.errors[0].message. The PostHog message, the URL and the first-seen time say which of these, or which other path, users actually hit, and the agent reads the commits that touched those lines in the same window.
The starter has no test runner: package.json lists only dev, build, start and the db:* scripts. So the agent adds Vitest and Testing Library as dev dependencies with pnpm, writes a test that renders the component or calls the action with the data the PostHog events show, with fetch, @/lib/db/queries or the stripe client mocked, and confirms it fails. It fixes the component, action or Stripe helper where the bad data enters, runs npx vitest run and pnpm build until both pass, and leaves lib/db/migrations and drizzle.config.ts alone. The pull request names the PostHog issue, its occurrence count and the frame that pointed at the bug.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Use the PostHog connection to list this project's error-tracking issues from the last 7 days and take the one with the most occurrences. Read its exception type, message, sample stack frames, event URLs and first-seen time. Map the frames to the source in app/(dashboard)/dashboard/page.tsx, app/(login)/actions.ts, app/api/team/route.ts, lib/payments/actions.ts, lib/payments/stripe.ts and the Stripe routes under app/api/stripe, and read the recent commits that touched those lines. The project has no test runner: add vitest and @testing-library/react as dev dependencies with pnpm, write a test that reproduces the exception with the data the PostHog events show (mock fetch, the queries module or the stripe client as needed), and confirm it fails. Fix the cause where the bad data enters, then run npx vitest run and pnpm build until both pass. Open a pull request that names the PostHog issue, its occurrence count and first-seen time, and quotes one sample stack trace with the line it maps to. If the cause is outside this repository, say so in the session result and open no pull request.",
"connections": [
"posthog"
],
"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 pull request named after the exception. In saas-starter it usually changes one file under app/(dashboard)/dashboard/, app/(login)/ or lib/payments/, adds a test beside it, and adds vitest, @testing-library/react and a test script to package.json with the updated pnpm-lock.yaml. The description carries the PostHog issue, its occurrence count, the first-seen time, one sample stack trace and the source line it maps to.
The session transcript keeps the PostHog queries, the pnpm install, every vitest and pnpm build run with its output, and each file the agent opened. The run.completed webhook delivers the agent's final message with the session_url.
Before merging, a reviewer checks that the fix handles the bad data where it enters, in the API route or the action rather than with an optional chain at the crash site, that a change in handleSubscriptionChange or the checkout route still records the plan name the dashboard shows, and that the new test fails on main. After the deploy the PostHog issue should stop receiving events.
Run it on every new top exception in PostHog
Run it from a daily scheduled job on your server: the job asks PostHog which issue has the most occurrences and sends this request only when that issue is new since its last run, with your PostHog connection named in connections. A fix that already shipped is not attempted twice, and a crash introduced by a release gets a pull request the next morning.
Set a webhook URL on the API key and Rush POSTs run.completed or run.failed with the session_url when the turn finishes. A key runs at most max_concurrent sessions at once, 4 by default, and answers 429 past that.
The use case this job follows, with its automation and trigger: Fix a bug from an alert.
Why run it on Rush?
Fixing a Next.js exception properly means reproducing it, and in a starter with no test runner that means choosing and wiring one before the first assertion, plus mocking Stripe and Postgres so the test does not need either. In a Rush sandbox the agent does that on its own machine, with its own node_modules, while your working copy and dev server stay untouched.
The result shows its work: the PostHog numbers it chose by, the trace and the source line, the test that fails before the fix, and every command with its output in the transcript. Several apps built from the same starter can each run in their own sandbox at the same time.
Frequently asked questions
Will the test hit Stripe or my database?
No. The test mocks the stripe client from lib/payments/stripe.ts and the functions in lib/db/queries.ts, so it needs neither STRIPE_SECRET_KEY nor POSTGRES_URL. The agent still needs pnpm build to pass, which compiles the routes without calling them.
The app has no tests at all. Is adding Vitest in scope?
Yes, and the pull request keeps it small: the two dev dependencies, a test script and one test file. If you would rather keep the starter dependency-free, say so in the prompt and the agent reproduces the exception with a script instead and quotes its output.
What if PostHog's frames are minified?
With source maps uploaded the frames name files and lines. Without them, the agent runs pnpm build, matches function names and the message to the source, and says in the pull request how confident the mapping is.
Does it need the PostHog connection on every run?
Yes. A key run gets only the connections it names, so the request on this page lists posthog; connect it once with POST /me/connections and name it, or its id, on each run.