Tools
Code Mode executors
Code Mode uses Node by default when enabled. Select QuickJS when you
need a hardened guest runtime. Both executors run the same plain JavaScript
cells, expose the same typed tool discovery, and use the same exec and wait
tools. Code Mode itself remains off by default.
Choose an executor
| Executor | Intended use | Execution | Suspended state |
|---|---|---|---|
node (default) |
Trusted execution on your Gateway host | Node.js node:vm in a worker thread |
A live worker and JavaScript context |
quickjs |
Hardened guest isolation | QuickJS-WASI in a worker thread, supplied by the bundled executor plugin | A serialized VM snapshot |
The intended guest API does not expose Node's filesystem, networking, process,
environment, or module-loading APIs. Module guards and a small set of globals
help keep cells focused on tool orchestration; they do not make node:vm safe
for hostile JavaScript. Use QuickJS when guest isolation is part of your threat
model, and use a separate OS user, container, or host when you need a stronger
host boundary.
QuickJS provides a separate WASM guest with no ambient host access. It can still call powerful tools if your tool policy grants them. Calls made through the Code Mode tool bridge retain OpenClaw's normal policy, approvals, hooks, and session ownership under either executor. These checks mediate tool calls; they cannot contain hostile code that escapes a Node VM context.
Set the executor
In the web interface, open Settings → Agents & Tools → Labs and use Code Mode executor to choose Node.js (default) or QuickJS (isolated). Activation and executor selection are separate: choosing an executor does not enable Code Mode.
To enable Code Mode with the default Node executor:
{ tools: { codeMode: { enabled: true, executor: "node", }, },}For hardened guest isolation, set executor: "quickjs" in the same object.
The bundled plugin ID is code-mode-quickjs; selecting its executor needs no
separate plugin enable step. Explicit executor selection activates this bundled
runtime even when plugins.enabled is false or a restrictive plugins.allow
list omits it. It does not enable other plugins. An explicit plugins.deny
entry or plugins.entries.code-mode-quickjs.enabled: false still blocks it.
An external plugin can supply the quickjs executor choice and remains subject
to the full plugin activation policy. Enable exactly one owner for that choice.
The selectable executor IDs are node and quickjs; node is owned by core.
The selected executor must be available. If it is missing, disabled, denied,
or cannot load, the run fails with runtime_unavailable; OpenClaw never
silently switches to Node or broad direct tool exposure. Check plugin policy
when a configured QuickJS executor is unavailable.
Set agents.entries.<agent>.tools.codeMode.executor to override the global
selection for one agent. An agent that omits it inherits the global choice.
See Code Mode configuration for activation
precedence and limits.
Understand waits and limits
Each cell keeps its selected executor for its entire lifetime, including every
wait. Changing configuration affects new cells; it does not move suspended
JavaScript between engines or replay completed tool calls.
Node retains its live worker context while suspended. QuickJS can release its
worker after serializing the guest and restore the snapshot for wait. Both
continuations are transient: completion, failure, cancellation, expiry, or
Gateway shutdown releases them. Neither survives a Gateway restart.
timeoutMs, output limits, pending-call limits, suspended-run capacity, and
snapshotTtlSeconds apply to both executors. The historical
snapshotTtlSeconds name also controls Node's suspended-context lifetime.
QuickJS additionally checks serialized VM state against maxSnapshotBytes.
Node has no serialized VM snapshot, so that setting does not bound its live
heap. Saved JSON results retain their shared memory/snapshot data allowance.
memoryLimitBytes limits QuickJS guest memory. For Node, it configures a
best-effort V8 worker heap budget across the old and young generations, subject
to engine minimums. That budget includes worker runtime allocations and
excludes external buffers; it is not a per-context heap measurement or security
boundary. Neither executor's
setting caps total Gateway RSS. Worker overhead and host-side tool results also
consume memory. A retained Node context can use more total host memory than a
size-limited QuickJS snapshot. The shared limit of 64 suspended cells and
reserved resume slots still applies; there is no separate global memory quota. See
Code Mode internals
for state ownership and retention.
Upgrade an existing configuration
Doctor and eligible Gateway startup migrations replace an explicit
runtime: "quickjs-wasi" with executor: "quickjs", preserving that explicit
choice. An existing executor setting takes precedence when both fields are
present. Activation and other limits remain unchanged.
The migrated explicit QuickJS choice also works when generic plugins are
disabled or allowlisted, without enabling unrelated plugins. An explicit denial
of code-mode-quickjs still prevents execution.
Configurations that did not explicitly select a runtime use the new Node
default. Set executor: "quickjs" explicitly to retain hardened guest
isolation. The retired runtime field is not a runtime alias; use
openclaw doctor --fix for an older configuration.