~/docs/getting-started
Getting started
bugzero is an AI bug-fixing agent and the control room to run it. When something breaks — reported by Sentry, PostHog or your own app through a webhook — the agent runs in your own GitHub Actions and opens a pull request with a fix; you steer it from one dashboard. Your code never leaves your infrastructure. Here's everything you need to set up, and why each step matters.
How an error becomes a pull request.
7 steps to your first fix.
Create your account
requiredSign up with your email and a password. You'll get a team workspace on the Free plan — 5 fixes a month, no card required.
Connect GitHub
requiredOn the Integrations page, install the bugzero GitHub App, choose the account or organization, and select the repositories bugzero may start fixes in.
Connect an error source
requiredOn Integrations → Error sources, connect the error tracker you already use and pick the projects bugzero should watch, or send errors from your own app. You can use more than one source.
- Sentry — connect your organization via OAuth.
- PostHog — pick your region and paste a personal API key with the
project:read,hog_function:writeandquery:readscopes. - Custom webhook — create an endpoint for each app and send errors to its secret URL from any language or tool; see Custom webhook below.
Map each project to a repository
requiredFor every project you watch, choose the GitHub repository the agent should fix. You set this right next to each project on the Integrations page. A custom webhook endpoint gets its repository when you create it.
Add the bugzero workflow
requiredIn Integrations → Runner setup, click Add workflow next to each repository. GitHub opens with .github/workflows/bugzero.yml prefilled — review it and commit it to your default branch. Then click Check again.
Add your AI key as an Actions secret
requiredIn each connected repository, open Settings → Secrets and variables → Actions and add a new secret named ANTHROPIC_API_KEY (or OPENAI_API_KEY) holding your own AI key.
Let Actions open pull requests
requiredIn each connected repository, open Settings → Actions → General, scroll to Workflow permissions, tick Allow GitHub Actions to create and approve pull requests and save. If the option is greyed out, an organization owner has to allow it under the organization's own Settings → Actions → General first.
pull-requests: write permission can't override it. Without it the agent still pushes its fix to a branch, but GitHub refuses to open the pull request — so you'd get a branch instead of a PR.Optional, but recommended.
Limit to the right environments
optionalOn each project mapping, tick the environments to react to — for example production only. Leave them all unticked to watch every environment. Custom webhook endpoints have the same optional filter.
Configure the agent
optionalOn the Agent page, pick the model and effort (the latest Claude or GPT models), write instructions with your team's conventions, and set a daily safety cap. Every time you publish instructions they become a new version — compare versions, see how each one performs, and roll back in one click.
Go Pro when you're ready
optionalFree includes 5 fixes a month. When you need more, upgrade to Pro — $9/month for unlimited fixes — from Billing, and manage or cancel through the customer portal.
Get your first fix
optionalWhen a new error hits a watched project and environment, bugzero starts a run that ends in a pull request. Track progress on the Runs page, then open the PR, read the diff and root-cause summary, and merge if it's right.
Send errors from anything.
Errors your tracker doesn't catch — a worker, a cron job, a script — or no error tracker at all? Send them to bugzero yourself: one HTTP request from any language or tool, no SDK.
On Integrations → Error sources, add a Custom webhook endpoint for each app: a name, the repository the agent fixes, its base branch and, optionally, the environments to react to. Each endpoint gets its own secret URL.
create an endpoint →Authenticate
The token at the end of the endpoint's URL identifies it. Call the URL as it is, or send the token in the Authorization header to the stable URL instead — better if your tooling logs URLs.
# token in the URL POST https://bugzero.dev/api/webhooks/custom/bzc_… # or: token in a header POST https://bugzero.dev/api/webhooks/custom Authorization: Bearer bzc_…
Payload
Send a JSON object with Content-Type: application/json, up to 256 KB. Only message is required.
- messagestring · required
- The error message.
- typestring
- The error class, e.g.
TypeError. Default:Error. - titlestring
- Replaces the default title,
type: message. - stacktracestring | array
- A string, or an array of lines or frames
{ file, line, column, function }, most recent call first. - environmentstring
- Matched against the endpoint's environment filter. Events without one always pass.
- fingerprintstring
- Groups events of the same error (see “One fix per error” below). Default: derived from the type, the message and the top stack frame.
- urlstring
- A link to the error in your system (http or https), shown on the run and in the pull request.
- contextobject
- Any extra details for the agent (request, user, tags…), sent as JSON and clipped to 4,000 characters.
- testboolean
- A dry run: reports what would happen and starts nothing.
Unknown fields are ignored, null counts as absent and long text is clipped.
Examples
With curl, from a terminal or a script:
curl -X POST "$BUGZERO_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"message": "order.customer is undefined",
"type": "TypeError",
"environment": "production",
"stacktrace": [
{ "file": "src/orders/receipt.ts", "line": 42, "function": "sendReceipt" },
{ "file": "src/orders/checkout.ts", "line": 88, "function": "completeOrder" }
],
"url": "https://logs.example.com/errors/8812",
"context": { "orderId": "ord_8812", "plan": "pro" }
}'From Node.js, for example in a catch block:
export async function reportError(error, context = {}) {
await fetch(process.env.BUGZERO_WEBHOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type: error.name,
message: error.message || String(error),
stacktrace: error.stack,
environment: process.env.NODE_ENV,
context,
}),
signal: AbortSignal.timeout(5000),
}).catch(() => {});
}
try {
await completeOrder(order);
} catch (error) {
await reportError(error, { orderId: order.id });
throw error;
}One fix per error
The agent starts once per error: after the first event, events with the same fingerprint on the same endpoint are skipped, even if that run failed. If it did, fix the setup (say, a missing workflow or AI key) and click Retry on the run page.
By default, numbers and ids in the message are ignored, so “User 123 not found” and “User 456 not found” are the same error. Want a fresh fix when an error comes back in a later release? Send a fingerprint that includes the release, e.g. "send-receipt@2.4.1". It replaces the default one, so keep the rest stable — no ids or timestamps.
Test it
Add "test": true to check the URL and your payload without starting anything. The response tells you whether a real event would start the agent and, if not, why:
curl -X POST "$BUGZERO_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"message": "order.customer is undefined", "test": true}'{
"ok": true,
"outcome": "test",
"wouldStart": true,
"fingerprint": "5d0c41a7e2b9f8c3a1d6e4b2c9f07a18",
"title": "Error: order.customer is undefined"
}Responses
Every response is JSON. Retry only on a 5xx: the same error never starts the agent twice, so retrying is safe.
- 202 outcome: "started"
- The agent started. The body includes the run's
runIdandstatus. - 200 outcome: "skipped"
- Nothing started;
reasonsays why (see below). - 200 outcome: "test"
- A dry run; nothing started (see “Test it”).
- 400 error: "invalid_json"
- The body isn't valid JSON.
- 400 error: "invalid_payload"
- A field is missing or has the wrong type;
issueslists each problem with its path. - 401 error: "unauthorized"
- Unknown token: check the URL — or the endpoint got a new URL or was deleted.
- 413 error: "payload_too_large"
- The body is over 256 KB.
- 5xx
- Something failed on our side. Safe to retry.
- reason: "duplicate"
- This error was already handled;
runIdis its run. - reason: "environment"
- The event's environment isn't in the endpoint's filter.
- reason: "repo_not_connected"
- The endpoint's repository isn't selected in the GitHub card.
- reason: "limit"
- The monthly Free limit or the daily safety cap was reached;
codeisfree_limitordaily_cap.
Keep the token secret
- Send events from your server only, never from a browser — anyone could read the token there.
- If your proxies or logs record URLs, send the token in the
Authorizationheader instead. - If the URL leaks, generate a new one for the endpoint; the old one stops working immediately.
- Everything you send is stored with the run and shown to the AI agent, so leave out passwords, keys and personal data.
Set everything up but no pull requests?
Almost always one of these:
- No project → repo mapping yet (step 04) — the single most common cause.
- The bugzero workflow isn't on the default branch, or the ANTHROPIC_API_KEY / OPENAI_API_KEY secret is missing (steps 05 and 06). Failed runs show the reason on the run page.
- The fix was pushed to a branch but no pull request opened — GitHub doesn't let Actions create them (step 07).
- The error's environment isn't in your watched list (step 08).
- No new error has occurred yet — bugzero reacts to new issues, not historical ones.
- You've used Free's 5 fixes this month, or the daily safety cap was reached — check the Dashboard.
- The repository isn't selected in the GitHub card (step 02).
- Sending errors to a custom webhook? Its JSON response says why an event was skipped; add
"test": trueto check without starting anything.
Ready to set up?
Create your account and connect your first repository — Free includes 5 fixes a month.