Engineering

How to write a bug report an agent can act on

Editorial · Reveneau · September 15, 2026

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

Common questions

What makes a bug report usable by an AI agent?

Four parts: an exact reproduction with starting state and ordered steps, the observed behaviour stated separately from the expected behaviour, a boundary naming where the fix belongs, and an explicit list of what must not change. The first two describe the defect and the last two prevent the fix from spreading into code nobody asked about.

Why does a bug report that works for a colleague fail for an agent?

Because most of the message was never in the text. A colleague supplies the release history, the parts of the system that break easily, and the reason a strange piece of code exists, so three vague lines are enough for them, while an agent has the repository and none of the surrounding knowledge.

How precise does the reproduction need to be?

Precise enough that someone with no prior knowledge can trigger the failure on the first attempt. That means the starting state, the exact input values, the browser or client, and the steps in order, because "sometimes on mobile" describes a suspicion rather than a procedure anyone can follow.

Why write the expected behaviour separately from the observed behaviour?

Because a report that only says what went wrong leaves the correct behaviour to be inferred, and an inferred rule is usually the narrowest one that makes the symptom disappear. Stating the rule and the reason behind it gives the fix something to satisfy other than the single case in the report.

What is the boundary in a bug report?

A statement of where the fix should go: the module, the file, or the layer. It is a search area rather than a diagnosis, and it exists to stop a small correction from turning into a rewrite of surrounding code that happened to look improvable along the way.

Why does an agent need to be told what must not change?

Because code that looks wrong and is deliberately correct is common, and nothing in the file explains it. Retry logic shaped by a payment provider's requirement, or an API response format three clients depend on, reads as an obvious cleanup opportunity to anything that does not know the history.

Should a bug report include a suggested fix?

Include the constraint the fix has to satisfy rather than the implementation, unless there is a genuine reason only one approach works. A prescribed solution narrows the investigation before it starts, and if the diagnosis in the ticket is wrong the agent will implement the wrong repair competently.

How do you handle a bug you cannot reproduce reliably?

Write down the conditions you do know, the frequency, and everything you have ruled out, then say plainly that reproduction is unreliable. That framing turns the task into an investigation with a real starting point instead of a repair request that will produce a confident change to the wrong thing.

Does this apply to feature requests as well as bugs?

Yes, and the same gap causes the same trouble. A feature described in one sentence relies on the reader knowing what the product is for and which rules matter, so a request needs the expected behaviour, the boundary, and the constraints written down exactly as a defect report does.

What does a good bug report do for the verification step?

It supplies the test almost directly, because a precise reproduction plus a stated expected behaviour is close to an executable check. That turns the report into something that can be verified automatically rather than something a reviewer has to confirm by reading the change and hoping.

How long should a report like this take to write?

A few minutes more than a vague one, and it replaces a longer conversation later. The time spent naming the boundary and the constraints is repaid immediately, because the alternative is reviewing a change to six files when the defect was in one.

Start a project