Code mode is an experimental OpenClaw agent-runtime feature. It is off by default. When you enable it, OpenClaw changes what the model sees for one run: instead of exposing every enabled tool schema directly, the model sees onlyDocumentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
exec and wait.
This page documents OpenClaw code mode. It is not Codex Code mode. Codex Code
mode is part of the Codex coding harness and has its own project workspace,
runtime, tools, and execution semantics. Codex Code mode and Codex-native
dynamic tool search are stable Codex harness surfaces. OpenClaw code mode is an
OpenClaw-owned experimental tool-surface adapter for generic OpenClaw runs. It
uses quickjs-wasi, a hidden OpenClaw tool catalog, and the normal OpenClaw
tool executor.
What is this?
OpenClaw code mode lets the model write a small JavaScript or TypeScript program instead of choosing directly from a long list of tools. When code mode is active:- The model-visible tool list is exactly
execandwait. execevaluates model-generated JavaScript or TypeScript in a constrained QuickJS-WASI worker.- Normal OpenClaw tools are hidden from the model prompt and exposed inside the
guest program through
ALL_TOOLSandtools. - Guest code can search the hidden catalog, describe a tool, and call a tool through the same OpenClaw execution path used by normal agent turns.
waitresumes a suspended code-mode run when nested tool calls are still pending.
Why is this good?
Code mode makes large tool catalogs easier for models to use.- Smaller prompt surface: providers receive two control tools instead of dozens or hundreds of full tool schemas.
- Better orchestration: the model can use loops, joins, small transforms, conditional logic, and parallel nested tool calls inside one code cell.
- Provider neutral: it works for OpenClaw, plugin, MCP, and client tools without depending on provider-native code execution.
- Existing policy stays in force: nested tool calls still go through OpenClaw policy, approvals, hooks, session context, and audit paths.
- Clear failure mode: when code mode is explicitly enabled and the runtime is unavailable, OpenClaw fails closed instead of falling back to broad direct tool exposure.
How to enable it
Addtools.codeMode.enabled: true to the agent or runtime config:
tools.codeMode is omitted, false, or an object
without enabled: true.
Use explicit limits when you want tighter bounds:
exec and
wait. If you need the redacted provider payload, add
OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted for a short debugging session.
Technical tour
The rest of this page describes the runtime contract and implementation details. It is intended for maintainers, plugin authors debugging tool exposure, and operators validating high-risk deployments.Runtime status
- Runtime:
quickjs-wasi. - Default state: disabled.
- Stability: experimental OpenClaw surface; Codex Code mode is a separate stable Codex harness surface.
- Target surface: generic OpenClaw agent runs.
- Security posture: model code is hostile.
- User-facing promise: enabling code mode never silently falls back to broad direct tool exposure.
Scope
Code mode owns the model-facing orchestration shape for a prepared run. It does not own model selection, channel behavior, auth, tool policy, or tool implementations. In scope:- model-visible
execandwaittool definitions - hidden tool catalog construction
- JavaScript and TypeScript guest execution
- QuickJS-WASI worker runtime
- host callbacks for catalog search, schema describe, and tool call
- resumable state for suspended guest programs
- output, timeout, memory, pending-call, and snapshot limits
- telemetry and trajectory projection for nested tool calls
- provider-native remote code execution
- shell execution semantics
- changing existing tool authorization
- persistent user-authored scripts
- package manager, file, network, or module access in guest code
- direct reuse of Codex Code mode internals
Terms
Code mode is the OpenClaw runtime mode that hides normal model tools and exposes onlyexec and wait.
Guest runtime is the QuickJS-WASI JavaScript VM that evaluates model code.
Host bridge is the narrow JSON-compatible callback surface from guest code
back into OpenClaw.
Catalog is the run-scoped list of effective tools after normal tool policy,
plugin, MCP, and client-tool resolution.
Nested tool call is a tool call made from guest code through the host bridge.
Snapshot is serialized QuickJS-WASI VM state saved so wait can continue a
suspended code-mode run.
Configuration
tools.codeMode.enabled is the activation gate. Setting other code-mode fields
does not enable the feature.
Supported fields:
enabled: boolean. Defaultfalse. Enables code mode only whentrue.runtime:"quickjs-wasi". Only supported runtime.mode:"only". Exposesexecandwait, hides normal model tools.languages: array of"javascript"and"typescript". Default includes both.timeoutMs: wall-clock cap for oneexecorwait. Default10000. Runtime clamp:100to60000.memoryLimitBytes: QuickJS heap cap. Default67108864. Runtime clamp:1048576to1073741824.maxOutputBytes: cap for returned text, JSON, and logs. Default65536. Runtime clamp:1024to10485760.maxSnapshotBytes: cap for serialized VM snapshots. Default10485760. Runtime clamp:1024to268435456.maxPendingToolCalls: cap for concurrent nested tool calls. Default16. Runtime clamp:1to128.snapshotTtlSeconds: how long a suspended VM can be resumed. Default900. Runtime clamp:1to86400.searchDefaultLimit: default hidden-catalog search result count. Default8. Runtime clamps this tomaxSearchLimit.maxSearchLimit: maximum hidden-catalog search result count. Default50. Runtime clamp:1to50.
Activation
Code mode is evaluated after the effective tool policy is known and before the final model request is assembled. Activation order:- Resolve the agent, model, provider, sandbox, channel, sender, and run policy.
- Build the effective OpenClaw tool list.
- Add eligible plugin, MCP, and client tools.
- Apply allow and deny policy.
- If
tools.codeMode.enabledis false, continue with normal tool exposure. - If enabled and tools are active for the run, register the effective tools in the code-mode catalog.
- Remove all normal tools from the model-visible tool list.
- Add code-mode
execandwait.
disableTools,
or an empty allowlist, do not activate the code-mode surface even if the config
contains tools.codeMode.enabled: true.
The code-mode catalog is run-scoped. It must not leak tools from another agent,
session, sender, or run.
Model-visible tools
When code mode is active, the model sees exactly these top-level tools:execwait
exec for tool orchestration, data joining, loops,
parallel nested calls, and structured transformations. The model should use
wait only when exec returns a resumable waiting result.
exec
exec starts a code-mode cell and returns one result. The input code is model
generated and must be treated as hostile.
Input:
codeis required and must be non-empty.languagedefaults to"javascript".- If
languageis"typescript", OpenClaw transpiles before evaluation. execrejectsimport,require, dynamic import, and module-loader patterns in v1.execdoes not expose the normal shellexecimplementation recursively.
exec returns waiting when the QuickJS VM suspends with resumable state. The
result includes a runId for wait.
exec returns completed only when the guest VM has no pending work and the
final value is JSON-compatible after OpenClaw’s output adapter runs.
wait
wait continues a suspended code-mode VM.
Input:
CodeModeResult union returned by exec.
wait exists because nested OpenClaw tools can be slow, interactive, approval
gated, or stream partial updates. The model should not need to keep one long
exec call open while the host waits for external work.
QuickJS-WASI snapshot and restore is the v1 resume mechanism:
execevaluates code until completion, failure, or suspension.- On suspension, OpenClaw snapshots the QuickJS VM and records pending host work.
- When pending work settles,
waitrestores the VM snapshot. - OpenClaw re-registers host callbacks by stable names.
- OpenClaw delivers nested tool results into the restored VM.
- OpenClaw drains QuickJS pending jobs.
waitreturnscompleted,failed, or anotherwaitingresult.
wait fails when:
runIdis unknown.- the snapshot expired.
- the parent run or session was aborted.
- the caller is not in the same run/session scope.
- QuickJS-WASI restore fails.
- restoring would exceed configured limits.
Guest runtime API
The guest runtime exposes a small global API:ALL_TOOLS is compact metadata for the run-scoped catalog. It does not contain
full schemas by default.
Output API
text(value) appends human-readable output to the output array.
json(value) appends a structured output item after JSON-compatible
serialization.
The guest code’s final returned value becomes value in a completed result.
Output item:
- output order matches guest calls
- output is capped by
maxOutputBytes - non-serializable values are converted to plain strings or errors
- binary values are not supported in v1
- images and files travel through ordinary OpenClaw tools, not through the code-mode bridge
Tool catalog
The hidden catalog includes tools after effective policy filtering:- OpenClaw core tools.
- Bundled plugin tools.
- External plugin tools.
- MCP tools.
- Client-provided tools for the current run.
execwaittool_search_codetool_searchtool_describetool_call
Tool Search interaction
Code mode supersedes the PI Tool Search model surface for runs where it is active. Whentools.codeMode.enabled is true and code mode activates:
- OpenClaw does not expose
tool_search_code,tool_search,tool_describe, ortool_callas model-visible tools. - The same cataloging idea moves inside the guest runtime.
- The guest runtime receives compact
ALL_TOOLSmetadata and search, describe, and call helpers. - Nested calls dispatch through the same OpenClaw executor path that Tool Search uses.
exec and wait.
Tool names and collisions
The model-visibleexec tool is the code-mode tool. If the normal OpenClaw
shell exec tool is enabled, it is hidden from the model and cataloged like any
other tool.
Inside the guest runtime:
tools.call("openclaw:core:exec", input)can call the shell exec tool if policy allows it.tools.exec(...)is installed only if the shell exec catalog entry has an unambiguous safe name.- the code-mode
exectool is never recursively available throughtools.
tools.call(id, input).
Nested tool execution
Every nested tool call crosses the host bridge and re-enters OpenClaw. Nested execution preserves:- active agent id
- session id and session key
- sender and channel context
- sandbox policy
- approval policy
- plugin
before_tool_callhooks - abort signal
- streaming updates where available
- trajectory and audit events
maxPendingToolCalls.
Runtime state
Each code-mode run has a state machine:running: VM is executing or nested calls are in flight.waiting: VM snapshot exists and can be resumed withwait.completed: final value returned; snapshot deleted.failed: error returned; snapshot deleted.expired: snapshot or pending state exceeded retention; cannot resume.aborted: parent run/session cancelled; snapshot deleted.
wait call from a
different run or session fails.
Snapshot storage is bounded:
- maximum snapshot bytes per run
- maximum live snapshots per process
- snapshot TTL
- cleanup on run end
- cleanup on Gateway shutdown where persistence is not supported
QuickJS-WASI runtime
OpenClaw loadsquickjs-wasi as a direct dependency in the owning package. The
runtime does not rely on a transitive copy installed for proxy, PAC, or other
unrelated dependencies.
Runtime responsibilities:
- compile or load the QuickJS-WASI WebAssembly module
- create one isolated VM per code-mode run or resume
- register host callbacks by stable names
- set memory and interrupt limits
- evaluate JavaScript
- drain pending jobs
- snapshot suspended VM state
- restore snapshots for
wait - dispose VM handles and snapshots after terminal states
TypeScript
TypeScript support is a source transform only:- accepted input: one TypeScript code string
- output: JavaScript string evaluated by QuickJS-WASI
- no typechecking
- no module resolution
- no
importorrequirein v1 - diagnostics are returned as
failedresults
Security boundary
Model code is hostile. The runtime uses defense in depth:- run QuickJS-WASI outside the main event loop
- load
quickjs-wasias a direct dependency, not through Codex or a transitive package - no filesystem, network, subprocess, module import, environment variables, or host global objects in the guest
- use QuickJS memory and interrupt limits
- enforce parent-process wall-clock timeout
- enforce output, snapshot, log, and pending-call caps
- serialize host bridge values through a narrow JSON adapter
- convert host errors into plain guest errors, never host realm objects
- drop snapshots on timeout, abort, session end, or expiry
- reject recursive access to
exec,wait, and Tool Search control tools - prevent convenience-name collisions from shadowing catalog helpers
Error codes
Error instances, stack
objects, prototypes, and host functions do not cross into QuickJS.
Telemetry
Code mode reports:- visible tool names sent to the model
- hidden catalog size and source breakdown
execandwaitcounts- nested search, describe, and call counts
- nested tool ids called
- timeout, memory, snapshot, and output cap failures
- snapshot lifecycle events
Debugging
Use targeted model transport logging when code mode behaves differently from a normal tool run:OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted.
This logs a capped, redacted JSON snapshot of the model request; it should only
be used while debugging because prompts and message text can still appear.
For stream debugging, use OPENCLAW_DEBUG_SSE=peek to log the first five
redacted SSE events. Code mode also fails closed if the final provider payload
does not contain exactly exec and wait after the code-mode surface has
activated.
Implementation layout
Implementation units:- config contract:
tools.codeMode - catalog builder: effective tools to compact entries and id map
- model-surface adapter: replace visible tools with
execandwait - QuickJS-WASI runtime adapter: load, eval, snapshot, restore, dispose
- worker supervisor: timeout, abort, crash isolation
- bridge adapter: JSON-safe host callbacks and result delivery
- TypeScript transform adapter
- snapshot store: TTL, size caps, run/session scoping
- trajectory projection for nested tool calls
- telemetry counters and diagnostics
node:vm child as the sandbox.
Validation checklist
Code mode coverage should prove:- disabled config leaves existing tool exposure unchanged
- object config without
enabled: trueleaves code mode disabled - enabled config exposes only
execandwaitto the model when tools are active for the run - raw no-tool runs,
disableTools, and empty allowlists do not trigger code-mode payload enforcement - all effective tools appear in
ALL_TOOLS - denied tools do not appear in
ALL_TOOLS tools.search,tools.describe, andtools.callwork for OpenClaw tools- Tool Search control tools are hidden from both the model surface and the hidden catalog
- nested calls preserve approval and hook behavior
- shell
execis hidden from the model but callable by catalog id when allowed - recursive code-mode
execandwaitare not callable from guest code - TypeScript input is transformed and evaluated without loading TypeScript on disabled or JavaScript-only paths
import,require, filesystem, network, and environment access fail- infinite loops time out and cannot block the Gateway
- memory cap failures terminate the guest VM
- output and snapshot caps are enforced for completed and suspended calls
waitresumes a suspended snapshot and returns the final value- expired, aborted, wrong-session, and unknown
runIdvalues fail - transcript replay and persistence preserve code-mode control calls
- transcript and telemetry show nested tool calls clearly
E2E test plan
Run these as integration or end-to-end tests when changing the runtime:- Start a Gateway with
tools.codeMode.enabled: false. - Send an agent turn with a small direct tool set.
- Assert the model-visible tools are unchanged.
- Restart with
tools.codeMode.enabled: true. - Send an agent turn with OpenClaw, plugin, MCP, and client test tools.
- Assert the model-visible tool list is exactly
exec,wait. - In
exec, readALL_TOOLSand assert the effective test tools are present. - In
exec, calltools.search,tools.describe, andtools.call. - Assert denied tools are absent and cannot be called by guessed id.
- Start a nested tool call that resolves after
execreturnswaiting. - Call
waitand assert the restored VM receives the tool result. - Assert the final answer contains output produced after restore.
- Assert timeout, abort, and snapshot expiry clean up runtime state.
- Export trajectory and assert nested calls are visible under the parent code-mode call.
pnpm check:docs.