· 6 min read ·

The Tool Loop at the Heart of Every Coding Agent

Source: simonwillison

Simon Willison has been publishing a series of agentic engineering patterns that cuts through a lot of the marketing fog around AI coding tools. The piece on how coding agents work is worth reading carefully, because the architecture is simple enough that you can hold it entirely in your head, and once you do, a lot of previously mysterious behavior becomes obvious.

Here is the short version: a coding agent is an LLM that has been given a set of tools, placed inside a loop, and told to keep running until the task is done. Every tool call and every result gets appended to the context window. The model reads all of that accumulated context on each iteration and decides what to do next. That is the entire mechanism. Everything else, orientation heuristics, multi-agent delegation, context compaction, is layered on top of that core loop.

What the Loop Actually Looks Like

At the wire level, a tool call is just structured JSON in the model’s response stream. When the model decides to read a file, it emits something like:

{
  "type": "tool_use",
  "name": "read_file",
  "input": {
    "path": "src/server.ts"
  }
}

The agent runtime intercepts that, executes the actual filesystem read, and appends a tool_result block to the conversation. The model then receives a new turn with the file contents visible, and continues. The loop repeats until the model emits no more tool calls and produces a final response, or until some external timeout or budget limit fires.

This maps closely to how a REPL session works. A developer typing into a shell also accumulates state incrementally: run a command, observe output, run the next command informed by what you saw. The difference is that in a shell session, state lives in the process environment and the filesystem. In an agent loop, state lives almost entirely in the context window, which is both its greatest strength and its central architectural constraint.

The Context Window as Process State

Every tool result, every file read, every error message, every bash output gets appended to the same growing context. This means the agent has perfect recall of everything it has observed during the current session. It also means the context window is constantly filling up, and when it fills, something has to give.

Different agents handle this differently. Claude Code compacts older portions of the conversation when the window gets full, preserving a summary rather than the raw transcript. Cursor and similar tools use retrieval-augmented approaches, pulling relevant chunks of code on demand rather than loading entire files eagerly. The Anthropic documentation on tool use does not prescribe a particular strategy here, which is why every major coding agent has ended up with a slightly different memory management approach.

The practical consequence for anyone building tooling around these agents: large tool outputs are expensive. If your tool returns 10,000 tokens of JSON when 200 tokens of structured data would do, you are burning context budget that the model could have used to track its own reasoning. Tool output design is a first-class architectural concern, not an afterthought.

Orientation Before Action

A well-designed coding agent does not start editing files immediately. Before touching anything, it explores. It reads directory structures, searches for relevant classes and functions, checks configuration files, and builds up a mental model of the codebase. This orientation phase is not a quirk of any particular agent; it falls out naturally from the tool loop architecture.

The model knows it will need context to make good edits. It also knows that every file read consumes context window space. So it is constantly making implicit cost-benefit decisions: is it worth reading this entire file, or should I search for the specific function I need first? Tools like grep and glob are especially valuable here because they let the agent retrieve targeted information without loading entire files.

This is where Simon’s framing of coding agents as fundamentally oriented systems becomes useful. The agent is not a chatbot that happens to also edit files. It is a system that spends significant effort understanding where it is before deciding what to do. CLAUDE.md files and similar project-level context documents exist precisely to short-circuit that orientation work, giving the model facts about the codebase that would otherwise require many tool calls to discover.

Tool Design Is API Design

Because the agent is making decisions about which tools to call based on their descriptions, tool descriptions are effectively a programming interface. A tool described as “reads a file” will get called differently than one described as “reads a file, returns line numbers, handles encoding errors gracefully.” The model infers calling conventions from those descriptions.

This has direct implications for anyone building custom tools for an agent. Vague descriptions produce unreliable behavior. Overly broad tools that do many things produce unpredictable calls. The principle of least surprise applies: tools should do one thing, do it predictably, and describe that thing accurately.

Error handling is particularly important. If a tool fails and returns an unstructured error string, the model has to guess what went wrong and how to recover. If a tool returns a structured error with a reason code and a suggested fix, the model can act on that information directly. The agent is reading tool output the same way it reads human text, which means tool output quality directly affects agent decision quality.

Failure Modes That Fall Out of the Architecture

Once you understand the loop, the failure modes become predictable.

Context overflow. The agent runs out of context budget partway through a large task. It may lose track of earlier decisions or repeat work it already did. Mitigation: break large tasks into smaller sessions, use CLAUDE.md to persist project knowledge across sessions.

Tool call spirals. The model gets stuck in a pattern of calling the same tool repeatedly with slightly different parameters, not finding what it needs, and trying again. This is the agent equivalent of a grep-and-scroll loop in a terminal. Mitigation: set iteration limits, design tools that surface “not found” clearly rather than returning empty results.

Observation lag. The agent makes an edit, does not verify the result, and proceeds on the assumption that the edit worked. If the edit produced a syntax error, downstream tool calls start failing in confusing ways. Good agents explicitly verify their changes by reading back what they wrote or running a build step after edits.

Prompt injection in tool output. Because the model treats tool output as trusted context, a malicious string inside a fetched webpage or a file could attempt to redirect the agent’s behavior. This is a real attack surface, not a theoretical one. The OWASP guidance on LLM security covers prompt injection as a top risk, and it applies directly to any agent that reads external content.

Multi-Agent Extensions

The single-agent loop scales poorly to tasks that require working on multiple independent subtasks simultaneously. The natural extension is to make tool calls that themselves spawn agent loops. An orchestrator agent identifies parallel work, calls a “run subagent” tool for each subtask, and collects the results.

This is structurally identical to how a process spawns child processes. Each subagent gets its own context window, its own tool budget, and its own task scope. Results flow back to the orchestrator as tool outputs. The architectural challenges are familiar to anyone who has written concurrent code: how do you merge results that may conflict, what happens when a subtask fails, and how do you avoid overwhelming the orchestrator’s context with large subagent outputs.

Frameworks like LangGraph and Anthropic’s own agent SDK provide primitives for wiring these patterns together, but the underlying model is the same loop, just nested.

What This Means in Practice

Building well with coding agents means understanding the tool loop well enough to work with it rather than against it. Keep tool outputs small and structured. Provide orientation context upfront. Design tasks to fit within context budgets. Treat tool descriptions as API contracts.

The abstraction is leaky in interesting ways. The context window is simultaneously the agent’s memory, its process state, and its communication channel with you. When something goes wrong, reading the agent’s trace is often the most direct path to understanding why, the same way reading a shell history tells you what a developer was attempting before they gave up.

Simon’s guide is worth revisiting as you build more complex agent workflows. The patterns he describes are not prescriptions so much as descriptions of what falls out naturally from the architecture, once you have enough experience to see it.

Was this interesting?