Playbook
Fixing bugs with AI is the easiest way to accidentally ship two bugs. You describe the symptom, the agent invents a plausible cause, changes something, and the crash moves down the road wearing a new hat. The fix "works" — the original error is gone — but a related feature is now quietly broken, and the diff is too big to trust. The way out isn't a cleverer prompt. It's an order of operations that makes guessing impossible: reproduce, root-cause, smallest fix, verify. Do all four, in order, and bug-fixing stops being a coin flip.
We fix bugs with agents every day, and the sessions that go sideways almost always skip step one. Here's the playbook we actually run.
Step 1 — Reproduce first, on demand
You cannot fix what you cannot trigger. Before you let the agent touch a line, nail down the exact recipe that makes the bug appear every single time: the precise command, the precise input, the precise steps. "It fails sometimes when I save" is a rumor. "Running npm run import fixtures/bad.csv throws on row 12" is a reproduction — and it's also the thing that will later prove you're done.
- Capture the exact command or user action that triggers it.
- Paste the full error and stack trace — all of it, not a summary.
- State what you expected instead.
- List what you already tried, so the agent doesn't retread dead ends.
If the bug is intermittent, your whole job for now is to make it reliable — shrink the input, pin the state, find the smallest case that fails consistently. An unreproducible bug isn't ready to fix; it's ready to reproduce, and that is the task.
Step 2 — Root cause, not symptom
This is where agents left alone go wrong, and where you steer. The symptom — undefined is not a function — tells you where the crash surfaced, not why. The root cause is upstream: a value set wrong, a condition never handled, an assumption that broke. Silence the symptom without addressing the cause and you've planted a landmine that detonates next week.
Direct the agent to trace, not patch. Have it read the code paths backward from the error: where does this value come from, what set it, what upstream call produced the bad state. Make it cite file:line. A real finding sounds like "the value is null because loadUser() returns null for deleted accounts and the caller never checks" — a specific mechanism at a specific place. If the agent proposes a fix before it can name the mechanism, stop it. A fix without a named cause is a guess in a nicer font.
Step 3 — The smallest correct fix
Once you know the true cause, the fix should be the least change that addresses it and nothing else. This is the moment agents love to "improve" the neighbors — rename variables, tidy adjacent code, refactor a function that was fine. Don't let them. Every extra line is a new place for a new bug to hide and a bigger diff to verify. Fence the agent: "fix only the root cause we identified, in these files, change nothing else." Cleanups are a separate task for a calmer moment.
Step 4 — Verify both halves
Verification has two mandatory parts. First, you re-run the exact reproduction from step 1 — same command, same input — and confirm the bug is genuinely gone. Not "the agent says so." You run it; that's why the reproduction had to be precise. Second, run the broader test suite plus a quick sanity check of related features, so the fix didn't trade one bug for two. Make the agent paste real output: the reproduction now passing, the suite still green. "Should be fixed now" is not evidence; a command that used to fail and now succeeds is.
The copy-paste debug prompt
Hand this to an agent to run the whole loop. The order is baked in so it can't jump to guessing.
We have a bug. Follow this order strictly. Do not skip steps.
REPRODUCTION
- Trigger: <exact command or steps that make it fail>
- Error / wrong behavior: <full error + stack trace, pasted>
- Expected instead: <what should happen>
- Already tried: <dead ends to avoid>
STEP 1 - Confirm the reproduction.
Run the trigger yourself and paste the failing output. Do NOT
propose a fix yet.
STEP 2 - Find the ROOT cause.
Read the code paths backward from the error. Explain the exact
mechanism and cite the file:line where the cause lives. Do not
fix the symptom. Wait for me to confirm the cause.
STEP 3 - Smallest correct fix.
Change only what's needed for that root cause, only in the files
involved. No refactors, no cleanups, no extra changes.
STEP 4 - Verify.
Re-run the reproduction and paste the now-passing output. Then
run the full test suite and paste that output too. If anything
else broke, stop and report it.
It feels heavy for a one-line typo and it's exactly right for anything that isn't.
A pre-fix checklist
- Do I have a reproduction that fails every time?
- Can the agent name the mechanism, at a specific
file:line? - Is the proposed fix the smallest one that addresses that cause?
- Did I personally re-run the reproduction after the fix?
- Is the full test suite still green?
Pick the right model for the bug
Most bugs are a daily-driver job — Opus 4.8 or a strong value model like Sonnet 5 traces and fixes them cleanly. For the gnarly, load-bearing bug in a large codebase where a wrong fix is expensive, reach for the hardest model you have (Fable 5 tops our benchmarks at 95.0 SWE). For fast, cheap iteration on a shallow bug, Gemini Flash's speed keeps the loop tight. Match the model to the stakes.
Once the fix lands, get fresh eyes on the diff — ideally an agent that didn't write it — via the AI code review workflow, which catches the mistakes a just-convinced debugger can't see. For the fuller debugging discipline, see the AI debugging workflow. And when a bug traces back to a missing test, writing tests with AI that actually catch bugs stops it recurring. Running the fix in one agent while a second re-verifies is what The Vibe Father's AutoVibe gate does automatically, but every step here works with a single terminal and the discipline to follow the order.