# How to debug code with AI: a practical workflow

URL: https://agentvera.dev/en/blog/debug-code-with-ai/ · Published: 2026-10-27

Debug code with AI the reliable way: reproduce first, hand the agent the failing test and logs, bisect with git, find the root cause, then lock the fix in a test.

**In short:**

- An AI agent debugs well when it can run the bug itself: start from a reproduction, a failing test or an exact command, not a description of the symptom.
- Give it the full stack trace and logs, let it bisect with git bisect run, add temporary logging, and ask for the root cause before any fix.
- Finish with a regression test that fails before the fix and passes after, and stop the agent when it starts guessing or loosening tests.

**To debug code with AI, give the agent a way to reproduce the bug, the full error and logs, and a clear rule: find the root cause before changing anything.** A coding agent such as Claude Code or Codex can run your tests, read stack traces, bisect your git history and add logging, which makes it a strong debugging partner. It fails in predictable ways too: it guesses when it cannot run the failing case, and it “fixes” symptoms by catching errors or relaxing tests.

This guide is a workflow that plays to the first and guards against the second: reproduce, feed the evidence, narrow down, explain, fix, lock it in with a test, and know when to pull the plug.

## Why agents get debugging wrong

Most bad AI fixes come from the same few places:

- **No reproduction.** The agent reads the code, forms a theory and patches it. Nothing proves the theory was right.
- **Partial evidence.** You paste the last line of the error. The useful frame, three levels down the stack, never reaches the model.
- **Fixing the symptom.** A null check, a `try/catch` or a retry makes the error disappear while the bad state that caused it is still there.
- **Moving the goalposts.** The test fails, so the agent edits the test.
- **Long, polluted sessions.** After five failed attempts the conversation is full of wrong theories, and the model keeps building on them.

Every step below is aimed at one of these.

## Step 1: reproduce the bug first

Before the agent touches code, it needs a command that shows the bug. That can be a failing test, a `curl` call, a script, or a page in the browser. The point is that anyone, including the agent, can run it and see the failure.

If you already have one, put it at the top of the prompt:

```text
This fails:

  pnpm vitest run src/billing/invoice.test.ts -t "applies discount once"

Expected total 90, got 81. Don't change any code yet.
Run the test, confirm you see the same failure, and tell me what you see.
```

If you don’t have a reproduction, make that the first task:

```text
Users report that saving a draft twice creates two drafts.
Write a failing test that reproduces this. Do not fix anything.
Stop when the test fails for the right reason.
```

“For the right reason” matters. A test that fails because of a typo in the test proves nothing. Ask the agent to show the failure output and explain why it matches the bug report. For intermittent bugs, have it run the reproduction in a loop (for example 50 times) and report how often it fails, so you can tell later whether a fix actually helped.

## Step 2: give the agent the full evidence

Agents are good at reading long, noisy output. Don’t trim it for them. Give:

- the **complete stack trace**, not only the message;
- the **exact command** and its full output;
- **relevant logs** around the time of the failure;
- **what changed recently**: a dependency bump, a deploy, a merged branch;
- **environment details** if they might matter: OS, runtime version, feature flags.

You don’t have to paste everything into the chat. Save it to a file and point the agent at it, or pipe it straight in. With Claude Code’s print mode:

```bash
pnpm test 2>&1 | tail -n 200 > /tmp/test-output.txt
cat /tmp/test-output.txt | claude -p "Explain the root cause of this failure. Don't edit files."
```

Inside an interactive session, `!` runs a shell command and puts its output into the conversation in both Claude Code and Codex, for example `!pnpm test src/billing`. For huge logs, ask the agent to `grep` for the request ID or the error code instead of reading the whole file; it saves a lot of the [context window](/en/glossary/context-window/ "What is a context window").

## Step 3: narrow it down with git bisect

When something used to work and now doesn’t, you don’t need a theory. `git bisect` finds the first bad commit by binary search, and it can run fully automatically, which makes it a perfect job for an agent.

First, write a small script that exits 0 when the code is good and non-zero when it is bad:

```bash
#!/bin/sh
# check.sh
pnpm install --frozen-lockfile >/dev/null 2>&1 || exit 125
pnpm vitest run src/billing/invoice.test.ts -t "applies discount once"
```

Then let git do the walking:

```bash
git bisect start
git bisect bad HEAD
git bisect good v2.3.0
git bisect run ./check.sh
git bisect reset
```

The exit codes are the contract, as the official `git bisect` docs define them: 0 means good, any code from 1 to 127 except 125 means bad, 125 means “can’t test this commit, skip it”, and anything higher aborts the bisect. That is why the install step above exits 125: a commit that doesn’t even install should be skipped, not counted as bad.

A prompt that hands the whole thing to an agent:

