How to Hand Off Bugs to Coding Agents: 2026 Method + Example
A 6-step repro-first method for handing bugs to Claude Code, Codex or Cursor: brief template, failing-test prompt, review checklist and worked example.
Someone pastes a Slack message, “invites are broken for some people,” into Claude Code, Codex or Cursor. The agent returns a confident, plausible diff. It merges, and the bug is still there, or a different one appears. At BuildBetter we hear this from product and engineering teams every week, and the model is rarely the cause. The hand-off is. This guide covers a six-step method you can run today with a spreadsheet and the coding agent you already use. It includes a full worked example and an honest view of when automating reproduction is worth the cost.
What It Means to Hand Off a Bug to a Coding Agent
Handing off a bug to a coding agent means giving an AI coding tool a structured, reproducible bug brief and a verification contract. The brief includes steps, expected result, actual result, reproduction rate, evidence and environment. The contract says the agent must reproduce the bug as a failing test before changing code, and a human verifies the fix against the original reproduction.
The core idea is simple. The agent is only as good as the brief. A coding agent will always produce a fix, because it is built to return output that matches your request. It will not stop to say it lacks the information to find the real cause. Your job is to make sure it fixes the right thing, and then to prove that it did.
The verification contract matters as much as the brief. Without it, the agent grades its own work. With it, you have a test that failed before the change, passed after it, and a human rerun of the original user flow confirming the bug is gone.
Scope: this guide applies to agentic coding tools that read a repository, plan multi-step changes, edit files and run commands such as tests and dev servers. That means Claude Code, OpenAI Codex (CLI, IDE extension and cloud tasks) and Cursor's Agent mode and background agents. It does not cover inline autocomplete.
Why Coding Agents Ship Confident Wrong Fixes
Coding agents ship wrong fixes because they optimize for a change that looks consistent with the description, and a vague description fits many changes. When the report says “invite expired,” the agent pattern-matches to the most common cause of that symptom, not the actual cause in your codebase. Developers feel this: in the Stack Overflow Developer Survey 2025, 66% named “AI solutions that are almost right, but not quite” as their top frustration, and about 45% said debugging AI-generated code takes more time.
The failures fall into six recognizable patterns:
- Symptom fixing. The agent hides the error message, adds a null check, or wraps code in try/catch. The error disappears from logs; the root cause stays.
- Wrong-cause fixing. “Invite expired” leads the agent to extend token lifetime, when the real cause is an email case mismatch. The diff is clean, reviewable and irrelevant.
- Unreproduced bugs. Nobody confirmed the bug happens reliably, so the agent “fixes” a flaky test, a stale cache or one user's browser extension.
- Missing environment. The bug exists only on staging data, in one browser, or under a feature flag state the agent cannot see. In local dev with seed data, it does not exist.
- Self-graded success. The agent writes a test that passes against its own fix but never failed against the original code. That test proves nothing.
- Scope creep. The agent “cleans up” adjacent code, and the diff grows too large to review against the bug.
Perceived speed makes these failures easy to miss. In METR's July 2025 randomized trial, experienced open-source developers using AI tools took 19% longer on tasks while believing they had been about 20% faster. The sample was small (16 developers on mature codebases), but it shows that how a fix feels and whether it works are different questions.
Every one of these failures traces back to two gaps. Either the input was not a reproducible bug, or there was no independent proof that the fix addressed the reproduction. The method below closes both.
The Method: A 6-Step Bug Hand-Off Any Team Can Run Today
The Repro-First Hand-Off needs a spreadsheet or doc, your existing coding agent and a browser. No new tool, no budget. It borrows the standard the industry uses to grade AI bug fixing: SWE-bench counts a task as resolved only when “fail-to-pass” tests (fail before, pass after) and existing “pass-to-pass” tests both succeed. You are applying that same bar to your own bugs.
Step 1 — Reproduce it yourself from a clean start, and count
Use a fresh browser profile or incognito window, a new test account and a known build. Run the steps three to five times and record the rate, such as “4 of 5.” The rate is diagnostic. A deterministic failure (5 of 5) points to logic or a data condition. An intermittent one (2 of 5) points to race conditions, caching, timing or environment state. Then vary one thing at a time to find the condition that changes the rate.
If you cannot reproduce the bug at least once, do not hand it off. Gather more evidence instead.
Step 2 — Write the brief with seven fields
| Field | What to include | Why the agent needs it | What breaks without it |
|---|---|---|---|
| Steps | Numbered, exact clicks and inputs, including the literal data used | Lets it write a test that follows the real path | Agent invents a path that may not trigger the bug |
| Expected result | What should happen | Defines the passing assertion | Agent guesses intended behavior |
| Actual result | What happens instead, with exact error text and status codes | Lets it confirm the test fails for the right reason | Test fails on a typo or selector and counts as a “repro” |
| Reproduced | Count from a clean start, plus any condition that changes the rate | Narrows where to look; any hypothesis must explain it | Agent fixes the most common cause, not yours |
| Replay or recording | Screen recording, HAR file or console log | Shows network calls and timing the steps omit | Reviewer cannot check the evidence |
| Environment | URL, build/commit, browser, flags, account role | Matches the conditions where the bug lives | Bug “vanishes” in local dev |
| Customer evidence | Ticket quotes or call snippets showing who is affected and how | Helps judge severity and edge cases | Fix ignores the affected segment or existing bad data |
Copy this template into a spreadsheet column or straight into your agent prompt:
BUG: [one-line title]
STEPS:
1. [exact action, with literal input]
2. ...
EXPECTED: [what should happen]
ACTUAL: [what happens; exact error text; status code]
REPRODUCED: [x of n from a clean start]
CONDITION: [what changes the rate, e.g. 0 of 5 when ...]
REPLAY: [link to recording / HAR / console log]
ENVIRONMENT: [URL] | [build or commit] | [browser] | [flags] | [role]
CUSTOMER EVIDENCE:
- [quote, source, account]
- ...Step 3 — Instruct the agent to write a failing test first
Paste the brief, then add:
Before changing any application code, write an automated test that
reproduces this bug. Run it and show me that it fails on the current
code for the reason described in ACTUAL. Do not modify application
code in this step.Check that it fails for the right reason. A test that fails on a missing import or a wrong selector is not a reproduction; the output should match the Actual field. Then commit the test separately. Anthropic's Claude Code guidance recommends exactly this: confirm the test fails, commit it, then tell the agent to make it pass without modifying the test. That stops the agent from “fixing” the bug by weakening the assertion. For UI bugs, see our guide to turning repro steps into Playwright end-to-end tests.
To make this the default, write the contract into your project instruction file: CLAUDE.md for Claude Code, AGENTS.md for Codex, or .cursor/rules for Cursor.
Step 4 — Require the agent to explain the cause before fixing
Ask for a one-paragraph root-cause hypothesis that names specific files and lines and explains why the cause produces the observed reproduction rate. Reject any hypothesis that does not explain the condition, such as why the bug fails 4 of 5 times rather than every time, or why one input type works and another does not.
Step 5 — Review the diff against the repro, not against vibes
- Does the test fail on main and pass on the branch? Does it fail again if you revert only the fix?
- Does the change touch the code path named in the hypothesis?
- Is the diff limited to the bug?
- Did it suppress an error rather than prevent it?
- Does it handle existing data, such as records created while the bug was live?
Step 6 — Rerun the original flow after merge
From a clean start, run the original steps the same number of times as in Step 1. Record “Reproduced after fix: 0 of 5” in the spreadsheet row and link the PR. Only then close the bug. Keep the test in the suite as a regression guard.
Here is the spreadsheet schema. It takes five minutes to set up:
| Bug ID | Brief link | Repro before (x/n) | Failing test link | Root cause (1 line) | PR | Repro after (x/n) | Status |
|---|---|---|---|---|---|---|---|
| BUG-142 | link | 5/5 | link | Case-sensitive invite lookup | #2318 | 0/5 | Closed |
Aside: if customer evidence is thin, a few targeted conversations can confirm who is affected. Our guide to running AI-moderated user interviews shows how to do this quickly.
Worked Example: Handing Off a Broken Team Invite Flow
This example is illustrative, not a customer case study, but every decision in it is one teams face regularly. Three support tickets in two weeks say invitees see “This invite has expired” immediately after receiving the email. The original Slack hand-off was: “invites expiring too fast, pls fix.”
Step 1: Reproduce and find the condition
The PM reproduces the bug from a clean start. Inviting the mixed-case email Dana.Lee@example.com fails 5 of 5 times. An all-lowercase email fails 0 of 5. That condition is the most valuable line in the brief.
The filled-in brief
BUG: Invite shows 'expired' immediately for mixed-case emails
STEPS:
1. Log in as admin. Go to Settings > Team > Invite.
2. Enter Dana.Lee@example.com, role Member. Click Send.
3. Open the invite link from the email in a fresh browser profile.
EXPECTED: Accept-invite page ('Join Acme') loads.
ACTUAL: 'This invite has expired.' GET /invites/accept returns 410.
REPRODUCED: 5 of 5 (mixed-case email)
CONDITION: 0 of 5 with dana.lee@example.com (all lowercase)
REPLAY: [recording + HAR link]
ENVIRONMENT: staging | commit 8f3c2a1 | Chrome 130 | no flags | admin
CUSTOMER EVIDENCE:
- 'Every invite I send says expired the second they click it.' (Ticket 4471)
- 'Two of my hires can't get in.' (Ticket 4502)
- 'Gave up and invited her personal Gmail instead.' (Ticket 4519, admin)The agent's failing test
test('invite link works for mixed-case email', async ({ page }) => {
await inviteMember({ email: 'Dana.Lee@example.com', role: 'member' });
const link = await getInviteLink('Dana.Lee@example.com');
const response = await page.goto(link);
expect(response.status()).toBe(200);
await expect(page.getByRole('heading', { name: 'Join Acme' })).toBeVisible();
});
// On main: Expected 200, Received 410The failure matches the Actual field, so it is a valid reproduction. The test is committed on its own.
Hypothesis 1: rejected
The agent's first hypothesis: extend the token TTL from 24 hours to 72 hours. Rejected. It does not explain why lowercase emails work 5 of 5 times. A TTL problem would hit every invite equally. This is the review step catching a confident wrong fix, and it is the fix the original Slack message would likely have shipped.
Hypothesis 2: accepted
The second hypothesis: the invite is stored with the email lowercased, but the lookup on accept uses the raw email from the link. The lookup misses and falls through to the “expired” branch. This explains the condition exactly.
Decisions the team made
- Normalize at write and read. Fixing only the read path leaves the next code path that writes emails open to the same bug.
- Fix the misleading error. A not-found invite now says “invite not found” instead of “expired,” so future reports describe the real problem.
- Handle existing data. Pending invites with mixed-case emails are still broken. The team re-sends them instead of writing a migration, because the count is small and re-sending carries less risk.
Verification
The failing test now passes, and the full suite passes. A post-merge rerun on staging shows 0 of 5 for mixed case and 0 of 5 for lowercase, from a clean start. The spreadsheet row is closed with the PR linked, and support replies to the three ticket authors.
Takeaway: the vague hand-off would likely have shipped the TTL change. The structured brief made the wrong fix visibly wrong.
Common Mistakes When Handing Bugs to Coding Agents
Most bad agent fixes come from a handful of repeatable hand-off mistakes, and each has a direct fix.
- Pasting the customer's words as the bug report. Customers describe symptoms, not conditions. Translate “it says expired” into steps, a rate and a condition before the agent sees it.
- Skipping the reproduction count. “It happened once” and “5 of 5” need completely different responses. The first needs investigation; the second is ready for a test.
- Accepting a test the agent wrote after the fix. If you never saw it fail on main, it is not evidence. Require the failure output first.
- Letting the agent pick the environment. Agents default to local dev with seed data, where data-dependent bugs often vanish. Name the environment in the brief.
- Batching several bugs into one prompt. Diffs blur together and review against any single repro becomes impossible. One bug, one brief, one PR.
- Reviewing the code but not rerunning the flow. A unit test can pass while the real user journey still breaks. Step 6 exists for this reason.
- Ignoring bad data created while the bug was live. The fix stops new damage but leaves old records broken. Ask the backfill question in every review.
Some problems no tool solves, including ours. Unclear product intent is one: “what should happen?” is a product decision, not a QA finding. Bugs that appear only under production load or with third-party integrations are another. So are reviewers who rubber-stamp diffs. Automated reproduction and hand-off do not replace judgment on expected behavior or careful code review.
When the Manual Method Stops Scaling
The full six-step method is overhead for trivial bugs, so match the process to the bug. For a one-line typo, a copy change or an obvious CSS misalignment you can see in the code, fix it yourself or tell the agent directly.
| Situation | What to do |
|---|---|
| Typo or copy change | Fix directly |
| Deterministic bug with an obvious cause | Short brief plus failing test |
| Intermittent, data-dependent or customer-reported bug | Full 6-step method |
| Recurring regressions across releases | Automate reproduction |
As a rule of thumb, the manual method works while one person can reproduce every bug from a clean start before hand-off. It strains when:
- Reproduction takes longer than the fix.
- You hand off more than a handful of bugs a week.
- Bugs recur after each release.
- Nobody owns the clean-start rerun after merge.
There is a stability cost to ignoring this. Google Cloud's DORA 2024 report found that a 25% increase in AI adoption was associated with an estimated 7.2% decrease in software delivery stability. Faster code generation without stronger verification tends to produce more change failures.
Tools That Help: BuildBetter QA Agent and the DIY Path
1. BuildBetter QA Agent — Best for reproduced bugs before every release
BuildBetter QA Agent (Build > QA Agent) tests your web app before each release with AI testers that explore test flows, check layout and retry suspected bugs from a clean start. Each test flow has a start page and a defined target, and admins choose which journeys are included. Runs happen on a nightly schedule, on a GitHub release trigger, or through Run now after you review the selected flows and credit limits. Each run uses credits.
Completed runs separate Verified bugs from Needs a look. Each finding carries steps, expected result, actual result and Reproduced (how often it happened from a clean start), which maps directly to the brief in the method above. Replay shows the exploration, repro 1 and repro 2 alongside the recorded agent actions, so you check the evidence before deciding what to fix. For hand-off, File to Inbox adds the bug to your team's work in BuildBetter Inbox/Triage, with Linear and Jira. Send to hands the same brief to a coding agent.
The case for one platform: QA findings sit in the same workspace as your customer calls, tickets and signals, so a bug and the customer complaints about it live side by side. Screens adds a screen library, captured sessions with replay and friction markers, and flows that synthetic personas can test.
Every plan includes unlimited seats, with usage-based credits published at buildbetter.ai/pricing. BuildBetter is SOC 2 Type II, HIPAA and GDPR compliant. Caveat: you still own expected-behavior decisions and code review. Teams with no web app or no release cadence may not need it.
2. Open-source DIY path — Best for teams that want to build their own
Use Playwright to write the failing end-to-end test and record traces. Stagehand, browser-use or Skyvern can drive agent-based browser reproduction if you want to build your own system. The trade-off is engineering time: someone has to maintain test environments, seed data and clean-start reruns.
FAQ: Handing Off Bugs to Claude Code, Codex and Cursor
What should a bug report for an AI coding agent include?
Seven fields: exact numbered steps with literal input data; expected result; actual result with exact error text and status codes; how many times it reproduced from a clean start (e.g., 4 of 5) and any condition that changes the rate; a replay, recording, HAR file or console log; the environment (URL, build/commit, browser, feature flags, account role); and customer evidence showing who is affected. Without the reproduction count and environment, the agent is guessing.
Should the coding agent write a failing test before fixing the bug?
Yes. Require the agent to write a test that fails on the current code for the reason stated in the bug report, and to show you the failure output, before it changes application code. This mirrors how SWE-bench grades agents (fail-to-pass tests) and Anthropic's recommended TDD workflow for Claude Code. A test that never failed proves nothing.
How do I know if an AI-generated bug fix is correct?
Check four things. First, the failing test now passes, and it fails again if you revert only the fix. Second, the diff touches the code path named in the root-cause explanation. Third, the explanation accounts for the reproduction condition and rate. Fourth, rerunning the original user flow from a clean start shows zero reproductions in the same number of attempts as before.
Is the hand-off process different for Claude Code, Codex and Cursor?
The brief and verification steps are the same. What differs is execution. Claude Code and Codex CLI run in your terminal with your local environment. Codex cloud tasks and Cursor background agents run in remote sandboxes that need dependencies, test runners and sometimes browsers configured. Cursor's Agent mode runs inside the editor. Confirm that whichever tool you use can actually run the failing test, and encode the contract in CLAUDE.md, AGENTS.md or Cursor rules.
When should I skip the structured brief and just fix the bug?
When the cause is obvious and the fix is a line or two, such as a typo, a copy change or a visible style error. Use a short brief plus a failing test for deterministic bugs with a clear cause. Use the full six-step method for intermittent, data-dependent or customer-reported bugs.
Can a QA agent hand bugs directly to a coding agent?
Yes. Some tools, including BuildBetter's QA Agent via Send to, pass a reproduced bug brief straight to a coding agent. A human should still review the replay evidence and the diff before merging.
Sources and Further Reading
- Test-driven development (Wikipedia): background on writing failing tests first
- Minimal reproducible example (Wikipedia): why reproduction quality determines fix quality
- Regression testing (Wikipedia): keeping the failing test as a permanent guard
- Playwright documentation: writing and running end-to-end tests that reproduce UI bugs
- BuildBetter QA Agent documentation: buildbetter.ai/university/qa-agent and docs.buildbetter.ai
- Stack Overflow Developer Survey 2025; METR, “Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity” (July 2025); Google Cloud DORA, Accelerate State of DevOps Report 2024; SWE-bench and SWE-bench Verified documentation; Anthropic, Claude Code best practices
- Related reading: Playwright Test Generation with AI: Complete Guide (2026)
Ship the Fix Customers Asked For, Then Tell Them
A reproduced bug, a failing test and a verified rerun get the right fix merged. The work is finished when the customers who reported the bug hear that it is fixed. BuildBetter keeps QA findings next to the calls, tickets and Slack threads where customers described the problem, so your team can ship the fix and close the loop in one place.