All jobs

Turn Sentry Errors Into Fix Pull Requests for a SvelteKit App

Yes. From a Sentry alert the agent reads the stack trace, reproduces the failing load or action with a Vitest test in your SvelteKit app and opens a pull request.

Run this on RushIn a Project that has your repository.

What the agent does

A Sentry alert for a SvelteKit app names a server load function or a form action most of the time, and the agent starts there. Through the Sentry connection it reads the issue and its latest event: the exception, the request URL and method, the release, and the in-app frames with their file paths and line numbers. It compares the frames against the route tree in its clone of the repository, so a frame in src/routes/article/[slug]/+page.server.js is matched to the article page's load and its createComment, deleteComment, deleteArticle and toggleFavorite actions before any code is read.

In a SvelteKit app like sveltejs/realworld the agent reads package.json first: SvelteKit ^2.52.2 on Svelte ^5.55.7 with runes: true in svelte.config.js, Vite ^7.3.2, adapter-vercel, marked and sanitize-html, and packageManager set to pnpm 10.20.0 with .nvmrc at 20 and engine-strict in .npmrc. There is no test script and no test runner; the only check is prettier --check . as pnpm lint. Every request goes through src/lib/api.js, whose send fetches https://api.realworld.show/api, returns the parsed body on an ok or 422 response, returns {} on an empty body and otherwise calls SvelteKit's error(res.status). The article loader runs api.get for the article and its comments in a Promise.all, then marked(article.body) and sanitizeHtml. The profile routes under src/routes/profile/@[user]/ load profiles/{user} in +layout.server.js and the author's articles through get_articles.js, which builds limit and offset from page_size in src/lib/constants.js. src/hooks.server.js sets locals.user by JSON.parse(atob(jwt)) on the cookie, which is itself a place a malformed cookie throws.

Because the project has no runner, the agent adds vitest as a dev dependency and a test script, keeping @sveltejs/vite-plugin-svelte that is already installed for Vite. It writes a test that imports the loader or action from the route file and calls it with a hand-built event: params from the event's URL, locals with or without a user, and a mocked fetch or a mocked $lib/api.js that returns the body the Sentry event implies, such as {} from an empty response or an article with no body. It runs npx vitest run and keeps the failing output, which shows the same exception type and message as the Sentry event.

Then it fixes the cause in the loader or action, reruns the test until it passes and runs pnpm lint and pnpm build so the Vercel adapter still builds. If the frame was in +page.svelte rather than a loader, it reads the component with data from $props() and fixes what the template assumes about the data, such as data.article.author, with a test for the loader that feeds it. It does not wrap the loader in a blanket try that hides the status; +error.svelte already renders a 404 and a generic page, and the fix keeps that behaviour.

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 SvelteKit app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the request URL and the in-app stack frames. Match the frames to the route files under src/routes, starting with the article route in src/routes/article/[slug]/+page.server.js and the profile routes under src/routes/profile/@[user]/, and to the fetch wrapper in src/lib/api.js. The project has no test runner: add vitest as a dev dependency with a test script, write a test that calls the failing load function or form action with a mocked API response and reproduces the exception, then fix the cause until `npx vitest run` passes. Install with pnpm, and run `pnpm lint` and `pnpm build`. Open a pull request that links the Sentry issue, quotes the frames and the failing test output, and explains the cause. Change nothing unrelated to this error.\n\nAlert payload:\n{payload}",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ],
  "connections": [
    "sentry"
  ]
}
  1. 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.
  2. 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.
  3. 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

The result is a pull request with a small diff: the route file where the exception started, a new test file beside it, vitest under devDependencies with a test script in package.json, and the updated pnpm-lock.yaml. The description links the Sentry issue, names the loader or action and the line, shows the test failing before and passing after, and explains in plain words why the code threw, for example that an empty API response reaches marked as undefined.

The session holds the full record: the Sentry queries, the pnpm install, vitest, lint and build commands with their output, and the files the agent read. Its final message, the result on the session and data.result in the run.completed webhook, is the short account a reviewer reads first; the transcript is where they check it.

Before merging, the reviewer confirms the test calls the same code path Sentry reported, that a fix which now throws error(404) or error(502) chooses the status the API answer deserves rather than hiding it, and that nothing in src/lib/api.js changed for routes that were working. A different approach is a follow-up message to the same session, and the agent amends the same branch.

Run it on every new Sentry issue

Add an alert rule in Sentry for the SvelteKit project that fires when a new issue is created, with a webhook action aimed at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the issue id as the Idempotency-Key, so Sentry's retries map to one run. Every new issue gets its own sandbox, its own test and its own pull request.

Give the API key a webhook URL and Rush POSTs run.completed when the turn ends, with session_url to read the pull request from. 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 SvelteKit loader fails on an API answer that is hard to get a browser to produce again, so reproducing it on a laptop means stubbing fetch by hand and wiring a test runner into a project that never had one, all while something else is half-done on your branch. In a Rush sandbox the agent sets up Vitest on its own disk, mocks exactly the response the Sentry event shows and leaves your working tree alone.

What you get back can be checked instead of trusted: the test that failed, the test that passes and the transcript of every command the agent ran. Each Sentry issue runs on its own, in parallel up to the key's max_concurrent limit, so a release that opened several issues gets several reviewed fixes rather than one person triaging them in order.

Frequently asked questions

The project has no tests. Does the agent still write one?

Yes. It adds Vitest as a dev dependency and a test script, because the repository has only prettier --check as a check. The test targets the loader or action directly with a mocked API, so it runs in a few seconds without a browser. If you already use Playwright instead, say so in the prompt and it writes a spec there.

The Sentry frames point into the Vercel build. Can it still find the line?

Server-side frames from adapter-vercel name the built files, so the agent maps them back through the route structure and the function names in the event, and says in the pull request which frames it placed and which it inferred. Uploading source maps to Sentry with a release makes the next event point at src/routes directly.

Which package manager does it use?

pnpm, because package.json sets packageManager to pnpm 10.20.0 and .npmrc has engine-strict=true. The sandbox uses Node 20 from .nvmrc and commits the updated pnpm-lock.yaml with the new dev dependency.

Will it change src/lib/api.js?

Only when the frames point there, for example an empty 200 response reaching JSON.parse. A change there affects every route, so the pull request calls it out and the test covers the exact response that broke, and the reviewer decides whether a narrower fix in the route is better.