This is part 3 of a multi-part deep dive into LLM/AI-based coding assistants. Part 1 covers SWE-Bench and Part 2 covers Terminal-Bench, the most influential benchmarks for evaluating coding assistants.
This post will describe the core components of a coding agent and give a step-by-step, granular illustration of the tool calling loop for a real open-source coding agent, Opencode.
The Basics
First, let’s define a “Coding Agent” as a system that combines an LLM with tool calling in a loop to read and write code. Some popular examples:
- Claude Code
- OpenAI Codex
- Cursor
- Windsurf
- Opencode
A coding agent has two independent components: the model and the scaffold.
- **The M…
This is part 3 of a multi-part deep dive into LLM/AI-based coding assistants. Part 1 covers SWE-Bench and Part 2 covers Terminal-Bench, the most influential benchmarks for evaluating coding assistants.
This post will describe the core components of a coding agent and give a step-by-step, granular illustration of the tool calling loop for a real open-source coding agent, Opencode.
The Basics
First, let’s define a “Coding Agent” as a system that combines an LLM with tool calling in a loop to read and write code. Some popular examples:
- Claude Code
- OpenAI Codex
- Cursor
- Windsurf
- Opencode
A coding agent has two independent components: the model and the scaffold.
- The Model: The underlying LLM (e.g.
gpt-5.2,claude-4.5-opus, etc.) - The Scaffold: The set of tools that the LLM has access to, and the system prompt(s) that are input to the LLM.
Note that these definitions can apply to any agentic system, not necessarily a coding agent. For coding agents, the set of tools and the system prompts are tuned for coding tasks.
The scaffold is the unique component of a coding agent. That is where we will focus our attention. Later we will look at a real example scaffold for a production-grade coding agent (Opencode), and see how it is used. First, I want to spend some time understanding how LLM tool calling works, since this is a critical component of the coding agent scaffold.
The Tool Calling Loop: Step-by-Step
Tool calling is a topic that is easily obfuscated but is actually simple when you see an example. A tool is just a function that can be executed by the LLM, typically in your local environment. The tool calling interface operates over HTTP transactions between a local orchestrator process and the LLM running remotely. In the case of coding agents, the orchestrator is part of the agent.
Let’s define an example tool, use it in the OpenAI responses API, and trace how it works at the HTTP layer step-by-step. Consider a bash tool that allows the model to execute shell commands in your local environment. Here is what a potential JSON interface to this tool could look like:
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| command | string | required | The shell command to execute |
Description
Now let’s trace through a complete example. Suppose the user asks the model “How many TypeScript files are in the src directory?”. Here’s the complete HTTP flow between your application and the OpenAI API:
Developer
Model
1
2
3
4
5
In summary, tool calling is just a response of type function_call. When the orchestrator receives a function call response, it executes the function locally with the parameters provided by the model, and feeds the result back.
This loop is the core of any coding agent: the model requests tools, the application executes them, and the results are fed back. Frontier models have been trained to execute these tool calls precisely and reliably.
Now that you understand the basic tool calling loop, all that’s left is to understand the tools and system prompt that make up a production coding agent. That is what we’ll focus on next.
An Example Scaffold: Opencode
Opencode is an open-source TUI-based coding assistant, a popular alternative to closed-source agents like Claude Code and Codex. Here is an example subset of the core tools available to models running in the Opencode scaffold:
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| command | string | required | The command to execute |
| timeout | number | optional | Timeout in milliseconds (max 600000) |
| workdir | string | optional | Working directory for command execution |
| description | string | required | 5-10 word description of what the command does |
Description
(bash.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file |
| offset | number | optional | 0-based line offset to start reading from |
| limit | number | optional | Number of lines to read |
Description
(read.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file to modify |
| oldString | string | required | The text to replace (must match exactly) |
| newString | string | required | The replacement text |
| replaceAll | boolean | optional | Replace all occurrences (default: false) |
Description
(edit.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file to write |
| content | string | required | The content to write |
Description
(write.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | string | optional | Absolute path to list (defaults to workspace) |
| ignore | string[] | optional | Glob patterns to ignore |
Description
(ls.txt)
As you can see, these tools are very simple and very flexible. We are just giving the model the minimum set of tools that it needs to be able to explore your filesystem, read files, and write files in your local environment.
This set of core tools gets you to 99% of the functionality of any current coding agent. There are a variety of more special-purpose tools integrated into Opencode and other agents that are also helpful, but they are not critical for core coding agent tasks. See the appendix for a full breakdown of Opencode tools.
Below is an interactive view of the complete API request that Opencode sends to the model alongside the user’s first message. This example assumes an empty directory with no custom configuration. Click on any tool or system prompt section to expand it.
So, before the first user message, the model sees a system prompt and a description of the tools available to it. This is precisely a description of the scaffold available to the model.
From here the Opencode scaffold is just responsible for receiving the tool calls from the model, executing them and providing the results back. Here is an illustrated example of what this looks like:
Developer
Model
1
2
3
4
5
6
7
8
And that’s it! In the next installment of the series we will use our knowledge to build our own fully-featured coding agent.
Appendix: Complete Tools Reference
Below is the complete list of all tools available in Opencode, organized by category.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| command | string | required | The command to execute |
| timeout | number | optional | Timeout in milliseconds (max 600000) |
| workdir | string | optional | Working directory for command execution |
| description | string | required | 5-10 word description of what the command does |
Description
(bash.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file |
| offset | number | optional | 0-based line offset to start reading from |
| limit | number | optional | Number of lines to read |
Description
(read.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file to modify |
| oldString | string | required | The text to replace (must match exactly) |
| newString | string | required | The replacement text |
| replaceAll | boolean | optional | Replace all occurrences (default: false) |
Description
(edit.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| filePath | string | required | Absolute path to the file to write |
| content | string | required | The content to write |
Description
(write.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | string | optional | Absolute path to list (defaults to workspace) |
| ignore | string[] | optional | Glob patterns to ignore |
Description
(ls.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| pattern | string | required | Glob pattern to match (e.g. **/*.ts) |
| path | string | optional | Directory to search in |
Description
(glob.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| pattern | string | required | Regex pattern to search for |
| path | string | optional | File or directory to search in |
| include | string | optional | Glob filter (e.g. *.ts) |
Description
(grep.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | string | required | URL to fetch |
| format | "text" | "markdown" | "html" | required | Output format |
| timeout | number | optional | Timeout in seconds |
Description
(webfetch.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | required | Search query |
| numResults | number | optional | Number of results to return |
| livecrawl | "fallback" | "preferred" | optional | Live crawling mode |
| type | "auto" | "fast" | "deep" | optional | Search type |
| contextMaxCharacters | number | optional | Max context length |
Description
(websearch.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | required | Programming-related search query |
| tokensNum | number | optional | Token count (1000-50000, default 5000) |
Description
(codesearch.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| description | string | required | Short description of the task |
| prompt | string | required | Detailed task instructions |
| subagent_type | string | required | Type of agent to spawn |
| session_id | string | optional | Session ID for stateful agents |
| command | string | optional | Slash command to execute |
Description
(task.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| todos | Todo[] | required | Array of todo items with id, content, status, priority |
Description
(todowrite.txt)
Parameters
No parameters
Description
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| operation | string | required | LSP operation (goToDefinition, findReferences, hover, etc.) |
| filePath | string | required | File to operate on |
| line | number | required | Line number (1-based) |
| character | number | required | Character offset (1-based) |
Description
(lsp.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| tool_calls | ToolCall[] | required | Array of tool calls (max 10) |
Description
(batch.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| tool | string | required | The tool that was called incorrectly |
| error | string | required | The error message |
Description
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| file_path | string | required | Absolute path to the file |
| edits | Edit[] | required | Array of edit operations |
Description
(multiedit.txt)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| patchText | string | required | The patch content in standard format |