Docs

CrashPatch speaks the Sentry envelope protocol. The client you already ship works unchanged — you change one string.

1. Point your SDK at CrashPatch

Create a project in the dashboard and it gives you a DSN. It is the same shape your SDK already expects: the public key, this host, and a numeric project id.

import * as Sentry from '@sentry/node'

Sentry.init({
  dsn: 'https://<public-key>@crashpatch.2.28.42.222.sslip.io/<project-id>',
  environment: process.env.NODE_ENV,
  release: 'web@1.4.2',
})

The public key travels in client bundles and is meant to. It can only write crashes into the one project it belongs to; it cannot read anything.

2. Upload source maps from your build

Without these, a minified frame names a file nobody has and the issue is declined rather than patched. Maps are uploaded rather than fetched: a bundle’s own sourceMappingURL deciding what we request would be a request-forgery gadget, and the maps teams are willing to give us are frequently the ones they deliberately do not publish.

curl -X POST https://crashpatch.2.28.42.222.sslip.io/api/v1/releases \
  -H "Authorization: Bearer $CRASHPATCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "web",
    "version": "web@1.4.2",
    "commitSha": "'"$GITHUB_SHA"'",
    "sourceMaps": [
      { "fileName": "app.4f2c1a.js", "content": <contents of app.4f2c1a.js.map> }
    ]
  }'

Uploading the same version again replaces its maps rather than adding a second copy, so a rebuild never resolves a frame to a line the build no longer has.

3. What happens to an issue

Crashes are grouped as they arrive. Everything after that happens once per group, however many times the bug fires.

  1. 01The frames are resolved against the source maps for that release.
  2. 02The files behind the deepest in-app frames are read from your repository, at the default branch.
  3. 03The crash, the stack and that source go to the model, which either proposes a patch or declines with a reason.
  4. 04A patch becomes a branch, one commit, and a draft pull request.

4. The four things an issue can say

Patch ready

A draft pull request is open. Its body says what was not verified.

Declined

We looked and decided not to patch it. The reason is on the issue — a crash inside a dependency, a stack that does not resolve to your repository, a fix that needs a decision only your team can make.

Triage failed

Something on our side broke. Also on the issue, also in plain words. This is never billed.

Not triaged

Triage is off for the project, no repository is connected, or the account has no triage allowance left.

5. What we do to your repository

Access is through a GitHub App you install on the repositories you choose, with Contents and Pull requests permissions and nothing else. Installation tokens are minted per job and never stored — they live an hour, and keeping one is strictly worse than asking for another.

Within that, CrashPatch creates a branch named crashpatch/<issue>, makes one commit on it, and opens a draft pull request. It does not merge, does not force-push, does not write to your default branch, and does not close anything.

6. Your source goes to a model

That is the product, so it is worth stating without euphemism: to propose a patch, the files behind the crashing frames are sent to an LLM along with the stack trace. Triage is off by default for every project and is turned on per project, never per account, and never as a side effect of connecting a repository.

The model is fenced: it may only rewrite files it was shown, plus one regression test beside one of them. A stack trace is text an attacker can influence, and without that fence a crafted exception message could talk it into editing a workflow file.