How to write a bug report an agent can act on

The bug report is the oldest tool in software, and it has always worked by leaving most of its information unwritten.
Consider a real one: "Checkout is broken on mobile, seems like a timing thing." A colleague reads that, remembers the race condition from last month, knows which release went out Tuesday, opens the right file, and has a fix in twenty minutes. The report was three lines. The message was much larger, and the rest of it was in the reader's memory.
Give the identical sentence to an agent and you get something confident, plausible, and directed at the wrong part of the system. Not because the agent understood less than the colleague, but because it received exactly what was written, which was never enough.
What the human was supplying for free
Worth naming the pieces, because they are invisible until they are missing.
A colleague knows which parts of the codebase break easily and which are stable. They know that the payment retry logic looks strange because a provider requires it that way. They know which customer reports this, and that the customer is on an old client version. They know that "timing thing" means the same thing it meant in March.
They also know when to come back and ask. That is the part that hides the problem, because a human who receives an underspecified ticket asks a question, and the missing information arrives in a hallway conversation that never reaches the ticket. The report is never improved. Its gaps just get filled, silently, every time it is read.
An agent has the repository, the tests, and the text you gave it. It cannot ask a colleague in the hallway. It fills gaps by inference, and inference from a partial description produces a change that satisfies the description and does not fix the real problem.
The four parts
1. Exact reproduction
Start with the state, then the steps, then the input.
"Sometimes fails on mobile" is a hypothesis. "Safari on iOS 18, logged in as a standard account, cart containing two items where one is out of stock, tap Pay" is a procedure. The difference is whether someone with no prior knowledge can trigger the failure on the first attempt.
Include the values. Not "an invalid postcode" but the exact string you typed. Not "a large order" but the number of line items. Defects that only appear at a boundary are common, and the boundary is usually in the value you did not write down.
If the failure is intermittent, say so explicitly and give the frequency you observed. An honest "reproduces roughly one time in five, always after the session has been idle" is far more useful than a clean-looking set of steps that does not actually reproduce anything. It also changes the task from a repair into an investigation, which is what you want when nobody knows the cause yet.
2. Observed and expected, written separately
Most reports describe what went wrong and stop. That leaves the correct behaviour to be inferred, and inference picks the narrowest rule that makes the symptom disappear.
Write both. "The order was created with a total of zero" is the observation. "An order should never be created when any line item failed validation, because downstream fulfilment treats a created order as committed" is the expectation, and it carries the reason. The reason is what stops a fix that special-cases a zero total while leaving the real rule broken.
This is the same discipline as writing a specification an agent can check, and the two documents end up similar. Our treatment of that is in writing specs an agent can verify, and the general problem of expressing a requirement precisely enough to act on is in writing software requirements.
3. The boundary
Name where the fix belongs. The module, the file, the layer.
This is not the diagnosis, and you do not have to be certain. It is a search area, and its job is to stop a small correction from expanding. Without it, a validation defect becomes a change to the form component, the state management, and two utility functions that looked improvable while the agent was there. Every one of those edits will be defensible in isolation. Together they are a review nobody has time for and a change nobody can confidently approve.
Say what is out of scope too. "The fix belongs in the order validation service; do not modify the cart component or the payment client" is one sentence and it removes most of the ways this goes wrong.
4. What must not change
The section that does not exist in human bug reports, and the one that matters most here.
Every codebase contains code that looks wrong and is deliberately correct. Retry logic shaped by a provider's rate limits. A response format three clients depend on. A duplicated check that exists because the first one runs before authentication. A person knows to leave these alone, or knows to ask. Anything working from the file alone reads them as code that needs cleaning up.
So list them. Which interfaces are contracts, which behaviour is depended on elsewhere, which strange thing is strange on purpose. If the reason is written down somewhere, link it. If it is not written down anywhere, this ticket is a good moment to fix that, because the next person to meet that code will have the same question.
The broader version of this principle, limiting what an autonomous system is permitted to change, is in AI agent permissions and guardrails.
Two things to leave out
A prescribed fix. State the constraint the solution has to meet, not the implementation, unless there is a genuine reason only one approach works. A suggested fix narrows the investigation before it begins, and if your diagnosis is wrong the wrong repair gets implemented well.
Certainty you do not have. "This is definitely a caching issue" sends the work somewhere specific. If you are not sure, write what you observed and what you ruled out. A list of what you ruled out is real information, and it stays true even if you are wrong about the cause.
The report is most of the test
Here is the part that makes the extra few minutes worth it.
A precise reproduction plus a stated expected behaviour is nearly an executable check already. You have the starting state, the input, and the assertion. Turning that into an automated test is a mechanical step, and once it exists the fix is verifiable rather than merely reviewable. The method is in how to write an acceptance test a machine can run.
That changes what review is for. Instead of reading a change and hoping you would notice the mistake, you have a check that fails before the fix and passes after, and a reviewer's attention goes to whether the rule itself was right. Which is the part a person is actually good at.
Vague reports produce changes that can only be evaluated by reading them, and reading is a weak tool here. Veracode's Spring 2026 research across more than 150 models on 80 tasks found generated code compiling and running correctly over 95 percent of the time while passing security checks in roughly 55 percent of generations. Code that runs is the easiest property to observe and the one that proves least, which is exactly why a defect gets through a review that felt careful. That tool gets weaker as volume rises.
Same discipline, easier to see
None of these four sections is new. A precise reproduction, a clear expectation, a scoped area, and a note about what not to disturb have always made a better ticket.
What changed is the feedback. A human reader accepts a bad report and quietly fills in what is missing, so the report never gets any better and nobody learns it was inadequate. An agent produces a visible, confident, wrong change, in about a minute. That is a harsh review of your ticket-writing, and it is an accurate one.
It also explains a frustration developers report constantly. Stack Overflow's 2025 survey found 66 percent naming "almost right, but not quite" as their biggest complaint about AI tools. Some of that is the model. A meaningful share is the instruction, because an almost-right description of the problem is a reliable way to get an almost-right solution back.
Teams that improve this find their human handoffs improve at the same time. The new engineer who joins in three months reads the same tickets, with none of the knowledge from hallway conversations either.
Thanks to the people who have rewritten a ticket after the first attempt produced something unrecognisable, and then written down why. The second version is almost always shorter than the conversation the first version caused.
Write the ticket for a competent stranger who cannot ask you anything. That reader now exists.
Related guide: Making AI agents reliable.
Sources
- Veracode, Spring 2026 GenAI Code Security update: across more than 150 models on 80 tasks, over 95 percent of generated code compiled and ran correctly against roughly 55 percent passing security checks.
- Stack Overflow 2025 Developer Survey, AI section: 66 percent cite "almost right, but not quite" as the biggest frustration with AI tools.


