All jobs

Turn Sentry Errors Into Fix Pull Requests for an Angular App

Yes. A Sentry alert starts a run that follows the frames into your Angular services, reproduces the error in a Vitest spec and opens a pull request with the fix.

Run this on RushIn a Project that has your repository.

What the agent does

An Angular Sentry event names the service method or component that threw, the route the user was on, the release and the breadcrumbs of HttpClient calls that came before it. The agent reads the alert payload after the prompt, fetches the issue and its latest event through the Sentry connection, and keeps the in-app frames, the breadcrumbs and the tags. Only then does it open its clone and read the files the frames point at.

In an Angular app like realworld-apps/angular-realworld-example-app (Angular 21.2.12, standalone components and signals), every request passes three functional interceptors in src/app/core/interceptors: apiInterceptor prefixes https://api.realworld.show/api, tokenInterceptor adds Authorization: Token <jwt> from JwtService, and errorInterceptor purges the session on any 401 except on /user and rethrows { ...body, status }, substituting a single network message when the body carries no errors. ArticlesService in src/app/features/article/services/articles.service.ts maps data.article out of every response and CommentsService maps data.comments. UserService in src/app/core/auth/services/user.service.ts keeps an authState of loading, authenticated, unauthenticated or unavailable: a 4xx on GET /user logs the user out, while a 5xx or status 0 keeps the token and retries after 2, 4, 8 and then 16 seconds. ArticleComponent in src/app/features/article/pages/article/article.component.ts loads the article, its comments and the current user with combineLatest in ngOnInit, computes canModify from article.author.username, and a catchError writes err.errors into an errors signal. A frame in any of these tells the agent which response shape or which status the code did not expect.

The unit runner is Vitest, not Karma: package.json has test as vitest, and vitest.config.ts loads @analogjs/vite-plugin-angular, runs in jsdom, matches src/**/*.spec.ts and initializes TestBed once in src/test-setup.ts with destroyAfterEach. The existing specs beside each service (articles.service.spec.ts, comments.service.spec.ts, user.service.spec.ts, jwt.service.spec.ts, tags.service.spec.ts, profile.service.spec.ts) use HttpClientTestingModule and HttpTestingController to flush a canned response. The agent adds a case in the same style that flushes exactly what the breadcrumbs show, such as a 404 with an empty body, an article whose author is missing or a 204 with no body on unfavorite, and runs bunx vitest run src/app/features/article/services/articles.service.spec.ts so the failure is recorded before any fix.

With the failure reproduced it fixes the service, the component or, when the frames point there, the interceptor, reruns the spec until it passes, then runs bun run format:check, which is what the lint.yml workflow runs, and bun run build. The Playwright suite in playwright.yml needs the realworld submodule from bun run setup and bunx playwright install --with-deps chromium; the agent runs bun run test:e2e when that install succeeds and says so either way. It installs with Bun because bun.lock is the committed lockfile, on a Node that satisfies the >=20.11.1 engines field. It does not widen catchError in ngOnInit to swallow the error: where the page should show a message instead of an empty article, it sets the errors signal and explains why.

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 Angular app; its payload follows this prompt. Use the Sentry connection to read the issue, its latest event, the breadcrumbs and the in-app stack frames. Match the frames to the services under src/app/features/article/services and src/app/core/auth/services, the interceptors under src/app/core/interceptors, and the article page component in src/app/features/article/pages/article. The project tests with Vitest through @analogjs/vite-plugin-angular: add a spec case beside the existing *.spec.ts that flushes the response the breadcrumbs show through HttpTestingController and reproduces the error, then fix the cause until `bunx vitest run` passes. Install with bun, run `bun run format:check` and `bun run build`, and the Playwright suite if its browsers install. Open a pull request that links the Sentry issue, quotes the frames and the failing spec 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 that changes one service, component or interceptor and adds a spec case next to it. The description links the Sentry issue, quotes the exception and the frames it followed, names the breadcrumb whose response it replayed through HttpTestingController, shows the spec failing before and passing after, and lists the format check and build with their results.

The session's transcript keeps the Sentry reads, each bun and vitest command with its full output and every file the agent opened, so a reviewer can see whether the Playwright run happened or why it was skipped. The run.completed webhook carries the agent's final message as data.result and a session_url for everything else.

Before merging, a reviewer checks that the flushed response is the one the breadcrumbs show, that a change in errorInterceptor or UserService does not stop a real 401 from logging the user out, and that canModify still compares usernames the same way. A follow-up message to the same session changes the approach on the same branch.

Run it on every Sentry issue alert

Add an alert rule to the Sentry project with a webhook action and point it at a handler on your server. The handler sends this request with the alert's JSON after the prompt and the Sentry issue id as Idempotency-Key, so a redelivery returns the run that already started. One issue becomes one sandbox and one pull request.

Give the API key a webhook URL and Rush POSTs run.completed with session_url when the turn finishes, so the handler can comment the pull request link on the Sentry issue. The same handler can instead call a webhook trigger on an automation in the Project with this prompt, forwarding the alert's JSON as the body with the trigger's secret as Authorization: Bearer; Sentry signs its own webhooks and cannot send that header itself. 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?

An Angular error that depends on one API response is slow to chase by hand: you reconstruct the response from breadcrumbs, remember which interceptor rewrote the error before the component saw it, and run a jsdom suite that competes with your dev server. In a Rush sandbox the agent does that on its own disk with Bun and Vitest, keeps every command's output, and leaves your checkout untouched.

The pull request carries its proof, the spec that failed and now passes, and the transcript shows the format check, the build and the Playwright attempt behind it. Each issue runs separately, in parallel up to the key's max_concurrent limit, so the errors a release leaves across the article, profile and settings pages become small parallel reviews.

Frequently asked questions

Does it use Karma and Jasmine?

Not here: this repository moved its unit tests to Vitest through @analogjs/vite-plugin-angular, and the new spec uses Vitest's describe and it like the existing ones. In a project whose test script still runs ng test, the agent runs that script instead and writes the spec in the style the project already has.

Will it change the interceptors for every caller?

Only when the frames point there, for example a 204 reaching the error normalizer with no body. Because every request passes through src/app/core/interceptors, the pull request flags such a change and the spec covers the exact response that broke, so a reviewer can ask for a narrower fix in a follow-up.

What if the error is really the API's fault?

The breadcrumbs show the request and its status. If the backend returned a 500, the agent says so, proposes a change only where the front end should have handled that answer, and otherwise opens no pull request so the API team can take the issue.

Does it run the RealWorld end-to-end specs?

When Chromium installs in the sandbox, yes: bun run test:e2e runs the shared specs from the realworld submodule against ng serve on port 4200 as playwright.config.ts sets up. The pull request says whether the suite ran.