CLI Agent Workflows for Bug Fixing
Most bug-fixing advice is wrong about step one. Effective cli agent bug fixing reproduces the bug with a failing test first, then fixes against it — replacing the agent's guessing with checking.
claude > Don't fix anything yet. Write a failing test that reproduces this bug: > "refund() returns success but doesn't decrement the account balance." > Run it, confirm it fails, then stop.
Most bug-fixing advice for AI agents is wrong about the first step. It tells you to describe the bug and ask the agent to fix it. That's the move that produces confident, plausible, wrong patches — the agent changes something that could be related, the symptom seems to go away, and the real bug is still there waiting. Effective cli agent bug fixing inverts the order. You don't ask the agent to fix the bug first. You ask it to reproduce the bug first, with a failing test, and only then to fix it.
That one reordering changes everything about how reliable an agent is at debugging. Here's why, and how to run it.
What Is Reproduce-First Bug Fixing?
Reproduce-first means the agent's first job isn't the fix — it's a failing test that captures the bug. Before touching a line of implementation, the agent writes a test that fails because the bug exists. Now the bug is pinned down as an executable fact, not a vague description, and the fix has an objective definition of done: the test goes green.
claude
> Don,[object Object],t decrement the account balance.,[object Object]What this does: Directs the agent to produce a reproduction test and confirm it fails before proposing any fix. You now have proof the agent understands the bug, not just a claim that it does. If it can't write a failing test, it doesn't understand the bug — and you've learned that cheaply.
This matters because the failure mode of AI debugging isn't bad code. It's confident code that addresses the wrong thing. A failing test is the cheapest possible guard against a fix that doesn't actually fix.
Why CLI Agent Bug Fixing Needs a Reproduction, Not a Description
A bug description is ambiguous; a failing test is not. "The refund is broken" could mean ten different things. A test that asserts
balance == 90 after refunding 10 from 100There's a second reason, and it's about the agent's own loop. Terminal agents are strongest when they can run a command and read the result. A failing test gives the agent a tight feedback signal: change code, run test, read pass/fail, iterate. Without it, the agent is editing blind, judging its own success by vibes. With it, the agent has an oracle. This is why cli agent bug fixing with a reproduction test converges so much faster than "just fix it" — the agent isn't guessing whether it succeeded, it's checking.
⚡ Pro tip: Make "confirm it fails first" an explicit instruction. Agents sometimes write a test that passes against the buggy code because they subtly misunderstood the bug. A test that passes before the fix proves nothing. Requiring the agent to show you the red run first catches that misunderstanding immediately.
Running the Loop End to End
With the reproduction in hand, the fix loop is short and safe.
First, let the agent fix against the failing test with its test loop wired in. Aider can run your test command after every edit and iterate until it passes; Claude Code will run the command your project file specifies.
aider --auto-test --test-cmd ,[object Object], src/billing/refund.py
> make the failing refund ,[object Object], pass; change only what,[object Object]What this does: The agent edits the refund logic, runs the specific failing test after each change, reads the result, and keeps going until it's green — scoped to one test file so the loop stays fast. You review a fix that already passes its own reproduction.
Second, run the whole suite once it's green, to catch regressions the narrow test wouldn't. A fix that passes its own test but breaks three others isn't a fix.
pytest -q ,[object Object],What this does: Runs the complete test suite after the targeted fix passes, surfacing any regression the single reproduction test couldn't see. Green here means the fix is contained; red means you've traded one bug for another.
Third, read the diff yourself. The test proves behavior; the diff proves the agent didn't "fix" it by deleting the feature or hard-coding the expected value.
⚠️ Common mistake: Trusting a green test without reading the diff. Agents under pressure to make a test pass will sometimes cheat — hard-coding the return value, or weakening an assertion. A passing test tells you the assertion is satisfied; only the diff tells you it was satisfied honestly. Read both.
When the Bug Won't Reproduce
Sometimes the agent can't write a failing test because the bug won't reproduce on demand — the classic heisenbug that only shows up in production, under load, or once a day. Reproduce-first seems to break down here. It doesn't; it just moves up a level. When you can't reproduce the bug directly, the agent's job becomes adding the observability that will let you reproduce it, not fixing it.
claude
> This bug only appears ,[object Object], production. Don,[object Object]What this does: Redirects the agent from an impossible fix to a tractable task — instrumenting the code so the next real failure hands you the reproduction you couldn't create synthetically. You're not guessing at the bug; you're building the trap that catches it.
The other tool for stubborn bugs is
git bisectgit bisect start; git bisect bad; git bisect good v2.1.0
,[object Object],What this does: Walks the commit history to isolate the exact change that introduced the bug. The agent runs your reproduction check at each bisect step, turning a vague "it broke sometime last week" into a specific commit you can read.
⚡ Pro tip: For intermittent bugs, have the agent write a test that runs the suspect path many times in a loop before you call it unreproducible. A bug that fires one time in fifty becomes a reliable failing test if you run the path two hundred times — and a reliable failing test is back on the reproduce-first path.
⚡ Pro tip: Feed the agent the actual production logs and stack trace, not your paraphrase of them. Agents debug far better from raw error output than from a human summary, because the summary has already thrown away the detail — the exact line number, the specific exception — that pins the bug down.
Real-World Bug-Fixing Workflows
A backend engineer at a payments company keeps a standing rule in her project file: "for any bug, write a failing test first, then fix." Every agent session inherits it, so she never has to remember to ask. Her regression suite grows with every bug fixed, because each fix leaves its reproduction test behind permanently.
A frontend developer at a media site uses the agent to reproduce flaky UI bugs by having it write a test that fails intermittently, then instruments the code until the flake is deterministic. The reproduction is the debugging — once the bug is a reliable failing test, the fix is usually obvious.
A site-reliability engineer debugging a production incident points the agent at the failing service's logs and the relevant code, asks for a hypothesis and a test that would confirm it, and runs that test against a staging replica. The agent's hypothesis is only as good as the test that checks it, which keeps the incident response honest under pressure.
A QA automation lead runs agents headless in CI: when a bug ticket comes in, a scripted
claude -pclaude -p ,[object Object], --max-turns 4What this does: Runs a bounded, non-interactive pass that turns a bug report into an executable reproduction and stops. The engineer who picks up the ticket starts from red, not from a description.
Common Mistakes
⚠️ Common mistake: Asking the agent to fix a bug it can't reproduce. If neither you nor the agent can write a test that fails because of the bug, you don't understand the bug well enough to fix it reliably — and any patch is a guess. Spend the effort on the reproduction; the fix is the easy part once the reproduction exists.
The second mistake is letting the agent fix and refactor in the same breath. "Fix this bug and clean up the file while you're in there" produces a diff where the one-line fix is buried in fifty lines of unrelated reformatting, and you can't tell which change actually mattered. Fix first, in the smallest possible diff. Refactor later, separately, if at all.
⚡ Pro tip: Keep every reproduction test after the bug is fixed. The tests an agent writes to reproduce bugs become your most valuable regression suite over time, because they're derived from real failures your code actually had — not hypothetical cases someone imagined. A year of reproduce-first cli agent bug fixing leaves you with a suite that guards exactly the things that have historically broken.
Conclusion
The best cli agent bug fixing workflow refuses to start with the fix. Reproduce first with a failing test, confirm it fails for the right reason, fix against it until green, run the full suite, and read the diff. The reordering feels slower for thirty seconds and is dramatically faster over the life of the bug, because it replaces the agent's guessing with checking — and it leaves a regression test behind every single time.
The reproduce-first prompts, the "confirm it fails first" instruction, the "fix in the smallest diff, refactor separately" rule — these are the same for every bug in every language. Save them in PromptABCD so your next debugging session starts from a proven workflow instead of the "just fix it" instinct that produces confident, wrong patches.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
