Tools become
a program.
Cloudflare’s @cloudflare/codemode lets a model write a small JavaScript program that calls tools. The program handles loops, branches and intermediate data. The model receives the result you choose to return.
npm latest: 0.5.5MITExperimental API
★ The important shift: instead of asking the model to manage every tool call, let it write the control flow once. You still decide which capabilities the program can use.
There is still an agent loop.
New to tool calling? Start here. Otherwise, skip this box.
An LLM produces text. An agent host gives that text consequences: it recognizes a tool request, runs a real function and sends the result back to the model. The function might query GitHub or read a database.
A typical function-call action contains a tool name and JSON arguments. The host checks and dispatches it. The model then sees the observation and chooses what to do next.
MCP standardizes how a client discovers and calls a server’s tools. OpenAPI describes HTTP APIs. Neither requires the model to orchestrate every operation itself.
A sandbox is a restricted execution environment. It runs untrusted code with limited access. Its effectiveness depends on the runtime’s isolation and on what the host exposes through that boundary.
Code Mode changes the action inside the loop. The host exposes a tool with an input like { code: string }. The model puts JavaScript in that string. A sandbox runs it, calls back to approved host capabilities, and returns a result or error. The model can then answer or write another program.
Conventional tool action
getChecks({ number: 17 })
The model plans the next request after seeing this result. Hosts can also support parallel calls and richer orchestration.
Code Mode action
async () => { … }
The program can call getChecks repeatedly, filter the results and return one summary.
This is a change in where orchestration happens. JSON can carry a whole workflow too—if a host implements such a workflow tool. The comparison here is against individual tool calls.
The current package has two layers
| Surface | What it supplies | When to use it |
|---|---|---|
createCodeToolfrom /ai | Tool schemas become a typed prompt; functions become sandbox-callable proxies. One-shot execution. | You already have a small tool set and want code composition. |
createCodemodeRuntimefrom package root | Connector discovery, durable call log, approval/replay, audit and saved snippets. | You need large integrations and execution that can wait for human approval. |
The first is enough to understand the core idea. The second is important to understanding the current package. Do not read an older quick start and assume it describes every feature—or that the simple helper automatically includes the durable runtime.
createCodeTool · tool.ts:89 · runtime handle · runtime-handle.ts:90
What happened to agents/codemode in the screenshot?
The release trail agrees with the screenshot’s Cloudflare dates: agents@0.2.3 was published on 26 September 2025, alongside Codemode #512. The separate @cloudflare/codemode@0.0.1 appeared on 29 December 2025 after the package split #756.
This lesson uses the separate package at 0.5.5, not that old subpath. The mcporter entry in the image names a different project; it is not this package.
Let the program carry the intermediate data.
Suppose you want bug-fix pull requests whose checks pass. Our toy repository has three PRs: #17 “Fix timeout” (bug), #18 “Update docs” (docs), and #19 “Fix retry” (bug). Checks pass for #17 and fail for #19.
async () => {
const prs = await codemode.listPRs({});
const ready = [];
for (const pr of prs) {
if (!pr.labels.includes("bug")) continue;
const check = await codemode.getChecks({ number: pr.number });
if (check.pass) ready.push({ number: pr.number, title: pr.title });
}
return ready;
}
There are still three real tool calls: one list and two check queries. But one model-written action can compose them. The raw list and check objects need not all enter the next model prompt. The program returns [{ number: 17, title: "Fix timeout" }].
Follow the same toy task
A scripted illustration, not a speed benchmark or a live GitHub connection. These are illustrative host/model turns; a parallel tool-calling host can reduce the conventional count.
The saving is in model round trips and exposed intermediate data. It is not a promise of fewer API calls, correct filtering, or lower cost for every task. Printing the full response in a loop can fill the context again. A bad loop can also multiply writes.
ToolDispatcher · executor.ts:230 · proxy + Worker loading · executor.ts:467
★ TypeScript is documentation; JavaScript is the action. The generated declarations help the model learn names and argument shapes. The built-in executors normalize and run JavaScript; they do not compile arbitrary TypeScript annotations.
Follow one action across the boundary.
A. Start with the small, one-shot helper
The developer supplies real functions. createCodeTool generates type declarations, places them in the tool description, and extracts the callable implementations. The model sees the declarations; the executor receives the implementations through host-side dispatch.
import { createCodeTool } from "@cloudflare/codemode/ai";
import { DynamicWorkerExecutor } from "@cloudflare/codemode";
// Host-side: myTools contains your AI SDK tools and execute functions.
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });
const codeTool = createCodeTool({ tools: myTools, executor });
// Pass this to your existing AI SDK model loop:
const modelTools = { codemode: codeTool };
The Workers executor needs a worker_loaders binding named LOADER. This is platform-specific execution infrastructure. Installing the npm package in a plain Node process does not give Node the Worker Loader API.
{
"worker_loaders": [{ "binding": "LOADER" }],
"compatibility_flags": ["nodejs_compat"]
}
The implementation then follows four steps:
- Prepare.
createCodeToolfilters tools, generates declarations and wraps host functions. In the AI SDK adapter, available schema validators check inputs. - Normalize.
normalizeCoderemoves code fences and wraps common forms into a callable function. Acorn parses JavaScript for this transformation. It is neither a security analysis nor a TypeScript compiler. - Execute.
DynamicWorkerExecutorconstructs a Worker module and loads a fresh sandbox. GeneratedProxyobjects route method calls back to the host with Workers RPC. - Observe. The return value and captured console logs come back. On this helper path,
runCodethrows if execution returns an error. The surrounding agent framework decides how to present that failure to the model.
schema extraction + wrapper · tool.ts:25 · normalizeCode · normalize.ts:1 · runCode · run-code.ts:1
⚠ Approval is different on the two paths. The small helper excludes AI SDK tools with needsApproval: true or a function-valued needsApproval. It does not pause them. The connector runtime below instead uses its own requiresApproval: true annotation to pause and replay.
B. Add connectors when you need discovery and durability
A connector maps an integration to a JavaScript namespace: github.list_pull_requests(…), for example. McpConnector wraps an existing MCP connection; OpenApiConnector derives methods from an API specification; custom connectors expose your own operations.
import {
createCodemodeRuntime,
DynamicWorkerExecutor,
truncateResult
} from "@cloudflare/codemode";
// Inside an Agent / Durable Object; github is your configured connector.
const runtime = createCodemodeRuntime({
ctx: this.ctx,
executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),
connectors: [github],
transformResult: (value) => truncateResult(value)
});
const modelTools = { codemode: runtime.tool() };
// Host-side approval handler, after authenticated user authorization:
// await runtime.approve({ executionId });
The runtime is a Durable Object facet: a named stateful component attached to the agent, with its own SQLite-backed execution history. The Worker entry must export CodemodeRuntime; the @cloudflare/codemode/vite plugin can add that export. The executor runs code once. The facet keeps what happened between runs.
createCodemodeRuntime · runtime-handle.ts:131 · facet lookup · proxy-tool.ts:910
Instead of dumping every method’s schema into the prompt, the runtime exposes a small discovery SDK and the configured namespace names. The model can first run:
async () => {
const matches = await codemode.search("list pull requests");
const docs = await codemode.describe(matches.results[0].path);
return docs;
}
The running program is not another LLM. A string containing new documentation does not magically change code already generated. Returning relevant docs lets the next model turn use the discovered method. If the code can inspect a result mechanically, it need not return the whole object.
The search is weighted lexical matching over method paths, names and descriptions, plus saved snippets. It is not an embedding search. The four platform methods are search, describe, step and run. Connector methods perform the actual application work.
lexical scoring · connectors/search.ts:11 · model-facing instructions · proxy-tool.ts:553
C. Approval restarts the program, then replays completed calls
Consider a connector with list_items and create_item. The developer marks create_item as requiresApproval: true. Each call crosses the runtime, which decides: return an old result, execute now, or pause.
async () => {
const before = await items.list_items();
const created = await items.create_item({ title: "Investigate timeout" });
return { beforeCount: before.length, created };
}
Watch the pause and replay
Scripted model of the documented protocol. No API calls, saved data or real approval.
- Ready. Nothing has run.
External writes: 0
On the first pass, list_items executes and its result is logged. create_item becomes pending; the run aborts with a paused outcome. The host shows the pending arguments to an authorized user.
After approval, the same source code runs from the beginning in a fresh execution. The earlier list call returns its recorded result. The approved create runs, gets logged, and the code continues. No JavaScript stack or local variable snapshot waits in memory for hours. Variables are reconstructed by replay.
decide · runtime.ts:411 · connector dispatch · proxy-tool.ts:398 · approval + replay tests · runtime.test.ts:121
⚠ This is not an exactly-once transaction over external APIs. If a remote write succeeds but the process crashes before recording its result, the log entry can remain executing. The replay logic explicitly allows re-execution. Use API idempotency keys or application-level deduplication for consequential writes.
D. Replay has a contract
- Same calls, same order, same arguments. Changing a timestamp in a pending action’s arguments causes replay divergence. Wrap nondeterministic work in
codemode.step("stamp", () => Date.now())to record and replay the value. - Sequence approval-capable calls. Prefer sequential
awaitoverPromise.allwhen a run may pause. Call sequence numbers are assigned by arrival at the host; racing arrivals can diverge on replay. - Await effects before returning. Release of a sandbox is not cancellation of host work. The 0.5.5 patch releases pending RPC calls so they no longer retain Worker concurrency slots; already-started host calls may still take effect.
- A replayed read can be stale. That preserves control flow across approval. An explicit
replay: "reexecute"read opts out of result storage and can return fresh data; it can also change later branches and trigger divergence. Revalidate authorization and business conditions on the host at write time. - Reject is not undo. Rejecting ends a paused run. Rollback separately attempts developer-supplied
revertfunctions in reverse order. Unrevertible actions remain; compensation can fail.
replay contract · docs/codemode/runtime.md · late-call gate · executor.ts:161 · rollback · proxy-tool.ts:1090
E. Keep the scope of each guarantee visible
| Feature | What it gives you | What you still own |
|---|---|---|
| Worker sandbox | Separate execution; direct network blocked by default via globalOutbound: null. Optional Fetcher routes permitted egress. | Tool scope, server-side authorization, secrets, validation and rate limits. A powerful tool remains powerful through RPC. |
| Type declarations | Readable method names and input/output documentation. | Runtime validation where needed. The connector base calls its execute function directly; declarations alone enforce nothing. |
| Durable log | Recorded calls/results for replay and audit; 1 MB serialized value limit. | Data retention and redaction. Default retention keeps 50 terminal executions; logs are not unlimited archives. |
| Model output shaping | transformResult can shrink final results. The runtime tool’s toModelOutput removes audit-only calls and bounds logs. | Choose useful summaries. Inside-run tool results stay full-sized; final truncation is not input-data validation. |
| Saved snippets | Host promotes an execution’s source with saveSnippet; model discovers and runs it later. | Review and permission policy. A previously successful script is not proof it is safe for new inputs. |
executor configuration · executor.ts:263 · connector executeTool · base.ts:185 · model output projection · proxy-tool.ts:789 · snippet curation · docs/codemode/snippets.md
Security design detail: OpenApiConnector also exposes a low-level authenticated request escape hatch. Protecting a named write method is insufficient if an unrestricted alternative can perform the same write. Scope every route to the integration, including escape hatches.
OpenAPI escape hatch · openapi.ts:78
Other exports, without mixing their guarantees
/tanstack-ai adapts tool definitions for TanStack AI. /mcp supplies MCP server helpers. MCP can remain the underlying transport while model-written code orchestrates calls; Code Mode does not inherently replace MCP.
/browser offers IframeSandboxExecutor and a zero-peer-dependency createBrowserCodeTool. It uses an iframe, CSP and message-based host dispatch. It is not the Workers durable facet. Its timer cannot preempt a tight synchronous browser loop. A custom Executor must provide its own security properties; the interface itself provides no isolation.
Source and verification record · 21 October 2026
- npm latest metadata: version 0.5.5; publish timestamp 2026-10-20 15:24 UTC. API is marked experimental in the package README.
- Cloned cloudflare/agents at fc7f59fb00e7ae0045086b094b94a22abc760206. Compared the published npm tarball’s source-map source contents with the checked source: all 27 mapped package source files matched. Pinned links on this page refer to that commit.
- Ran the published browser build in headless Chrome with synthetic local tools: the PR program returned only #17; call trace was list → checks #17 → checks #19. Confirmed an approval-marked browser tool was excluded and a TypeScript annotation was rejected. This checks browser packaging and the example—not Cloudflare network isolation or durable replay.
- Read Worker executor, tool adapters, connector dispatch, replay decisions, result projection and relevant tests. The upstream Workers runtime tests cover pause/approve, replayed reads, divergence and steps. Those Workers tests were inspected, not rerun here; no cloud deployment or live model benchmark was performed.
- CodeAct comparison below uses the primary 7 June 2024 v4 PDF: method, main experiments, Table 3, CodeActAgent training/results and limitations. No claim of a new replication or comprehensive appendix review.
Can you predict the next step?
Five questions. Choose an answer to see why each option is right or wrong. You can change your answer. Everything runs locally in this page; no answers are submitted.
0 / 5 answered
Continue below for the research comparison and the original paper’s evidence.
CodeAct asks a broader research question.
Executable Code Actions Elicit Better LLM Agents is Xingyao Wang and colleagues’ ICML 2024 paper. It proposes executable Python as an agent action space: generate code, run it, observe results or errors, then revise through further turns. The paper also introduces a benchmark, interaction training data and fine-tuned models.
The common idea is clear. A model can express “fetch these records, loop, branch, compute” as a program. Tool outputs become variables instead of forcing every intermediate decision back through model text.
| Question | Cloudflare Code Mode 0.5.5 | CodeAct paper / CodeActAgent |
|---|---|---|
| What kind of thing? | An experimental npm package: tools, executors, connectors and a durable runtime. You bring the model and outer agent loop. | A research action framework, empirical comparisons, CodeActInstruct data and fine-tuned CodeActAgent models. |
| What does the model write? | JavaScript code inside a tool-call argument; TypeScript declarations document available capabilities. | Python code actions, interleaved with observations and natural-language interaction. |
| What can code call? | Configured host capabilities and supplied modules/bindings. No direct outbound network by default in the Worker executor. | Supplied Python-callable tools in the tool benchmarks; broader interpreter demos use existing Python libraries, such as pandas and scikit-learn. |
| Where does state live? | One-shot executor is disposable. Connector runtime persists source, call results, approvals and snippets; replay reconstructs locals. | Interactive Python state supports reuse of variables and objects across turns, illustrated by reusing a trained model for later metrics/plots. The paper does not specify Cloudflare-style durable approval replay. |
| How does it handle errors? | Exceptions/logs become host outcomes; an outer model loop can revise code. Durable runtime returns structured completed/paused/error outcomes. | Interpreter feedback and tracebacks drive multi-turn self-debugging; training data explicitly retains useful error-correction trajectories. |
| What is trained? | No model training is required by this package. Quality depends on the model you connect. | 7,139 CodeActInstruct trajectories mixed with conversation data; full-parameter tuning of Llama-2 7B and Mistral 7B. |
| Approval & effects? | Optional connector annotations, host approval UI, durable replay and explicit compensating reverts. Scope and authorization remain the application’s job. | The paper acknowledges sandbox/security risks. Its benchmark results are not a production permission or rollback protocol. |
What CodeAct actually measured
The paper evaluates 17 LLMs on atomic API-Bank calls and 82 human-curated M³ToolEval tasks. The latter permits up to ten interaction turns and compares code actions with the tested JSON/text formats.
| Action format | Success rate | Average turns |
|---|---|---|
| CodeAct | 74.4% | 5.5 |
| JSON | 52.4% | 7.6 |
| Text | 53.7% | 7.7 |
That is 20.7 percentage points over the next-best format for this model and task suite. Code wins or ties for best success on 12 of 17 models, not every model. On atomic API-Bank calls, GPT-4’s tested JSON formats do better than code. The fine-tuned Mistral CodeActAgent reaches 12.2% on M³ToolEval; the Llama-2 variant remains at 0%. The action format helps capable models express more, but does not replace capability.
These are 2024 model/benchmark results. They do not measure Cloudflare’s package, current models, sandbox strength, cost per successful production task or long-running reliability. Cloudflare’s “models are better at code” motivation is consistent with part of this evidence; it is not a universal theorem about every tool API.
How to keep the two ideas straight
If you already have a tool-using agent and want it to compose API work inside a restricted execution environment, Code Mode provides implementation pieces. If you want to study which action representation makes an agent more effective, CodeAct provides the research framing and experiments.
You could combine that research pattern with a Code Mode-style runtime: let the model write programs and self-correct, while the host enforces capabilities and durable approval. This is a design combination, not a claim that Cloudflare implements CodeActAgent or derives its code from that project. No direct code lineage was established in this check.
★ Shared principle: use code to express the work between observations. Different scope: CodeAct studies the agent’s action language and learning; Cloudflare packages how code reaches integrations and, optionally, survives approval pauses.
The model writes the plan in an executable language.
The host still owns the permission to carry it out.
Primary paper: Xingyao Wang, Yangyi Chen, Lifan Yuan, Yizhe Zhang, Yunzhu Li, Hao Peng and Heng Ji. CodeAct v4 PDF, §§2–3, Table 3, Figure 3 and Impact Statement. Original code, data and models. Cloudflare source, tests and verification scope are linked in the implementation record.