```text
The invoice discount test passes on tag v2.3.0 and fails on main.
Write a check script for git bisect run (exit 125 if the commit
can't be built), run the bisect, then git bisect reset.
Report the first bad commit and explain which line in its diff
causes the failure. Don't fix anything yet.
```

Make sure the working tree is clean first, or do it in a separate [git worktree](/en/blog/git-worktree-parallel-agents/ "Git worktrees for parallel agents") so the bisect checkouts don’t fight with your own work. If the test file itself didn’t exist in old commits, copy it to a path outside the repo and have the script run that copy.

## Step 4: add logging, then remove it

When the stack trace doesn’t explain the state that led to the error, the agent needs to see values at runtime. Ask for targeted, temporary logging:

```text
Add temporary logs that print the cart items, the discount list and
the running total at each step of applyDiscounts(). Prefix every line
with [DEBUG-1234] so we can find and remove them later. Run the
failing test and show me the log lines.
```

The prefix is the trick. When the bug is understood, one instruction cleans up:

```bash
git grep -n "DEBUG-1234"
```

Agents also handle debuggers well when they are scriptable: `node --inspect` with a breakpoint is awkward for a terminal agent, but a quick `python -m pdb` session, an extra assertion, or a one-off script that calls the function with the failing input usually gets the same answer faster.

## Step 5: root cause before the fix

This is the most important rule. Ask the agent to explain the bug **before** it writes a fix, and read the explanation:

```text
Before changing any code, explain the root cause:
1. What state is wrong, and where does it first become wrong?
2. Why does the code produce that state?
3. Why didn't existing tests catch it?
Then propose the smallest fix and wait for my OK.
```

A good answer points at a specific line and a specific condition (“the discount is applied in both `addItem` and `checkout` since commit a1b2c3 moved the call”). A weak answer is vague (“there may be an issue with how discounts are handled”) or jumps to a defensive patch. If you get the weak kind, the agent hasn’t found the cause yet; send it back to Step 3 or 4.

Claude Code’s plan mode is useful here, because the agent can read and run read-only commands but not edit files until you approve. Start it with `claude --permission-mode plan`, or press Shift+Tab to cycle into it. [Claude Code plan mode](/en/blog/claude-code-plan-mode/ "Claude Code plan mode") covers it in detail. In Codex, `/plan` serves a similar purpose.

## Step 6: fix it and lock it in with a regression test

Now let the agent fix it, with constraints:

```text
Apply the fix. Rules:
- Do not edit or skip existing tests.
- Do not catch and swallow the error.
- Add a regression test named after the bug that fails without
  the fix and passes with it. Prove both: revert the fix, run the
  test, restore the fix, run it again.
- Run the full test suite at the end.
```

The “prove both” part is what makes the test trustworthy. A regression test that would have passed before the fix is decoration. For more on getting useful tests out of an agent, see [how to write unit tests with AI](/en/blog/write-unit-tests-with-ai/ "Write unit tests with AI").

Then review the diff yourself, looking for the usual symptom fixes:

| Pattern in the diff | Why it’s suspicious |
| --- | --- |
| New `try/catch` that logs and continues | The error is hidden, the bad state remains |
| Optional chaining or `?? default` added at the crash site | Treats missing data as normal instead of asking why it’s missing |
| Retries or longer timeouts | Often masks a race condition |
| Type widened to `any` or `unknown` | Silences the compiler instead of fixing the type |
| Test expectation changed | The goalpost moved |

Sometimes one of these is the right fix. The question to ask is whether the agent explained why.

## Browser bugs: give the agent a browser

