Fixer
@autowright/fixer is the intelligence layer: a long-running worker that
polls the service for pending failures and processes each one into either a
pull request or a needs-attention notification.
The worker loop
The worker polls GET /api/errors?status=pending every POLL_INTERVAL_MS
(default 5 seconds) and runs jobs up to MAX_CONCURRENT_FIXES (default 2) in
parallel. Each job is fully isolated — its own temp directory, its own repo
clone, its own agent session.
Anatomy of a fix job
- Download the evidence bundle from artifact storage into the job’s working directory.
- Clone the target repo —
git clone --depth 1 --filter=blob:none, so even large repos clone in seconds; file contents are fetched only when the agent actually reads them. - Run the agent over the evidence and the source.
- Deliver — on a confident fix: commit, push, open a GitHub PR, notify Slack. Otherwise: notify Slack with the diagnosis and evidence link.
- Report back — the job PATCHes its status and
FixResult(including cost) to the service.
The agent
The agent runs on the Claude Agent SDK with a deliberately narrow toolbox:
| Setting | Value |
|---|---|
| Model | claude-sonnet-4-6 |
| Allowed tools | Read, Edit, Glob, Grep |
| Disallowed | Bash, web access — the agent edits code; it cannot execute anything |
| Max turns | 50 |
Its prompt carries the error classification, the failed step, the action log,
and pointers to the captured DOM — plus classification-specific fix guidance
(a SELECTOR_NOT_FOUND sends it hunting through dom.html for the element
that replaced the broken selector).
The sandbox
Every tool call passes through a canUseTool gate that resolves the requested
path and confines it to the job’s working directory (repo/ plus
artifacts/). Anything outside — or anything unrecognized — is denied
conservatively. The agent cannot read your filesystem, other jobs, or the
fixer’s own environment.
The confidence gate
The agent must end its final message with an explicit verdict:
FIX_OUTCOME: FIXED— a confident, evidence-backed fix → becomes a PR.FIX_OUTCOME: CANNOT_FIX— anything else → becomes triage. No speculative PRs, ever.
Delivery
- Pull requests are opened through the GitHub REST API using
GITHUB_TOKEN. The PR body carries the agent’s summary, the classification, and a link to the evidence bundle. - Slack notifications are Block Kit messages to
SLACK_WEBHOOK_URL(“Fix proposed” or “Needs attention”), skipped silently when no webhook is configured.
Cost accounting
The fixer extracts the agent’s real usage — total_cost_usd, turn count,
duration, and input/output/cache token counts — onto the FixResult, on both
success and failure. It surfaces in the Slack message and the
dashboard’s fix detail page, so every fix has a price
tag.
Configuration
| Variable | Default | Purpose |
|---|---|---|
ANTHROPIC_API_KEY | — | Required — powers the agent |
GITHUB_TOKEN | — | Required for cloning private repos and opening PRs |
SLACK_WEBHOOK_URL | — | Optional notifications |
POLL_INTERVAL_MS | 5000 | Queue poll cadence |
MAX_CONCURRENT_FIXES | 2 | Parallel job limit |
The fixer makes outbound calls only (service, storage, GitHub, Anthropic, Slack) — it needs no inbound ports. See Self-Hosting.