Code Mode API reference
Code Mode publishes six package entry points. Import framework-specific APIs from their matching entry point:
| Entry point | Purpose |
|---|---|
@cloudflare/codemode | Runtime, connectors, Workers executor, and framework-independent utilities |
@cloudflare/codemode/ai | AI SDK tools and connector adapter |
@cloudflare/codemode/mcp | Model Context Protocol (MCP) server wrappers |
@cloudflare/codemode/tanstack-ai | TanStack AI tools and adapter |
@cloudflare/codemode/browser | Browser tool descriptor and iframe executor |
@cloudflare/codemode/vite | Vite plugin for connector discovery and Worker exports |
The main entry point does not require the optional AI SDK, TanStack AI, or Zod peer dependencies to be installed.
function createCodemodeRuntime( options: CreateCodemodeRuntimeOptions,): CodemodeRuntimeHandle;Creates the host-side control plane for a named Code Mode runtime.
CreateCodemodeRuntimeOptions has these fields:
| Field | Type | Required | Description |
|---|---|---|---|
ctx | DurableObjectState | Yes | Durable Object state that hosts the runtime facet. |
connectors | CodemodeConnector[] | Yes | Connectors exposed as sandbox globals. Connector names must be unique, and codemode is reserved. |
executor | Executor | Yes | Sandbox that runs generated code. |
name | string | No | Durable runtime identity. Defaults to "default". Valid characters are letters, digits, _, -, and .. |
maxExecutions | number | No | Terminal records kept when a new run begins. Defaults to 50. Running and paused executions are not pruned. |
transformResult | TransformResult | No | Reshapes a completed result returned to the model. The audit trail retains the unmodified result. |
interface CodemodeRuntimeHandle { tool( options?: CodemodeRuntimeToolOptions, ): Tool<ProxyToolInput, ProxyToolOutput>; approve(options: CodemodeApproveOptions): Promise<ProxyToolOutput>; reject(options: CodemodeRejectOptions): Promise<boolean>; rollback(options: CodemodeRollbackOptions): Promise<void>; pending(executionId?: string): Promise<PendingAction[]>; expirePaused(options?: CodemodeExpireOptions): Promise<string[]>; executions(limit?: number): Promise<ExecutionState[]>; deleteExecution(id: string): Promise<boolean>; pruneExecutions(keep?: number): Promise<number>; saveSnippet(name: string, options: SaveSnippetOptions): Promise<Snippet>; snippets(): Promise<Snippet[]>; deleteSnippet(name: string): Promise<boolean>;}The handle methods have these effects:
| Method | Effect |
|---|---|
tool(options?) | Returns the AI SDK tool given to the model. description replaces the default description. connectorHints adds a one-line hint for each connector when using the default description. |
approve({ executionId }) | Resumes a paused execution through replay. The result can complete, pause again, or return an error status. It does not revive a non-paused execution. |
reject({ seq, executionId }) | Rejects one pending action and terminates the execution. Returns false if the action is no longer pending. It does not roll back earlier actions. |
rollback({ executionId }) | Calls available revert functions in reverse call order. Missing connectors and methods without revert remain applied. It attempts later reverts after a failure. |
pending(executionId?) | Lists pending actions. Without an ID, it combines actions from all paused executions. |
expirePaused({ maxAgeMs? }) | Terminates stale paused or running executions and returns their IDs. The default age is 24 hours. |
executions(limit?) | Returns audit records, newest first. |
deleteExecution(id) | Deletes one audit record. It also disposes resources for a non-terminal execution. Returns whether the record existed. |
pruneExecutions(keep?) | Deletes older terminal records and returns the count deleted. Defaults to keeping 50. |
saveSnippet(name, options) | Saves code from options.executionId as a reusable snippet. It accepts any execution status, so applications should verify successful completion first. Replaces the same name. |
snippets() | Returns saved snippets, ordered by name. |
deleteSnippet(name) | Deletes a snippet and returns whether it existed. |
The method option types are:
type CodemodeRuntimeToolOptions = { description?: string; connectorHints?: Record<string, string>;};
type CodemodeApproveOptions = { executionId: string };type CodemodeRejectOptions = { seq: number; executionId: string };type CodemodeRollbackOptions = { executionId: string };type CodemodeExpireOptions = { maxAgeMs?: number };class CodemodeRuntime extends DurableObject<unknown> { constructor(ctx: DurableObjectState, env: unknown);}CodemodeRuntime is the durable facet behind the runtime handle. The Vite plugin exports this class from the Worker entry module. Use createCodemodeRuntime() for application code instead of constructing the facet directly.
The main entry point also exports these runtime constants:
| Constant | Value | Purpose |
|---|---|---|
DEFAULT_MAX_EXECUTIONS | 50 | Default terminal execution retention count |
DEFAULT_PAUSED_TTL_MS | 86400000 | Default stale execution age in milliseconds (24 hours) |
MAX_DURABLE_VALUE_BYTES | 1000000 | Serialized JavaScript string-length limit for one durable value |
type ProxyToolInput = { code: string };
type ProxyToolOutput = | { status: "completed"; executionId: string; result: unknown; logs?: string[]; } | { status: "paused"; executionId: string; pending: PendingAction[]; } | { status: "error"; executionId: string; error: string; logs?: string[]; };
type TransformResult = (result: unknown) => unknown | Promise<unknown>;Sandbox and replay errors use the error output variant. They do not throw through the model tool call.
type ExecutionStatus = | "running" | "paused" | "completed" | "error" | "rejected" | "rolled_back";
type ExecutionState = { id: string; code: string; status: ExecutionStatus; log: ToolLogEntry[]; result?: unknown; error?: string; logs?: string[]; connectors?: string[]; createdAt: number; updatedAt: number;};
type ToolLogEntry = { seq: number; connector: string; method: string; args: unknown; result?: unknown; requiresApproval: boolean; ephemeral?: boolean; state: "executing" | "applied" | "pending" | "reverted" | "error";};
type PendingAction = { executionId: string; seq: number; connector: string; method: string; args: unknown;};createdAt and updatedAt contain epoch milliseconds. An ephemeral log entry comes from a connector tool with replay: "reexecute". Its result is not stored and the call runs again during replay.
The runtime decision type is:
type ToolDecision = | { kind: "replay"; result: unknown } | { kind: "execute"; seq: number } | { kind: "pause"; seq: number };runtime.tool() injects a codemode global into generated sandbox code.
declare const codemode: { search(query: string): Promise<SearchOutput>; describe(target: string): Promise<DescribeOutput>; step<T>(name: string, fn: () => T | Promise<T>): Promise<T>; run(name: string, input?: unknown): Promise<unknown>;};The sandbox methods behave as follows:
| Method | Description |
|---|---|
search(query) | Searches connector methods and saved snippets. Results are ranked and limited to 50. |
describe(target) | Returns generated TypeScript for a connector, connector.method, or snippet name. |
step(name, fn) | Runs a closure once and records its result. Replay returns the recorded result without running the closure again. |
run(name, input?) | Runs a saved snippet. A missing snippet or recorded connector resolves to an object with an error property. |
Use step() around nondeterministic or side-effectful sandbox work that does not use a connector. Issue connector calls sequentially when an execution can pause. Concurrent calls can reach the replay cursor in a different order.
The discovery output types are:
type SearchResult = { path: string; connector: string; method: string; description?: string; kind: "method" | "snippet"; score: number;};
type SearchOutput = { results: SearchResult[]; total: number; truncated: boolean;};
type DescribeOutput = { path: string; description?: string; types: string; kind: "connector" | "method" | "snippet";};interface SaveSnippetOptions { description?: string; inputSchema?: unknown; executionId: string;}
interface Snippet { name: string; description: string; code: string; savedAt: number; inputSchema?: unknown; connectors?: string[];}connectors records every namespace configured when the source execution started. savedAt contains epoch milliseconds. Before calling saveSnippet(), verify that the source ExecutionState.status is completed.
interface Executor { execute( code: string, providersOrFns: | ResolvedProvider[] | Record<string, (...args: unknown[]) => Promise<unknown>>, options?: ExecuteOptions, ): Promise<ExecuteResult>;}Custom executors should report failures in ExecuteResult.error instead of throwing.
interface ExecuteResult { result: unknown; error?: string; logs?: string[];}
interface ResolvedProvider { name: string; fns: Record<string, (...args: unknown[]) => Promise<unknown>>; prelude?: string;}
interface ConnectorBinding { name: string; binding: { callTool(method: string, args: unknown): Promise<unknown>; };}
interface ExecuteOptions { connectors?: ConnectorBinding[];}Passing a function record instead of ResolvedProvider[] is deprecated. It creates one provider named codemode.
class DynamicWorkerExecutor implements Executor { constructor(options: DynamicWorkerExecutorOptions); execute( code: string, providersOrFns: | ResolvedProvider[] | Record<string, (...args: unknown[]) => Promise<unknown>>, options?: ExecuteOptions, ): Promise<ExecuteResult>;}DynamicWorkerExecutorOptions has these fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
loader | WorkerLoader | Yes | — | Worker Loader binding used to create isolated Workers. |
timeout | number | No | 60000 | Execution timeout in milliseconds. |
globalOutbound | Fetcher | null | No | null | Outbound network policy. null blocks access. A Fetcher receives all outbound requests. |
modules | Record<string, string> | No | {} | Module source keyed by import specifier. The reserved executor.js key is ignored. |
bindings | Record<string, unknown> | No | {} | Additional environment bindings injected into each sandbox Worker. |
The executor validates provider and connector namespaces. Names must be valid JavaScript identifiers, unique, and must not shadow executor globals.
class ToolDispatcher extends RpcTarget { constructor(fns: Record<string, (...args: unknown[]) => Promise<unknown>>); call(name: string, argsJson?: string): Promise<string>;}ToolDispatcher is the Workers RPC bridge used by DynamicWorkerExecutor. call() accepts serialized positional arguments and returns a serialized result or error envelope.
function runCode(options: { code: string; executor: Executor; providers: ResolvedProvider[]; connectors?: ConnectorBinding[];}): Promise<{ result: unknown; logs?: string[] }>;Normalizes and executes code. An ExecuteResult.error causes runCode() to throw an Error that includes captured console output.
interface ToolProvider { name?: string; tools: ToolDescriptors | ToolSet | SimpleToolRecord; types?: string;}Tool providers have these fields:
| Field | Description |
|---|---|
name | Sandbox namespace. Defaults to codemode. |
tools | Tool descriptors, an AI SDK ToolSet, or records containing execute. |
types | TypeScript declarations shown to the model. Code Mode generates them when omitted. |
function resolveProvider(provider: ToolProvider): ResolvedProvider;The main-entry implementation does not validate inputs against schemas. It excludes tools whose needsApproval is true or a function. Use runtime connectors for durable approval flows.
abstract class CodemodeConnector< Env = unknown, Props = unknown,> extends WorkerEntrypoint<Env, Props> { constructor(ctx: DurableObjectState | ExecutionContext, env: Env);
abstract name(): string; protected instructions(): string | undefined; protected abstract tools(): ConnectorTools | Promise<ConnectorTools>; protected tool(name: string, tool: ConnectorTool): ConnectorTool;
describe(): Promise<ConnectorDescription>; executeTool( method: string, args: unknown, ctx?: ToolExecuteContext, ): Promise<unknown>; revertAction( method: string, args: unknown, result: unknown, ctx?: ToolExecuteContext, ): Promise<boolean>; onPassEnd(executionId: string, status: PassEndStatus): Promise<void>; disposeExecution( executionId: string, status: ExecutionEndStatus, ): Promise<void>; getTypeScriptTypes(): Promise<string>;}Connector authors implement or override these hooks:
| Hook | Required | Description |
|---|---|---|
name() | Yes | Returns the unique sandbox namespace. |
instructions() | No | Returns connector guidance included by describe(). |
tools() | Yes | Returns the connector tool record. Derived connectors implement this hook. |
tool(name, tool) | No | Decorates a resolved tool. Use it to add approval, replay, or revert behavior to derived tools. |
onPassEnd(executionId, status) | No | Releases per-pass resources. Runs after every pass, including a paused pass. |
disposeExecution(executionId, status) | No | Releases per-execution resources after a terminal transition. It does not run on pause. |
Lifecycle hooks should be idempotent, should not rely on instance memory, and should not throw. On a terminal pass, onPassEnd() runs before disposeExecution().
The base class derives describe(), executeTool(), revertAction(), and getTypeScriptTypes() from the tool record. Connector authors do not need to implement these methods.
type ConnectorTool = { description?: string; inputSchema?: JSONSchema7; outputSchema?: JSONSchema7; requiresApproval?: boolean; replay?: "log" | "reexecute"; execute: ( args: unknown, ctx?: ToolExecuteContext, ) => Promise<unknown> | unknown; revert?: ( args: unknown, result: unknown, ctx?: ToolExecuteContext, ) => Promise<void> | void;};
type ConnectorTools = Record<string, ConnectorTool>;type ToolExecuteContext = { executionId: string };inputSchema defaults to an open object. requiresApproval: true pauses before execution. replay: "reexecute" skips durable result storage and re-executes the call on each resume. These two options cannot be combined.
revert provides compensation for runtime.rollback(). It can apply to any tool, whether or not the tool requires approval.
abstract class McpConnector< Env = unknown, Props = unknown,> extends CodemodeConnector<Env, Props> { protected abstract createConnection(): | McpConnectionLike | Promise<McpConnectionLike>; protected toolName(tool: McpTool): string;}McpConnector converts each MCP tool into a connector method. toolName() defaults to sanitizeToolName(tool.name). Override it to resolve naming collisions.
interface McpConnectionLike { name?: string; client: Pick<Client, "callTool">; instructions?: string; tools?: McpTool[]; fetchTools?: () => Promise<McpTool[]>;}The connector uses tools when that array is non-empty. Otherwise, it calls fetchTools() when provided. MCP error results become thrown connector errors. Structured content is returned before text content.
abstract class OpenApiConnector< Env = unknown, Props = unknown,> extends CodemodeConnector<Env, Props> { protected abstract spec(): | Record<string, unknown> | Promise<Record<string, unknown>>; protected abstract request(options: OpenApiRequestOptions): Promise<unknown>; protected exposeSpec(): boolean;}OpenApiConnector creates one method per OpenAPI operation. It uses a sanitized operationId when present, then falls back to a name based on the HTTP method and path. Duplicate operations and names reserved for request or spec are skipped.
Every OpenAPI connector exposes a low-level request method. exposeSpec() defaults to false. Return true to also expose spec.
type OpenApiRequestOptions = { path: string; method?: string; params?: Record<string, unknown>; body?: unknown; headers?: Record<string, string>;};Derived operation tools substitute path parameters. They pass query values as params, header values as headers, and JSON request data as body.
type ExecutionEndStatus = "completed" | "error" | "rejected" | "rolled_back";
type PassEndStatus = ExecutionEndStatus | "paused";
type ToolAnnotations = { requiresApproval?: boolean; replay?: "log" | "reexecute";};
type ConnectorDescription = { name: string; instructions?: string; descriptors: JsonSchemaToolDescriptors; annotations?: Record<string, ToolAnnotations>;};interface JsonSchemaToolDescriptor { description?: string; inputSchema: JSONSchema7; outputSchema?: JSONSchema7;}
type JsonSchemaToolDescriptors = Record<string, JsonSchemaToolDescriptor>;
function generateTypesFromJsonSchema(tools: JsonSchemaToolDescriptors): string;
function jsonSchemaToType(schema: JSONSchema7, typeName: string): string;generateTypesFromJsonSchema() returns declarations for a codemode namespace. Tool names are sanitized before declarations are generated. Unsupported schemas degrade to unknown instead of causing generation to fail.
The main entry point provides these code and result utilities:
| Function | Signature | Behavior |
|---|---|---|
sanitizeToolName | (name: string) => string | Replaces common separators, removes invalid characters, prefixes digit-leading names, and suffixes JavaScript reserved words. |
normalizeCode | (code: string) => string | Converts common model output forms into an async arrow function. It also removes supported Markdown fences. |
truncateResponse | (text: string, options?: TruncateOptions) => string | Truncates text to a character budget and appends a size marker. |
truncateResult | (value: unknown, options?: TruncateOptions) => unknown | Preserves small structured values. Oversized serializable values become truncated JSON text. |
type TruncateOptions = { maxChars?: number; maxTokens?: number;};The default budget is 6000 estimated tokens at four characters per token. maxChars overrides the derived character budget.
This entry point requires the ai and zod peer dependencies.
function createCodeTool( options: CreateCodeToolOptions,): Tool<CodeInput, CodeOutput>;
interface CreateCodeToolOptions { tools: ToolProviderTools | ToolProvider[]; executor: Executor; description?: string;}
type CodeInput = { code: string };type CodeOutput = { result: unknown; logs?: string[] };description can contain {{types}}. Code Mode replaces that token with generated declarations. A raw tool record becomes one provider named codemode. An array accepts multiple provider namespaces.
Tools whose needsApproval is true or a function are excluded. This API does not pause. Use createCodemodeRuntime() and connectors for durable approval handling.
The AI SDK entry point provides these tool-provider utilities:
| Export | Signature | Description |
|---|---|---|
aiTools | (tools: ToolDescriptors | ToolSet) => ToolProvider | Wraps AI SDK tools in the default provider. |
generateTypes | (tools: ToolDescriptors | ToolSet, namespace?: string) => string | Generates declarations from AI SDK or Zod schemas. The namespace defaults to codemode. |
resolveProvider | (provider: ToolProvider) => ResolvedProvider | Filters approval-gated tools, validates input with AI SDK asSchema() when available, and extracts executable functions. |
interface ToolDescriptor { description?: string; inputSchema: ZodType; outputSchema?: ZodType; execute?: (args: unknown) => Promise<unknown>;}
type ToolDescriptors = Record<string, ToolDescriptor>;class ToolSetConnector extends CodemodeConnector { constructor( ctx: DurableObjectState | ExecutionContext, options: ToolSetConnectorOptions, );}
function toolSetConnector( ctx: DurableObjectState | ExecutionContext, options: ToolSetConnectorOptions,): ToolSetConnector;
interface ToolSetConnectorOptions { name?: string; instructions?: string; tools: ToolSet;}The namespace defaults to tools. The connector excludes tools without an execute function. needsApproval: true and function-valued needsApproval map to durable connector approval. needsApproval: false executes without approval. AI SDK schemas validate input before execution.
This entry point requires the MCP SDK and Zod peer dependencies.
interface CodeMcpServerOptions { server: McpServer; executor: Executor; description?: string;}
function codeMcpServer(options: CodeMcpServerOptions): Promise<McpServer>;Wraps an existing MCP server with one code tool. The wrapper connects to the source server through an in-memory transport, discovers its tools, and exposes those tools as methods on codemode inside the executor.
A custom description can contain {{types}}, which the wrapper replaces with generated TypeScript declarations. It can also contain {{example}}, which the wrapper replaces with an example call based on the first upstream MCP tool. Returned MCP values are unwrapped in this order: compatibility toolResult, MCP errors, structuredContent, all-text content, then the original mixed-content result.
interface OpenApiMcpServerOptions { spec: Record<string, unknown>; executor: Executor; request: (options: RequestOptions) => Promise<unknown>; name?: string; version?: string; description?: string;}
interface RequestOptions { method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; path: string; query?: Record<string, string | number | boolean | undefined>; body?: unknown; contentType?: string; rawBody?: boolean;}
function openApiMcpServer(options: OpenApiMcpServerOptions): McpServer;Creates an MCP server with two tools:
| MCP tool | Sandbox API | Purpose |
|---|---|---|
search | codemode.spec() | Runs code against the OpenAPI document. Local $ref values are resolved before the code receives the document. |
execute | codemode.spec() and codemode.request(options) | Runs code that can inspect the document and call the host-provided request function. |
name defaults to openapi. version defaults to 1.0.0. The host request function keeps credentials outside the sandbox. Text responses are limited to approximately 6,000 tokens and include a truncation marker when clipped.
The search and execute tool descriptions use fixed example snippets. Unlike codeMcpServer(), this function does not support {{types}} or {{example}} placeholders. An optional description is appended to the execute tool description.
This entry point requires the @tanstack/ai and zod peer dependencies.
function createCodeTool(options: CreateCodeToolOptions): ServerTool;The options, CodeInput, and CodeOutput match the /ai entry point. The returned ServerTool can be passed to TanStack AI chat().
The TanStack AI entry point provides these tool-provider utilities:
| Export | Signature | Description |
|---|---|---|
tanstackTools | (tools: TanStackTool[], name?: string) => ToolProvider | Wraps TanStack AI tools in a provider. Only tools with an execute function are callable. The namespace defaults to codemode. |
generateTypes | (tools: TanStackTool[], namespace?: string) => string | Converts supported TanStack AI schemas to JSON Schema, then generates declarations. |
resolveProvider | (provider: ToolProvider) => ResolvedProvider | Resolves a framework-independent provider without schema validation. |
normalizeProviders | (tools: ToolProviderTools | ToolProvider[]) => ToolProvider[] | Converts raw tools into a one-element provider array. |
This entry point also exports DEFAULT_DESCRIPTION. tanstackTools() excludes tools with needsApproval: true or a function-valued needsApproval. Tools with needsApproval: false remain callable.
The browser entry point uses browser APIs and plain JSON Schema. It does not require the AI SDK or Zod.
function createBrowserCodeTool( options: CreateBrowserCodeToolOptions,): BrowserCodeToolDescriptor;
interface CreateBrowserCodeToolOptions { tools: | JsonSchemaExecutableToolDescriptor[] | JsonSchemaExecutableToolDescriptors; executor?: Executor; description?: string;}Array-form tools must include name. Object-form tools use each record key as the name. The executor defaults to a new IframeSandboxExecutor.
The tools option also accepts descriptors with needsApproval?: boolean | ((...args: unknown[]) => unknown). Tools with needsApproval: true or a function-valued needsApproval are excluded. Tools with needsApproval: false remain callable. JSON Schema contributes model-facing declarations but does not perform runtime validation.
interface JsonSchemaExecutableToolDescriptor extends JsonSchemaToolDescriptor { name?: string; execute: (args: Record<string, unknown>) => Promise<unknown>;}
type JsonSchemaExecutableToolDescriptors = Record< string, JsonSchemaExecutableToolDescriptor>;The returned descriptor has this shape:
interface BrowserCodeToolDescriptor { name: string; description: string; inputSchema: { type: "object"; properties: { code: { type: "string"; description: string }; }; required: ["code"]; }; outputSchema: { type: "object"; properties: { result: { description: string }; logs: { type: "array"; items: { type: "string" }; description: string; }; }; required: ["result"]; }; execute(args: CodeInput): Promise<CodeOutput>;}class IframeSandboxExecutor implements Executor { constructor(options?: IframeSandboxExecutorOptions); execute( code: string, providersOrFns: | ResolvedProvider[] | Record<string, (...args: unknown[]) => Promise<unknown>>, ): Promise<ExecuteResult>;}
interface IframeSandboxExecutorOptions { timeout?: number; csp?: string;}The iframe executor accepts these options:
| Field | Default | Description |
|---|---|---|
timeout | 30000 | Maximum execution time in milliseconds. It cannot preempt a synchronous loop that blocks the browser event loop. |
csp | default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; | Content Security Policy applied to the sandbox iframe document. |
Each execution creates a hidden iframe with sandbox="allow-scripts". Tool calls cross the iframe boundary through nonce-scoped postMessage messages. The iframe is removed after success, error, or timeout.
This entry point also exports the framework-independent Executor, ExecuteResult, and ResolvedProvider types. It re-exports JsonSchemaToolDescriptor and JsonSchemaToolDescriptors.
The Vite entry point has one default export:
function codemodeVitePlugin(): Plugin;The plugin appends export { CodemodeRuntime } from "@cloudflare/codemode" to the Worker entry module (src/server.ts, src/index.ts, or src/worker.ts). This makes the runtime facet available as ctx.exports.CodemodeRuntime, which createCodemodeRuntime() requires.
The plugin leaves the entry module unchanged if it already exports CodemodeRuntime. Connector classes need no special file name or import syntax — import them normally and pass instances to the runtime.
Without the plugin, add the export manually:
export { CodemodeRuntime } from "@cloudflare/codemode";A connector import can target one connector file or a directory. A directory import re-exports every matching connector file under that directory.