UI bugs are hard to describe in text: a button that does nothing, a layout that breaks after a click, an error that only shows in the console. With [Playwright MCP](https://github.com/microsoft/playwright-mcp "Playwright MCP") the agent can open the page and look for itself. Add it to Claude Code:

```bash
claude mcp add playwright npx @playwright/mcp@latest
```

or to Codex in `~/.codex/config.toml`:

```toml
[mcp_servers.playwright]
command = "npx"
args = ["@playwright/mcp@latest"]
```

Tools such as `browser_navigate`, `browser_click`, `browser_snapshot`, `browser_console_messages` and `browser_network_requests` let the agent reproduce the bug step by step, read the console errors and see which API call failed. A debugging prompt:

```text
Start the dev server. Open http://localhost:5173/settings, change the
display name and click Save. Report console errors and the network
request for the save, with status and response body. Don't fix yet.
```

Once the cause is clear, ask the agent to turn the steps into a Playwright test so the bug stays fixed. [AI agent browser testing](/en/blog/ai-agent-browser-testing/ "AI agent browser testing") goes deeper into the setup.

## Bugs that only show in CI

When tests pass locally but fail in CI, the difference is usually environment: timezone, locale, parallelism, missing env vars, a different Node or Python version, or test order. Give the agent the CI log and the workflow file, and ask it to list the differences between CI and your machine before guessing. Running the suite in random order or with the CI’s timezone (`TZ=UTC pnpm test`) often reproduces the failure locally. If CI failures are a regular chore, [auto-fixing CI failures with AI](/en/blog/auto-fix-ci-failures-with-ai/ "Auto-fix CI failures with AI") shows how to automate the loop.

## When to stop the agent

An agent will keep trying long after it should stop. Pull the plug when:

- **Two or three fixes have failed.** Each new attempt is built on the same wrong theory.
- **The diff spreads.** It started in `invoice.ts` and is now editing config, unrelated modules or lock files.
- **It touches the tests.** Changing an assertion to match the wrong output is never a bug fix.
- **It can’t reproduce the bug but fixes it anyway.**
- **The explanation keeps changing** between turns without new evidence.

What to do instead:

1. Stop the turn (Esc in Claude Code and Codex).
2. Undo its changes. Commit before you start debugging so `git restore .` or `git stash` takes you back; [undoing Claude Code changes](/en/blog/undo-claude-code-changes/ "Undo Claude Code changes") covers the options.
3. Write down what you learned: which theories were wrong and why.
4. Start a **fresh session** with the reproduction, the facts and the ruled-out theories. A clean context with three good facts beats a long one with ten bad guesses.

Sometimes the right move is to take a narrower question: “Is `cart.items` already wrong when `checkout()` is called?” is easier to answer than “fix the checkout bug”.

## Debugging with AgentVera

[AgentVera](/en/download/ "Download AgentVera") is a desktop app for macOS, Windows and Linux that runs Claude Code, Codex, Gemini CLI and other CLI agents side by side in real terminals. Several of its tools fit the workflow above:

- **[Send to agent](/en/features/send-to-agent/ "Send to agent"):** select an error in the terminal dock, the browser console or Docker logs and send it to an agent with ⌘⇧L, or click the Fix badge on a caught error. Long logs are capped at 12,000 characters and keep their end, where the stack trace usually is.
- **[Agent browser](/en/features/agent-browser/ "Agent browser"):** a separate-profile Chrome that agents drive through Playwright MCP, with tabs streamed live so you can watch the agent reproduce the bug.
- **[Checkpoints](/en/features/checkpoints-and-replay/ "Checkpoints and session replay"):** each turn is snapshotted to a hidden git ref, so you can see what a failed attempt changed and undo that turn without touching your branches or stash.
- **Two theories in parallel:** start two agents in separate worktrees from the [Git panel](/en/features/git-and-github/ "Git and GitHub"), give each one a different hypothesis, and keep the fix that holds up.
- **[Verify](/en/features/verify/ "AgentVera Verify"):** on Pro and Team, criteria like “the regression test fails without the fix and passes with it” are checked by a separate read-only verifier when the agent’s turn ends.

Once the bug is fixed, write down what you learned where the next person will find it; [writing documentation with AI](/en/blog/write-documentation-with-ai/ "Write documentation with AI") covers that side.

## Wrapping up

Debugging with an AI agent works when you treat it like debugging with a sharp colleague: start from a reproduction, share all the evidence, narrow the search with `git bisect`, add logging to see real values, and insist on the root cause before the fix. End every bug with a regression test that you have seen fail and pass. And when the agent starts guessing, stop it, undo, and start fresh with what you’ve learned.

## Frequently asked questions

**Can AI really debug code, or does it just guess?** A coding agent can debug for real when it can run the code: reproduce the bug, read the output, add logging and test a hypothesis. Without a way to run the failing case it can only guess from reading, which is where most wrong fixes come from.

**What should I give the agent when I report a bug?** The exact command or test that fails, the full error with its stack trace, what you expected instead, and anything that changed recently. A one-line reproduction beats a long description of the symptom.

**Can an agent run git bisect on its own?** Yes. Give it a good and a bad commit and a script that exits 0 when the code works and 1 when it does not. git bisect run then checks out commits and runs the script until it finds the first bad one. Exit code 125 tells git to skip a commit that cannot be tested.

**How do I stop an AI agent from making a fix that only hides the bug?** Ask for the root cause in plain words before any code changes, forbid editing or skipping existing tests, and require a regression test that fails without the fix. Review the diff for try/catch blocks, retries and widened types that silence the error instead of removing its cause.

**When should I stop the agent and debug myself?** When it has tried two or three fixes that did not work, when it starts changing unrelated files, or when it proposes weakening a test or an assertion. Stop it, undo its changes, and restart with a sharper reproduction or a smaller question.

---

**About AgentVera.** AgentVera is a desktop app for macOS, Windows and Linux, built by Solviera Teknoloji. It runs 18 AI coding agents (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) side by side, per project, in real terminals with the user's own CLI installs and logins. The free plan has unlimited agents. Download: https://agentvera.dev/en/download/ · Pricing: https://agentvera.dev/en/pricing/
