How Modern Coding Agents Are Really Built
Source: Vanishing Gradients, Nicolay Gerold of Amp / Sourcegraph with Hugo Bowne-Anderson, YouTube ID IPJ7Mp_ajuQ
The modern coding agent is not a mysterious autonomous creature. It is a context machine: a loop, a conversation array, a handful of tools, and a harness whose real job is to keep the model looking at the right blob of text at the right moment.
That simplicity is easy to underestimate. Nicolay Gerold’s core argument is that the frontier has shifted away from elaborate agent architecture and toward harness engineering: the practical craft of shaping context, tools, feedback, cancellation, permissions, compaction, and delegation so a model can keep making good decisions while working inside a real codebase.
Who Is Nicolay Gerold?
Nicolay Gerold is a software engineer at Sourcegraph working on Amp Code, one of the more interesting modern coding-agent harnesses. He is also the founder of Icebark, and his perspective is unusually grounded because he is not only theorizing about agent loops; he is building the product surface, tool layer, and production details that determine whether agents survive contact with real repositories.
Hugo Bowne-Anderson frames the session as a hands-on tour through the parts of coding agents that still matter in 2026: the core loop, context engineering, compaction, handoff, sub-agents, tool design, recursive language models, and the increasingly provocative claim that bash may be enough for many frontier models.
The Agent Is the Context You Give It
Gerold’s starting point is brutally clarifying: an LLM sees only a blob of text. Tool calls, assistant messages, user messages, system instructions, XML-ish tags, JSON payloads, and chat templates are all ultimately serialized into tokens. The model’s behavior follows from that input.
“The entire behavior is determined by the input — by the context that you have in the context window right now.”
This turns coding-agent design into a quality-control problem over context. The goal is not to bolt on more orchestration for its own sake. The goal is to maintain a high-signal context window as the agent explores a repo, executes commands, sees failures, patches files, and continues over many turns.
Gerold describes harness engineering as context engineering for both the user and the agent. The harness gives the user ways to provide intent, files, plans, skills, and repo guidance. It gives the model tools for pulling in additional evidence. It gives the environment ways to push back through tests, lint output, command failures, type errors, runtime logs, and other feedback. A good harness maximizes signal while minimizing noise, knowing that it can never remove noise entirely because exploration is part of the job.
The Core Loop Is Almost Embarrassingly Small
The core of a coding agent is not complicated. Gerold points to Thorsten Ball’s “How to Build an Agent” essay as the canonical demystifier: an agent is essentially an LLM loop, an array of conversation messages, and tool execution.
At each turn, the harness sends the conversation back to the model. The chat template converts structured messages into a token stream with enough semantics for the model to know what is a system instruction, what is a user request, what is a tool result, and what should become a tool call. The model emits more structured text, the harness parses it into tool calls, executes those calls, appends the results, and repeats.
The production version adds features that sound mundane but matter enormously: persisted sessions, streaming responses, provider-specific streaming parsers, cancellation wiring, local JSONL logs, and tool-result formatting. Pi, the minimal coding agent Gerold discusses, is valuable precisely because it keeps the production loop readable. It shows that the magic is not a giant hidden framework. The hard part is making the small loop robust.
Tools Shape Model Behavior More Than People Think
Most frontier models can call arbitrary tools, but Gerold emphasizes that they are not neutral tool users. They carry biases from the harnesses and tool schemas used during training. An OpenAI model, an Anthropic model, and another frontier model may all be able to call a shell tool, but they will not use the same toolset with the same frequency or taste.
That is why a harness cannot simply be ported from one model provider to another. The tool surface has to be tuned to the model. Gerold gives a concrete example: when a model is given a shell-command tool shaped like another provider’s bash tool, it may call it less often and delegate more work to sub-agents instead. The question is not merely “Can the model call this?” It is “Will this model naturally use this tool well, often enough, and in the right situations?”
Read Tool vs. Bash
The old coding-agent stack often included separate tools for reading files, creating files, editing files, and running shell commands. Gerold argues that with stronger frontier models, the dedicated read tool is often no longer necessary. Bash is composable, familiar, and already deeply represented in training data. A model can use shell commands to inspect files, filter output, search selectively, and avoid dumping huge files into context.
The reason this matters is context efficiency. Earlier read tools often had to add line ranges, maximum-file guards, and failure messages because models would read too much and blow up the context window. Bash gives the model a more flexible interface for narrowing what it sees. That same flexibility is also why weaker models or cheaper modes may still need a safer read abstraction: the harness should match the model’s capability and risk profile.
EditFile vs. Apply Patch
The edit surface creates similar trade-offs. A simple edit_file tool can be just a path, an old string, a new string, and a replace-all flag. It is easy to understand, easy for the model to use, and easy for the harness to validate. Claude Code’s string-replacement style succeeded partly because the model could repeat content it had seen, generate the new version, and let the harness perform a constrained replacement.
apply_patch is more powerful and more parallel, but it is also more complex. The model must generate hunks correctly, associate them with files, and stay within the patch format. Some models are excellent at this; others go off-distribution. The practical lesson is not that one tool is universally better. The lesson is that tool shape changes behavior. The best tool is the one your target model can use reliably under pressure.
Permissions, Hooks, and the Approve-Button Trap
Hooks are one of the major power centers in a production harness. They can steer behavior, implement permissions, intercept tool calls, and add custom automation. A before-tool-call hook, for example, can ask the user to approve an edit before it lands.
Gerold is skeptical of the default value of constant approvals. He says he now often runs with broad permissions because, in practice, many users hit approve every time without really reading the code. At that point the approval loop mostly slows the agent down while creating the illusion of control.
The deeper product question is where human attention is actually useful. If users are not going to inspect each action, a harness should invest more in reversible operations, good diffs, test feedback, safe sandboxes, clear logs, and post-run review. The approve button should not become a ritual that transfers responsibility back to the user without improving outcomes.
Cancellation Is a Production Feature, Not a Detail
Cancellation sounds boring until an agent is running commands, streaming an inference call, launching sub-agents, and possibly leaving background processes alive. Gerold calls it surprisingly annoying because cancellation has to be wired through the whole system.
If a user cancels a turn, the harness may need to stop the current model call, kill a running shell process, decide what happens to async sub-agents, clean up tmux sessions, and prevent orphaned work from confusing later turns. Bad cancellation creates memory leaks, runaway processes, stale state, and user mistrust. In a real coding agent, cancellation is part of the safety model.
AGENTS.md Should Be a Map, Not a Manual
Gerold’s view of repo guidance is refreshingly restrained. The root AGENTS.md file should give the model a map: how to run tests, start the dev server, invoke the linter, find deeper documentation, and load relevant skills. It should not be a thousand-page instruction manual.
The reason is cost. Root guidance is often included in every conversation. Every unnecessary paragraph permanently taxes the context window. Better systems split guidance across directories: server, CLI, web, and other subtrees can each have their own localized instructions. The root file points the model toward the right places instead of front-loading every detail.
This is a general principle for agent design: keep always-on context short, navigational, and durable. Put situational knowledge behind references the model can load when needed.
Sub-Agents Keep the Main Context Clean
Sub-agents are useful because they isolate exploration. A codebase-search sub-agent can grep, read, and inspect widely, then return the relevant files and a concise synthesis to the main agent. The main agent gets a cleaner context window and can make more targeted tool calls instead of carrying every failed search path and intermediate output.
Gerold connects this to advisor patterns as well. A planning agent or review agent can inspect the codebase and advise without polluting the primary thread. The main model can then accept, reject, or refine that advice. This is especially valuable as stronger models become better at delegating and better at not blindly accepting subordinate outputs.
The important nuance is that sub-agents are not magic. They are a context-management technique. Their job is to compress search and reasoning into a useful artifact that the main agent can trust enough to act on, but still evaluate critically.
Plan Mode Is Dying, but Planning Is Not
Gerold’s take on plan mode is blunt: separate planning modes are becoming less necessary because models have learned to follow a simple instruction like “plan, but do not edit.” Earlier models needed UX scaffolding. Newer models often do not.
That does not mean planning has disappeared. It means planning is becoming an instruction rather than a mode. In fact, models often plan internally and sometimes over-plan externally. Gerold notes that generated plans can become so large that nobody reads them; at that point it may be more useful to let the model implement, review the diff, give feedback, revert, and retry with better task instructions.
The broader rule is to revisit every harness feature as models improve. A feature that compensated for a model weakness last year may become unnecessary, or even harmful, once the model can do the behavior directly.
Compaction, Handoff, and the Usable Context Window
Compaction exists because conversation arrays grow forever. Advertised context windows are not the same as usable context windows; models may accept enormous inputs while degrading in attention or tool use long before the theoretical limit. Gerold mentions seeing degradation at hundreds of thousands of tokens even when the nominal window is much larger.
The first answer was summarization: when the window fills, ask the model to summarize the prior conversation, delete the old messages, and continue. That helped with size but introduced loss. Important facts could be omitted, distorted, or stripped of the evidence needed for later decisions.
Handoff emerged as a more structured response: preserve enough state to continue in a fresh thread. But as compaction improves, some handoff machinery becomes less necessary. The pattern mirrors plan mode: agent features should be judged against current model capability, not kept as permanent architecture because they once solved a hard problem.
Recursive Language Models Turn Code Into the Interface
Gerold describes recursive language models in simpler terms than the name suggests: give the model code execution capabilities, a REPL, or a Jupyter-like environment, and expose its tools as functions. Instead of forcing every operation through direct tool calls that immediately spill results into context, the model can assign outputs to variables, process them, filter them, and print only what matters.
This is another version of the bash argument. Code is composable. A model that can operate through code can control its own context more efficiently, combining tool outputs, extracting relevant sections, and avoiding needless token floods. The interface becomes less about a menu of isolated tools and more about giving the agent a programmable runtime.
The Best Way to Build Coding Agents Is With Coding Agents
The most recursive practical advice is also the most important: use coding agents to build coding agents. Gerold argues that harness engineering is fundamentally tinkering. The feedback loop gets stronger when the tool can modify itself, improve its own extension API, and help the builder try more ideas.
That power has a downside. Agents make it easy to generate a lot of code, and that invites feature slop. Gerold’s counterpoint is to use the extra throughput for quality, not indiscriminate expansion: run 20 iterations, polish harder, refine interfaces, and raise the bar for what lands in the codebase.
As models improve, harnesses should be re-tuned. Gerold says he asks more of stronger models: better engineering taste, deeper interfaces with narrow surfaces, closer adherence to existing code style, and more effective delegation. The question for each model generation is: what can the harness now demand that was barely possible before?
Practical Framework: What Still Matters in a Coding-Agent Harness
| Harness area | What to optimize for | Failure mode to avoid |
|---|---|---|
| System and repo instructions | Short, navigational, durable context | Always-on manuals that consume context and go stale |
| Tool design | Tool shapes the target model naturally uses well | Porting another provider’s harness without retuning |
| Shell access | Composable inspection, filtering, and execution | Overly narrow tools that force noisy context dumps |
| Edit tools | Reliability under model distribution and validation | Powerful patch formats the model cannot consistently emit |
| Sub-agents | Isolated exploration and concise synthesis | Delegation without critical review by the main agent |
| Compaction | Preserve decision-relevant state and evidence | Summaries that lose constraints, files, or rationale |
| Cancellation | Abort model calls, processes, and async work cleanly | Orphaned commands, stale background agents, and user confusion |
| Permissions | Real safety, reversibility, and reviewability | Approve-button theater that users rubber-stamp |
Key Lessons
- Start from the loop. A coding agent is an LLM loop over a conversation array plus tool execution. Production complexity surrounds the loop; it does not replace it.
- Treat context as the product surface. Instructions, tool results, environmental feedback, and sub-agent summaries are all competing for the model’s attention.
- Tune tools to models. Frontier models have learned different harnesses and carry different tool-use biases. The same tool schema can produce different behavior.
- Prefer composability when the model can handle it. Bash, code execution, and RLM-style interfaces let capable models filter and transform context before exposing it.
- Delete obsolete scaffolding. Plan mode, read tools, handoff systems, and permission flows should be revisited as models get smarter.
- Invest in production edges. Cancellation, streaming, persistence, compaction, hooks, and review flows are what turn a demo loop into a useful product.
Why This Matters for Diffie
For Anand and Diffie, the most relevant lesson is that agent quality will be judged less by whether the model can “use tools” and more by whether the harness creates a high-signal feedback loop around the browser, DOM, network, console, screenshots, test assertions, and developer intent.
Diffie’s ICP — frontend engineers who need AI browser testing — does not just need another autonomous loop. They need an agent that knows how to gather the right evidence from a web app, avoid drowning itself in noisy logs, recover from flaky UI states, and return artifacts a human engineer trusts. Gerold’s framing suggests a concrete product thesis: Diffie should be a context-engineering layer for frontend verification.
That points to several sharp product moves:
- Make browser feedback first-class. Treat screenshots, DOM snapshots, console errors, network failures, route changes, and assertion diffs as carefully shaped context, not raw dumps.
- Design tool schemas for the model you actually use. If OpenAI Codex is primary, tune Diffie’s browser, inspection, and patch tools to the behaviors Codex naturally performs well rather than copying another harness.
- Use sub-agents for noisy exploration. A visual-regression scout, console-log investigator, or route-discovery worker can summarize findings without polluting the main debugging thread.
- Replace permission theater with reviewable evidence. Frontend engineers will trust Diffie more if every proposed fix is backed by a before/after screenshot, failing/passing test, and concise diff than if they are asked to approve every tiny action.
- Keep repo guidance navigational. Diffie should help teams write short AGENTS.md-style maps for running dev servers, fixture data, auth flows, and test commands, then load deeper instructions only when needed.
The GTM implication is equally important. “AI browser testing” is broad; “the harness that gives coding agents reliable frontend feedback” is sharper. It speaks directly to the moment Gerold describes: models are getting stronger, so the enduring value shifts to context, feedback, tool shape, and production reliability. Diffie can own that wedge for frontend teams.