How a coding agent actually works: the eight layers of a harness
Strip away the terminal UI and every coding agent is the same eight layers. Understanding them tells you exactly why one harness is safe to leave unattended and another is not.

A coding agent harness has eight layers: the agent loop that repeatedly calls a model and executes what it asks for; the tool and edit engine that applies changes to disk; context assembly that decides what the model sees; the sandbox that bounds what execution can touch; the permission gate that decides which proposed actions run; the durability layer that records what happened; the model adapter that normalises providers; and the extension surface that lets you add capability. Most 2026 harnesses share the same flat loop, so the differences that matter to users live in the other seven layers.
Layer 1: the loop, and why it got simpler
The first generation of coding agents built elaborate state machines: a planning phase, an implementation phase, a verification phase, an intent classifier that routed a request into one of them. Nearly all of that has been dismantled. The 2026 consensus design is a flat loop — send the full conversation and the full tool catalogue to the model, execute whatever it calls, return the results verbatim including real error text, and repeat until the model stops calling tools and answers in prose.
The change matters because of who decides the turn is finished. In a phase machine, the engine decides; it can insist on a plan that the task did not need, or declare success because a verification step passed while the actual bug remains. In a flat loop the model ends the turn, and the engine’s job narrows to enforcement: bounding runaway behaviour and making every action pass through one gate. Kendr Code documents this explicitly — its earlier phase machine, subagent runtime, and task-graph compiler were removed in a single refactor in August 2026, leaving one flat loop for its Agent, Ask, and Plan modes, where Ask and Plan are a read-only tool filter plus a short mode contract rather than separate engines.[1]
What remains in the loop layer is runaway protection, and good implementations keep it deliberately light: a step budget, a breaker that nudges then stops on identical repeated calls, a cap on identical repeated failures, and a bound on provider-rejected attempts. Heavy-handed loop policing is how agents end up refusing to finish work a human would have finished.
- Ask whether modes are separate engines or a tool filter over one loop. Separate engines drift apart and develop different safety gaps.
- Ask what ends a turn. If the engine can declare success, ask on what evidence.
- Ask whether tool errors reach the model verbatim. Sanitised errors are the most common cause of an agent looping on the same broken call.
Layer 2: the edit engine is where repositories get corrupted
There are three generations of edit engine in production today. The first asks the model to emit a whole file and writes it — simple, and catastrophic on large files. The second asks for a search-and-replace or unified diff and applies it with fuzzy matching — the dominant design, and the source of most silent corruption, because a fuzzy match against a file that changed since the model read it can apply a patch in the wrong place. The third preconditions every write on a content hash captured at read time and refuses to apply if the file moved underneath it.
Above the write primitive sits transactionality. A refactor that touches nine files is one logical change; if it fails on the seventh, the repository should not be left in a state where two thirds of a rename has been applied. The strong designs run multi-file edits as checkpointed transactions with per-file atomic replacement and compensating rollback, and record content-addressed blobs so undo and redo are exact rather than approximate. It is worth being precise about what this does not give you: a rollback-journalled transaction is recoverable, but it is not an operating-system-wide atomic commit, so another process can briefly observe an intermediate file set. Harnesses that claim otherwise are overselling.
The edit engine is also where honest harnesses distinguish typed tools from shell strings. A typed patch call can be inspected, diffed, checkpointed, approved, and rolled back. The same edit expressed as a heredoc piped into a stream editor can only be approved or refused as an opaque string.
Layer 3: context assembly, retrieval, and compaction
Two schools are in open competition. Agentic search gives the model grep, glob, and ranged file reads and lets it navigate; it is transparent, needs no index, stays correct as the repository changes, and costs a lot of tokens. Indexed retrieval builds a semantic or structural map ahead of time; it is far cheaper per query and far better on large monorepos, but it can go stale and it moves part of the reasoning out of the model’s view. The IDE-native products lean indexed; most terminal harnesses lean agentic. Aider’s tree-sitter repository map is the well-known middle path — a structural summary of symbols rather than either raw files or opaque embeddings.[2]
Compaction is the layer nobody demos and everybody feels. A long task will exceed the context window; the question is whether the harness notices before the provider does. Step-count triggers alone are not enough, because one tool call returning a large build log can blow the budget in a single step. The better implementations trigger on estimated request size — for example at 70 percent of the model’s known context window — and treat a provider-signalled overflow as a compact-and-retry rather than a failed turn. Bounding tool output head-and-tail rather than truncating the tail matters more than it sounds: the error message is almost always at the end.[1]
Above compaction sits memory. The useful distinction is between instruction files that you write — AGENTS.md, CLAUDE.md, and their hierarchical resolution — and memory the agent writes for itself across sessions. Both are now common; the second is the one to inspect, because an agent that silently accumulates wrong conclusions about your codebase will keep acting on them.
Layers 4 and 5: the sandbox and the permission gate are different things
These two are constantly conflated in marketing and they solve different problems. The sandbox bounds what a running process can reach — filesystem scope, network egress, syscalls. The permission gate decides which proposed actions run at all. A harness can have a strict gate and no sandbox, in which case an approved command can do anything; or a strong sandbox and a weak gate, in which case it will happily do the wrong thing inside a safe box.
Real sandboxing is an operating-system feature. Codex uses Seatbelt on macOS, Landlock with seccomp on Linux, and a native Windows sandbox, with network off by default.[3] Container-backed designs get isolation from the container runtime instead, which is more portable and more expensive to start. The pattern to distrust is a string blocklist over shell commands: it stops the example in the README and nothing that has been thought about for five minutes.
The permission gate is where the most consequential engineering happens and where the field is least mature. A serious gate is granular per action, records the exact proposed arguments durably so a pending approval survives a process kill, resolves each decision as a single conditional state transition so two clients cannot both decide it, returns rejection feedback to the model as text rather than failing the turn, and applies identically to actions proposed by delegated subagents. If a subagent can bypass the gate, the gate does not exist.
- Sandbox question: which kernel mechanism, on which operating system, and what is the posture on the platform you actually run?
- Gate question: what happens to a pending approval if the process is killed while you are away from the keyboard?
- Delegation question: do subagent tool calls pass through the same gate as the parent turn?
- Reuse question: can an approval mint a scoped standing rule, and can you list and revoke those rules later?
Layer 6: durability, or what the system believes after a crash
Most harnesses persist a transcript. That is a convenience feature. Durability in the engineering sense means the record of invocations is the authoritative state of the system, so that after a crash the harness can answer: which turn was running, who owned the workspace, which actions were proposed but never decided, and which file changes were half-applied.
The mechanisms are unglamorous and borrowed from distributed systems. A single-writer lease with a heartbeat, so two runtimes cannot mutate one workspace. An idempotent turn start claimed atomically in the database, so a desktop app and a command-line client sharing state cannot both start the same turn. Restart reconciliation that replays pending approvals oldest-first. A hash-chained ledger recording the objective, the repository baseline, and the pre-existing state of every path the task touched, so a claim of completion can be checked against what was actually true when the task began.
This layer is invisible until the day it is the only thing that matters, which is precisely why so few harnesses invest in it. It is also the prerequisite for unattended operation: an agent you leave running overnight is only as trustworthy as its ability to tell you, the next morning, exactly what it did and what it was in the middle of.
Layers 7 and 8: the model adapter and the extension surface
The model adapter normalises providers, and the honest ones declare capabilities explicitly rather than assuming parity. Provider support is not binary. A harness can speak six providers while only streaming from two, or offer native tool-calling on one and fall back to a constrained JSON protocol elsewhere. That unevenness is invisible in a feature table and extremely visible in daily use, where it shows up as a turn that appears to hang or a model that silently does nothing. Ask for the capability matrix, not the provider count.
The extension surface has standardised faster than anything else in this stack. MCP is now the common tool-connection protocol across Claude Code, Codex, OpenCode, Copilot, VS Code, and most independent harnesses, and GitHub retired its proprietary extension mechanism in favour of it. The Agent Client Protocol has done something similar on the editor side, letting one agent drive multiple editors.[4] Skills, hooks, plugins, and subagent catalogues are converging on the shapes Claude Code established.[5] For a buyer this is good news: extension investment is increasingly portable, and a harness that cannot consume MCP servers is now choosing to be isolated.
ACP carries one design trap worth flagging, because implementing it badly can undo work in the layers below. The protocol offers file-read, file-write, and terminal methods that let the editor perform the operation on the agent’s behalf. Taking them is tempting and usually wrong: routing edits through the editor creates a second, non-transactional write path that bypasses your own checkpointing, and routing commands there bypasses the sandbox. The same applies to permission prompts — an ACP client asking the user to approve a tool call must resolve that answer through the engine’s existing approval transition, not decide it locally, or two clients can reach different conclusions about the same action. A harness that adds an editor integration and quietly loses its edit and approval guarantees has traded a 10 for a 7 in exchange for a checkbox.
How to evaluate a harness in thirty minutes
Run one destructive-adjacent task with approvals on and watch which layer answers. Ask it to rename a symbol across a dozen files, then kill the process mid-turn and restart. What comes back tells you almost everything: whether the edit was transactional, whether the approval survived, whether the harness knows which files it had already touched, and whether it can distinguish its own changes from yours.
Then read two files in the source, if the source is open: the tool policy and the approval path. The tool policy tells you whether the surface is deny-by-default and typed or an allowlist over shell. The approval path tells you whether decisions are transactional. Those two files predict more about how the product behaves in month three than any benchmark table.
Frequently asked questions
What is the difference between an agent and a harness?
The agent is the model deciding what to do next. The harness is everything else: the loop that calls the model, the tools it can call, the gate that approves them, the sandbox that bounds them, and the log that records them. Swapping models changes capability; swapping harnesses changes safety and recoverability.
Why did coding agents drop multi-phase state machines?
Because the engine was making decisions the model was better placed to make. Phase machines forced plans on tasks that did not need them and declared success on engine-defined criteria rather than actual outcomes. The flat loop hands turn-completion back to the model and narrows the engine to enforcement.
Is indexed retrieval better than agentic search?
Neither dominates. Indexed retrieval is much cheaper and stronger on large monorepos but can go stale; agentic search is transparent and always current but token-expensive. Structural approaches such as a tree-sitter repository map sit between the two.
What does durability mean for a coding agent?
That the invocation record is the authoritative state, not a convenience transcript. Concretely: single-writer leases, idempotent turn starts, pending approvals that survive a process kill, restart reconciliation, and a replayable ledger of what the repository looked like before the task began.
Sources and evidence
Primary and authoritative sources used for factual claims. Company research and executive forecasts are labeled as such in the article.
- 1
- 2Aider repository mapAider
- 3
- 4Agent Client ProtocolAgent Client Protocol
- 5Claude Code overviewAnthropic