---
title: "Lessons from 40+ Coding Agent Harnesses: Context Pollution Decides Failure"
url: "https://www.morphllm.com/blog/coding-agent-harness-lessons"
description: "After studying every major coding agent harness, one pattern dominates: context pollution determines task failure. Search wastes 60% of agent time. Edit retries inject redundant file reads. The agents that win are the ones that keep their context clean."
date: "2026-03-16"
author: "Tejas Bhakta"
---
# Lessons from 40+ Coding Agent Harnesses: Context Pollution Decides Failure

We've been pulling coding agent harnesses apart for a while now, and the count is somewhere past forty. That's Claude Code and Cursor and Aider, Cline and Continue and OpenCode, SWE-agent and Codex CLI and Windsurf and Amazon Q, and then a long tail of open-source forks and internal builds that nobody outside the company will ever see.

They disagree about almost everything you'd think would matter, from how they plan to how they search to how they hand work off between models. What surprised us is that none of those choices decides whether the agent succeeds. The thing that does is how quickly the agent's context fills up with garbage.

## Context rot is real, and you can measure it

When the context is small the model is sharp, and as it grows the model gets duller, and the part that trips people up is that this happens even if every token in the window is genuinely relevant.

Chroma [ran the experiment](https://research.trychroma.com/context-rot) on 18 different LLMs, GPT-4.1 and Claude 4 and Gemini 2.5 and Qwen 3 among them, sweeping across 8 input lengths and 11 needle positions. What they found for Opus 4.6 is a loss of about 14 percentage points over a 750K token span, which works out to roughly 2% for every 100K tokens you add. A model comfortably above 90% on a short prompt is already coming apart by the time you hit 32K. And this is the easy case, a plain needle-in-a-haystack lookup, long before anyone asks it to reason across a handful of files at once.

Random Labs calls the bad region the ["Dumb Zone"](https://randomlabs.co/blog/slate): the part of the window where retrieval quality drops below usable. Working memory is whatever sits above that line. Inject noise and the line creeps toward you.

[Augment Code](https://www.augmentcode.com/tools/context-window-wars-200k-vs-1m-token-strategies) watched accuracy fall from 89% at 8K tokens to 25% at 1M. Which is to say the million-token window is mostly a number on a spec sheet. The [Lost-in-the-Middle](https://arxiv.org/abs/2307.03172) paper (Liu et al.) saw accuracy fall 30%+ when the thing you need sits in the middle of a long context. And [LongMemEval](https://arxiv.org/abs/2410.10813) at ICLR 2025 had GPT-4O at 60-64% on full context, versus 87-92% once you handed it oracle retrieval.

Spotify [ran into this for real](https://engineering.atspotify.com/2025/11/context-engineering-background-coding-agents-part-2). Their agents "tended to get lost when context window filled up, forgetting the original task after a few turns." Steve Yegge said it with more flair: ["coding agents toward the end of their useful context window will do anything to get the room clean-looking before their battery runs out."](https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a)

Put those together and you get a strange result. A model handed 8K clean tokens beats the same model handed 48K that's half tool output from botched edits and files it re-read for no good reason.

The benchmarks say the same thing out loud. SWE-Bench Pro is 1,865 tasks spread over 41 repos, and if you point Augment, Cursor, and Claude Code at it with the same underlying model, they finish **17 problems apart** on 731 issues with nothing different but the scaffold around them. On SWE-Bench Lite the gap gets even louder: GPT-4 scores [2.7% under an early RAG scaffold and 28.3% under CodeR](https://arxiv.org/pdf/2509.16941), which is a 25.6 point swing you bought with nothing but the harness.

So the harness is where your leverage actually lives. It decides two things, how the agent finds code and how it applies edits, and both of those are the same context problem wearing different clothes.

## The search problem

[Cognition clocked](https://cognition.ai/blog/swe-grep) 60% of an agent's time going to search instead of to writing code. Picture Opus trying to find a webhook handler somewhere in a big repo. It greps for "webhook," reads three or four files, works out that one of them is a test fixture, reads two more, backtracks, and eventually lands on the real handler. By then it's dragging six files around and four of them are useless. The problem is that those four aren't merely dead weight in the token budget; they [actively degrade](https://arxiv.org/abs/2307.03172) the model's ability to think about the two files that count.

This is how context gets polluted in basically every harness I've looked at. The agent reads 50 files to find the 3 it needed, and then all 50 sit in the history and get replayed on every single call that follows.

[Manus found](https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus) that the input-to-output token ratio for agents comes out around 100:1, nowhere near the balanced ratio you get from a chatbot. Almost everything an agent touches is input, whether that's a tool result or a file read or the output of a search, so the frontier model burns most of its capacity reading rather than writing. And that's exactly why what it reads is the lever you want your hand on.

A sub-agent takes care of this by running the search inside its own window. It does the same exploration you'd have done anyway, except it swallows the dead ends itself and hands back only the files that matter, with the exact line ranges attached. The main model never has to look at the mess it took to get there.

Anthropic's [multi-agent research system](https://www.anthropic.com/engineering/multi-agent-research-system) is the clean demonstration. Opus 4 plus Sonnet 4 sub-agents beat single-agent Opus 4 by 90.2%. Each sub-agent burned 10K+ tokens exploring but returned 1,000-2,000 tokens of condensed results. Anthropic also found token usage alone explains 80% of the performance variance on BrowseComp, with tool calls and model choice mopping up most of the rest.

Everyone who builds a good harness lands on the same move. Claude Code spins up [Task agents](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) in parallel windows. Cognition built [SWE-grep](https://cognition.ai/blog/swe-grep). [Sourcegraph's Amp](https://ampcode.com/notes/how-to-build-an-agent) puts it as sub-agents "fundamentally changing your relationship with the context window by giving you a multiplication of context windows." The main window is the first-class citizen. Protect it.

### Why a search-specific model wins

Any model can play the search sub-agent, and we tried a bunch of them, Haiku and Sonnet and GPT-4o-mini. A dedicated one still wins, for a fairly narrow reason. Search wants a lot of parallelism, and RL-training a model to be good at parallel tool-call formats usually regresses whatever it knew about sequential ones. So the model you'd want for search is not the model you'd want for the main loop.

[WarpGrep](https://morphllm.com/products/warpgrep) fires up to 8 parallel tool calls in a turn and runs up to 4 turns, so that's as many as 32 calls all chasing separate hypotheses at the same instant: this grep pattern, that directory, some other file glob. On turn 1 it spreads its bets wide, and by turns 2 and 3 it's narrowing based on whatever came back.

Cognition's [SWE-grep](https://cognition.ai/blog/swe-grep) is put together the same way, with up to 8 parallel calls a turn, a hard cap of 4 turns, nothing but grep/read/glob, and a 5-second latency target so it never breaks the developer's flow. SWE-grep-mini runs above 2,800 tokens/second on Cerebras. The nice part is that none of the parallelism was designed in. Nobody wrote a reward for it. The model works out on its own, through RL, that firing more calls at once pays off.

The training throws off some behaviors we didn't ask for. It greps into `node_modules/` when the answer isn't in the app code. It follows an import to source to implementation across hops. It stops early once the next call clearly won't add anything.

Results on SWE-Bench Pro:

| Model | Without WarpGrep | With WarpGrep v2 | Delta |
|-------|:-:|:-:|:-:|
| **Opus 4.6** | 55.4% | **57.5%** | +2.1 |
| **Codex 5.3 (CLI)** | 56.0% | **59.1%** | +3.1 |
| **MiniMax 2.5** | 55.4% | **57.6%** | +3.7 |

Every model improves. Every pairing reaches #1.

The cost and the speed both move the way you wouldn't guess. Bolting a second model onto the system makes the whole thing *cheaper* and *faster* at once, 15.6% cheaper at $2.51 against $3.06 a task, and 28% faster at 445s against 618s. WarpGrep spends the cheap tokens on search so the expensive model never has to.

## The edit problem

If search pours noise in from the outside, failed edits pour it in from the inside.

The usual way to edit a file is search-and-replace. The model hands over an `old_string` and a `new_string`, the harness locates the old one and swaps it. Simple enough until the model gets the whitespace slightly wrong, or invents a line that isn't there, or hands over a string that happens to occur twice. Now the match fails, and you're into the recovery loop that quietly drains the budget: an error comes back, a `read_file` shoves the whole file (often 10-30KB) into the history, the model tries again, and sometimes it fails again anyway.

Look at how the various harnesses cope and you find a small arms race of fuzzy matching. [Fabian Hertwig wrote it up](https://fabianhertwig.com/blog/coding-assistants-file-edits/): Codex escalates through three tiers, Aider through four, OpenCode grinds through a nine-pass fuzzy chain, and RooCode goes so far as to expand outward from a guessed region using Levenshtein scoring. All that machinery exists to work around one stubborn fact. You simply can't count on a frontier model to reproduce an exact string from a file it read a few turns back.

Aider even has a name for the failure. It's [`SearchReplaceNoExactMatch`](https://github.com/Aider-AI/aider/issues/770), and it's the error its users report more than any other. Their [own numbers](https://aider.chat/docs/unified-diffs.html) put the edit format's effect at roughly 26% versus 59% for GPT-4 Turbo on the same tasks, which is enormous for a change that touches nothing about the model. One trace still sticks with me. A single refine somehow burned through 561,352 input tokens, and when I dug in, five `read_file` calls had done most of the damage. What got me was that two of those reads were the very same file. The only reason it got pulled twice was that an edit failed in between the first read and the second.

<div style={{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem', margin: '2rem 0', alignItems: 'start'}}>

<div>
<img src="/images/search-replace-flow.webp" alt="Search-and-replace edit flow: 8 tool calls, match failures trigger re-reads that bloat context" style={{width: '100%', maxWidth: '340px', borderRadius: '12px'}} />
</div>

<div>
<img src="/images/fast-apply-flow.webp" alt="Fast apply edit flow: 2 tool calls, no match failures, minimal context growth" style={{width: '100%', maxWidth: '340px', borderRadius: '12px'}} />
</div>

</div>

Fast apply attacks the problem from the other end. You stop asking the frontier model to hit a string exactly. Instead it writes down its intent and a rough sketch of the code, and it leaves everything it isn't touching behind a `// ... existing code ...` marker. A second model, the apply model, reads that sketch and merges it into the real file with an eye to structure. Once there's no string to match against, the entire re-read-and-retry cascade has nothing to feed on and disappears. Cursor [got here first](https://fireworks.ai/blog/cursor), training a speculative edits model for it. Ours is [Morph Fast Apply](https://docs.morphllm.com/); it lands 98% of its merges and runs at 10,500 tokens/second. A single edit costs it somewhere around 700-1,400 tokens, where the full-file rewrite it replaces would have been 3,500-4,500.

The point is that the frontier model never has to hold the whole file. It works from a sketch and hands the actual merge to a model built for nothing else.

## What forty harnesses taught us

A few things stuck with us after all of it.

The biggest one is that the thing holding agents back is context, not raw model intelligence. Give a current model a clean window and it can already solve most coding tasks. Random Labs [said it plainly](https://randomlabs.co/blog/slate): "The real bottleneck in long-horizon agentic tasks is context management, not model intelligence." So every token you burn on stray search results and failed edits and files you read twice is a token spent making the model dumber about the actual problem.

The fix that follows is to specialize and isolate. Push the search out into a sub-agent. Apply your edits with a fast model. And keep the frontier model's window clear for the one job it's genuinely better at than anything else, which is reasoning about code it's never seen. Anthropic found [moving from Sonnet 3.7 to Sonnet 4](https://www.anthropic.com/engineering/multi-agent-research-system) bought them more than doubling the token budget on 3.7 ever did. A good model in a clean window beats a great model in a dirty one.

Which is really just the harness again. Change the scaffold and the same models drift 17 problems apart on SWE-Bench Pro and 25.6 points apart on SWE-Bench Lite. So the agents that win this aren't running a cleverer planner or a bigger window. They're the ones that manage to keep their context clean.

---

Which is why we built [WarpGrep](/products/warpgrep), an RL-trained search sub-agent that hits #1 on SWE-Bench Pro with every major model, and [Morph Fast Apply](/products/fast-apply), a model that merges edits at 10,500+ tokens/second with no match failures. Both exist to keep the frontier model's window on the one job that needs it: writing the code.
