Code Mode: how agents can save tokens by writing code
The problem
Imagine asking your coding agent:
Look through the issues for our API and dashboard projects. Show me only the open, high-priority ones, grouped by project.
Nothing particularly difficult. Fetch two lists, filter them, and return a summary.
But think about what happens if each tool response goes straight back to the model. The agent receives the API issues. It receives the dashboard issues. Both lists become part of its context, including all the closed issues, low-priority work, descriptions, and metadata you never asked about.
The model then does something code could have done in a few lines: check two fields and keep the matching rows.
For a handful of issues, that's fine. Now imagine thousands of them. Does the model need to read all this data, or does it just need the answer?
That's the useful idea behind Code Mode.
First, let's follow a normal tool call
The agent application gives the model tools with names, descriptions, and input schemas. A tool might read a local file, run a shell command, or search GitHub issues through an MCP server.
For our issue-tracker request, the model might ask for something like this:
{
"name": "list_issues",
"arguments": {
"project": "api"
}
}
The application executes the request and sends the result back. The model reads that result and decides what to do next.
That loop is useful when each result requires a new decision. Read a failing test, work out the cause, inspect the relevant function, then choose a fix.
But for our issue lists, we already know what to do after fetching them. Check whether each issue is open and high priority. Keep its ID and title. Group the matches by project.
Those steps can run in code.
What Cloudflare proposed
Cloudflare introduced its Code Mode approach in this blog post: turn the available tools into a TypeScript API, then let the model write code that calls that API.
Their reasoning was straightforward. Models have seen enormous amounts of real-world code during training. Calling functions, working through arrays, and chaining API requests are familiar patterns. Cloudflare reported that this approach helped its agents handle larger and more complex tool sets.
The part that matters for our example is what happens between calls. A program can take a tool's response, process it, and pass values into another call while it runs. The model can come back in when there's something useful to read or a decision to make.
So the agent writes a small script, the runtime executes it, and the selected output goes back to the model.
The two fetches still happen. The services still return their data. The difference is where that data gets processed.
Let's work through the issue example
Suppose our issue tool is available as listIssues({ project }) and returns an array of records like this:
[
{ "id": "API-12", "title": "Login returns 500", "status": "open", "priority": "high" },
{ "id": "API-13", "title": "Update SDK docs", "status": "open", "priority": "low" },
{ "id": "API-14", "title": "Fix webhook retries", "status": "closed", "priority": "high" }
]
Our dashboard project has a similar list:
[
{ "id": "WEB-21", "title": "Billing page is blank", "status": "open", "priority": "high" },
{ "id": "WEB-22", "title": "Adjust button spacing", "status": "open", "priority": "low" }
]
Here's a simplified script for the workflow. We're using listIssues as our example API; the agent gets the actual tool names and argument formats from its environment.
// Here's what the agent could write to do this.
const projects = ["api", "dashboard"];
const results = await Promise.allSettled(
projects.map(async (project) => {
const issues = await listIssues({ project });
return issues
.filter((issue) =>
issue.status === "open" && issue.priority === "high"
)
.map(({ id, title }) => ({ id, title }));
})
);
return results.map((result, index) =>
result.status === "fulfilled"
? { project: projects[index], issues: result.value }
: { project: projects[index], error: String(result.reason) }
);
Follow what happens here :
First, the script requests both projects' issues. Those requests are independent, so they can run together.
As each list comes back, the script checks status and priority, then keeps just the matching IDs and titles. The closed webhook issue drops out. So does the low-priority documentation work.
Finally, it returns this:
[
{
"project": "api",
"issues": [{ "id": "API-12", "title": "Login returns 500" }]
},
{
"project": "dashboard",
"issues": [{ "id": "WEB-21", "title": "Billing page is blank" }]
}
]
Now the model has exactly what it needs to answer our question. It can tell us that the login error and blank billing page needs attention.
With five issues, you can follow every step. With thousands of issues and long descriptions, the same approach keeps a lot of irrelevant data out of the model's context.
There's also a small choice in that script worth noticing: Promise.allSettled(). If the dashboard request fails, the API results survive alongside an explicit dashboard error. The agent can report what it found and tell us which project it couldn't check.
When connecting this to a real service, we'd also handle its response format, validate the records, and work through any remaining pages.
“Couldn't the tool just filter the issues for us?”
Absolutely. If the issue tool accepts status and priority arguments, use them. Let the service narrow the results before sending them back.
Our first example makes the mechanics easy to follow. Now let's take the request one step further:
Find the open, high-priority issues across both projects. Check whether their assignees are marked out of office today in our team calendar, and flag the issues we should review for reassignment.
Now we're working with two services. The issue tracker knows who owns each issue. The calendar knows who's away. The script brings those answers together.
Here's how the work flows:
- Search both projects using the issue tool's status and priority filters.
- Collect the assignees from the matching issues, keeping each person only once.
- Match those people to their calendar accounts and check today's out-of-office entries.
- Attach that availability to the issues and return the ones whose assignees are away.
Suppose API-12 is assigned to Alice, who's out today, while WEB-21 is assigned to Bob, who's back at work. The agent can return a short answer: “Review API-12 for reassignment; Alice is out of office today.” If a calendar lookup fails, that person's availability stays unknown and the result says so.
The tools do the searching and calendar lookups. Code handles the steps between them: collecting IDs, avoiding duplicate requests, and matching the results. The model then has the information it needs to explain which issues deserve a closer look.
You could build a dedicated tool for this entire workflow too if your team runs this check every morning, that might be a good choice. But codemode is useful when a user asks for something which can only be returned by combining the use of multiple available tools.
“Can't agents already call tools in parallel?”
Yes. Many agents can request several independent calls in the same model turn.
In our expanded example, though, we need the issue results before we know whose calendars to check. Code Mode lets the script carry that information into the next calls, then join the responses before returning to the model.
Each lookup still happens, but the model can skip the mechanical work of reading IDs and copying them into new calls.
You can already see this in coding agents
This approach is now showing up in open-source coding agents such as Pi and OpenCode.
Pi exposes a codemode tool that runs JavaScript, calls other tools, and lets the script filter results before they reach the model. That includes built-in tools such as file reads as well as connected MCP tools.
OpenCode v2 uses Code Mode by default for MCP servers. Its execute tool lets the agent call and combine tools through JavaScript.
As a user, you still ask for an outcome: check these projects, find the relevant issues, summarize what needs attention. The agent can turn the predictable parts of that request into a program.
Where it helps
Code Mode is a good fit when a task combines several tool calls with predictable processing: checking builds across repositories, filtering logs, or joining issue data with calendar availability.
For one small lookup, a direct tool call is usually enough. The savings depend on the workflow and how much data the script keeps out of the model's context; the underlying requests still take time and carry their usual costs.
A few things to watch
- Check before retrying writes. A script can fail after creating an issue or posting a comment. Those actions may already be complete.
- Review tool permissions. The script's reach depends on the tools it can call and what they're allowed to do.
- Keep failures visible. If a source couldn't be checked, say so in the result.
- Treat fetched content as data. Instructions inside an issue description stay part of the issue, rather than becoming directions for the agent.
The mental model to keep
Let the model plan the work and make the judgment calls. Let code handle the predictable reads, filters, and joins. Then bring the useful result back to the conversation.
P.S. If you want to try this yourself, use GPT 6.1 Sol in Pi. That model loves using codemode :)
Sources
- Cloudflare: Code Mode — the approach, its motivation, and Cloudflare's implementation.
- Pi: Codemode — calling tools and processing results through JavaScript.
- OpenCode v2: MCP servers — default Code Mode exposure for MCP tools.
- OpenCode v2: Execute — JavaScript execution for composing tool calls.