# Fix agent

> **For agents:** this is a UI surface, not a tool — it streams a model's reasoning to a person watching. If you are an agent working on an issue yourself, call `get_fix_context` and reason directly, then `resolve_issues_from_commit` once your fix is pushed.

Open an issue in the list, expand it, and press **Fix with agent**. A panel opens beside the list and works the problem: it reads the issue, thinks, and either patches it or tells you what it thinks is wrong.

## Two modes, and the difference is the point

| | Repository connected | Not connected |
|---|---|---|
| Reads your source | Yes — the files the stack frames name, plus code search | No |
| Output | A patch and a pull request | A diagnosis and what to check |

Without a repository the agent has the stack trace, the surrounding source lines captured with the event, the breadcrumbs, the release and the impact. That is enough to reason about a cause; it is **not** enough to write a patch. So it doesn't write one. A patch against code the model cannot see is a guess wearing the costume of an inspection, and it costs more to review than it saves.

The panel says which mode it is in before it says anything else.

## Connecting a repository

**Settings → Agents → Fix agent repository.** You need:

- the repository as `owner/repo`;
- a fine-grained access token with **Contents: read and write** and **Pull requests: write**.

Access is verified before anything is stored — a token that cannot reach the repository fails at the point you paste it, not the first time somebody needs a fix. The token is encrypted at rest with the same key the notification channel configs use, and no API route ever returns it.

Connecting and disconnecting are **human-only**, like minting an API token. A credential that could grant itself commit access to your source would outlive its own revocation.

## What it does with the repository

The agent has two read tools — open a file, search the code — and one way to finish: propose a patch as the full new contents of each file it changes. It is told to read every file it intends to modify first, to change as little as possible, and to stop and explain rather than guess when it cannot see enough. Stopping short of a patch is a valid outcome and the panel presents it as one.

When it does produce a patch, Bugwatch creates a branch, commits **all** the files in one commit, and opens a pull request. One commit rather than one per file: a branch that half-applied would be worse than no branch.

## Resolving from the commit

The pull request's commit message ends with a trailer:

```
Fixes #412
```

`POST /v1/orgs/{org}/projects/{project}/resolve-by-commit` — tool `resolve_issues_from_commit` — reads a commit message, resolves the issues its trailers close, and records the commit on each issue's activity feed. Wire it into CI on your default branch and merging the fix is what closes the issue.

It reads the GitHub conventions you already use: `fix`, `fixes`, `fixed`, `close`, `closes`, `closed`, `resolve`, `resolves`, `resolved`, followed by `#42` or `COMPAT-42`.

**A bare mention never resolves anything.** `see #42` and `refactor around #42` leave the issue open. The cost of a false positive here is an issue silently marked fixed while it is still firing, so the verb is required.

## Models and credits

The agent runs on a curated catalogue of models, reached through Cloudflare AI Gateway with keys **Bugwatch** holds. There is deliberately no bring-your-own-key: a leaked provider key is our incident, not yours.

| Model | Plan | Best for |
|---|---|---|
| Claude Fable 5.1 | paid plans | Long, multi-file fixes — the default on paid plans |
| Claude Opus 5 | paid plans | Half the cost of Fable for most fixes |
| Claude Sonnet 5 | every plan | Fast, cheap first diagnosis — the default on Free |
| GPT-5 | paid plans | A second opinion from a different family |
| Gemini 2.5 Pro | paid plans | Large context; unfamiliar codebases |

Claude models reason before answering and the panel streams a summary of that reasoning. Requests carry a server-side refusal fallback, so a declined request re-runs on another model instead of dying silently.

### How credits work

Every run is metered from the provider's own token counts at the catalogue's price. Two pots, spent in order:

1. **The plan's monthly allowance** — Free includes $1, Starter $5, Team $15, Business $50, Scale $100. It resets on your billing anchor and does not roll over.
2. **Purchased credit packs** — $10, $25 or $50 from Settings → Billing. They never expire and are drawn down only once the month's allowance is gone.

A run's cost is only known when it ends, so the gate to *start* one is a floor (5¢ available), not zero. If a run overshoots what was left, the overshoot is recorded on the usage row rather than quietly forgiven — a debt nobody can see is a debt nobody can act on.

`get_agent_usage` returns the balance, the models your plan may use with their prices, and recent runs. Buying credits is human-only, like every other purchase.

### Deployment

`ANTHROPIC_API_KEY`, `OPENAI_API_KEY` and `GOOGLE_AI_API_KEY` are secrets on the API Worker and never reach the browser. `AI_GATEWAY_BASE` (up to and including the gateway id) routes every call through Cloudflare AI Gateway; `AI_GATEWAY_TOKEN` is sent as `cf-aig-authorization` when the gateway requires it. A model whose key is missing shows as *not configured* rather than failing on the first click.
