Why Your Coding Agent Can't Tell When the Work Is Done
Over the past months, I’ve burned through more than two billion tokens a week running agentic coding workflows using Codex and Claude. During this time, I’ve noticed a handful of recurring failure modes that show up when dealing with multi-hour agent execution across models, projects, and tasks.
I hesitate to call them true cognitive biases. The models are not conscious, and they are certainly not experiencing emotions. But the resulting behavior is consistent enough that thinking about them as cognitive biases has proven useful. More importantly, these behaviors explain why powerful coding agents still struggle with one critical task: deciding whether they are actually done. Two biases in particular drive this, and they turn out to be the same problem wearing different clothes.
The first shows up as the context window fills. As an agent’s context window fills up, the probability of premature completion appears to increase. When discussing this behavior with peers, I often call it agent context anxiety. Not because the model feels anxiety, but because its behavior starts to resemble a human working against an approaching deadline.
As the available context shrinks, the agent appears increasingly motivated to reach closure. Attention narrows. Exploration decreases. The focus shifts toward producing a final answer and moving on.
Some of this pressure is beneficial. It encourages efficiency and discourages wasting tokens. But excessive pressure creates failure modes: premature sign-off, shortcuts, and insufficient validation.
Modern agentic harnesses can compact the context before it gets full, but the model does not seem to be aware of that mechanism. So, in a long agentic session, the context window fills up, the agent gets anxious, starts optimizing for closure. If it doesn’t stop prematurely first, the harness compacts the context, the agent relaxes, and it gets a fresh runway.
The second bias is what I call the too deep in the weeds effect.
Here, the model loses sight of the broader objective and becomes focused on a narrow slice of the work. It successfully completes that slice and then incorrectly concludes that the overall task is complete.
For example, you may ask the model to implement a feature while staying aligned with coding best practices as defined by the project. The feature itself gets built, but the code is overdefensive and the tests are mock-heavy, exactly the patterns the project’s rules call out to avoid.
In this case, the model has effectively forgotten what “done” means and substituted a smaller goal for the original one.
The two failure modes look different, one about pressure and the other about scope, but they break in the same place. In both, the agent loses track of the real objective. The premature sign-off arrives with the same confidence as a genuine one.
That points at something structural. Doing the work and judging whether it’s finished are different jobs. The doer is operating under deadline pressure, inside a narrowed goal, buried in the context that produced the work. It’s the worst possible vantage point from which to ask, “Is this actually complete?”
Which leads to the uncomfortable conclusion underneath both biases: The agent performing the work should not be the one deciding whether the work is done.
Knowing these failure modes, how can we counter them?
Since the agent doing the work can’t be trusted to sign off on it, there’s a need for an external quality gate that works on two levels.
The first is mechanical: deterministic checks the model can’t argue its way around. Formatters enforce style. Linters catch likely bugs and enforce naming and complexity limits. Architecture tests protect the system’s intended shape by catching forbidden dependencies, layer violations, and boundary-crossing shortcuts, while a behavior-focused test suite verifies the code actually does what it’s supposed to. The doer should be instructed to run these mechanical checks often as it works, and frontier models are quite receptive to this guidance.
The second level is cognitive, covering the judgment no linter can make. Was the goal actually reached? Were the anti-patterns and shortcuts the project forbids actually avoided? These questions are inherently less deterministic, so they lean on the project’s instructions as the standard of truth. The crucial move here is who does the judging: never the agent that wrote the code. Instead, you spin up a fresh sub-agent with a clean context, hand it the diff, the original spec, and the project’s instructions, and let it evaluate the work from an unbiased vantage point.
This works neatly as an implementation loop once your feature specs are captured into a markdown file:
- The implementation agent reads its spec file and begins working, applying mechanical checks along the way.
- Once it determines the work is complete, it spawns a sub-agent to review the changes against the spec file and project instructions.
- If the reviewer gives the green light, the implementation agent stops. Otherwise, the reviewer returns concrete findings, and the implementation agent goes back to step 1.
Once tuned, this type of loop can dramatically increase feature completeness: not by making the implementation agent magically smarter, but by preventing it from declaring victory too early. In practice, this is the difference between work that feels 80% done and work that is much closer to truly complete.
I’ll share more about how I implement this loop in a future post. For now, understanding why it matters is already half the battle.