# Code Mode maintainer notes

> Code Mode implementation layout, the validation checklist, and the E2E test plan

- 网址：https://funcoding.ai/agents/openclaw/tools/code-mode/maintainers/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/tools/code-mode/maintainers

---
## Implementation layout

- config contract: `tools.codeMode`
- catalog builder: effective tools to compact entries and id map
- model-surface adapter: replace visible tools with control/direct tools
- executor contract: evaluate, continue, dispose
- Node executor: worker and VM context retained across waits
- QuickJS executor: WASM loading, evaluation, snapshot, restore, dispose
- worker supervisor: timeout, abort, crash isolation
- bridge adapter: JSON-safe host callbacks and result delivery
- continuation owner: TTL, capacity, run/session scoping, executor pinning
- trajectory projection for nested tool calls
- telemetry counters and diagnostics

The shared catalog and tool bridge retain policy ownership. Executors
own JavaScript execution and continuation state. Node's `node:vm` is trusted
execution, not a sandbox security boundary.

Rebuilding `before_tool_call` hooks must retain the surrounding execution
wrappers in their original order. Caller authority, cancellation, activity, and
run-lifetime checks enclose preparation and result finalization as well as the
tool body. Execution wrappers register their rebuild function when copying tool
metadata; schema-only copies preserve that registration.

Tool Search treats each published catalog entries array as an immutable descriptor
snapshot. Registration, restriction, and executor rebinding replace that array;
publish schema or description changes through the catalog owner. Search text is
rendered lazily once per snapshot, and warm searches reuse the content-addressed
lexical index. Visibility is checked on every search, including mutable permission
sets, and BM25 statistics use only that effective inventory. Cached lexical data
contains no tool executors.

## Validation checklist

Code mode coverage should prove:

- disabled config without an enabling override leaves existing tool exposure unchanged
- omitted `enabled`, including object config that sets other fields, stays
  disabled unless an agent or model override enables it
- per-model `true`, `false`, and unset values preserve activation precedence,
  fallback-model selection, and limits from the enclosing options
- enabled config exposes `exec`, `wait`, and only required direct-only tools to
  the model when tools are active for the run
- omitted executor selects Node; explicit QuickJS selects the bundled plugin,
  and unavailable executors fail without fallback
- explicit legacy `runtime: "quickjs-wasi"` migrates to `executor: "quickjs"`
- global and per-agent executor selection stays fixed through every `wait`
- raw no-tool runs, `disableTools`, and empty allowlists do not trigger
  code-mode payload enforcement
- every catalog-eligible effective non-MCP name has one callable winner
- direct-only tools stay model-visible and do not appear in `catalog`
- denied tools have no global or catalog handle
- bare globals, callable `catalog.search` results, `catalog.all`, and handle
  `describe()` work for OpenClaw and client tools without exposing exact ids
- `API.list("mcp")` and `API.read("mcp/<server>.d.ts")` expose TypeScript-style
  MCP declarations without a bridge/tool call
- MCP namespace `$api()` remains available as an inline fallback for schemas
- MCP namespace calls work for visible MCP tools with one object input, while
  search handles use the same namespace dispatcher and `catalog.all()` stays native
- Tool Search control tools are hidden from both the model surface and the
  hidden catalog
- nested calls preserve approval and hook behavior
- caught and uncaught nested failures remain recoverable without replaying
  previously executed side effects
- network-controlled failures retain untrusted-content wrapping and sanitization
- shell `exec` is hidden from the model but callable as a guest global when
  allowed
- recursive code-mode `exec` and `wait` are not callable from guest code
- executable cells accept plain JavaScript while typed discovery remains available
- TypeScript-only syntax and retired `language`/`typecheck` arguments fail before
  any nested tool dispatch
- intended guest APIs omit `import`, `require`, filesystem, network, and
  environment access; QuickJS isolation is tested separately from Node's
  programming constraints
- infinite loops time out and cannot block the Gateway
- executor memory failures terminate execution
- output caps apply to both executors; serialized snapshot caps apply to QuickJS
- `wait` resumes the executor continuation and returns the final value
- expired, aborted, wrong-session, and unknown `runId` values fail
- transcript replay and persistence preserve code-mode control calls
- transcript and telemetry show nested tool calls clearly

## E2E test plan

Run these against both executors when changing the runtime:

1. Start a Gateway with `tools.codeMode.enabled: false`.
2. Send an agent turn with a small direct tool set.
3. Assert the model-visible tools are unchanged.
4. Restart with `tools.codeMode.enabled: true`.
5. Send an agent turn with OpenClaw, plugin, MCP, and client test tools.
6. Assert the model-visible tool list is `exec`, `wait`, plus only configured
   direct-only tools.
7. In `exec`, call safe bare globals and assert normalized, reserved, and
   colliding names match the quick index.
8. Search `catalog`, inspect handle metadata/`describe()`, and call
   OpenClaw/plugin/client handles without observing exact ids.
9. In `exec`, call `API.list("mcp")` and `API.read("mcp/<server>.d.ts")` and
   assert the declaration files describe visible MCP tools.
10. In `exec`, search by task intent across native and MCP tools, inspect the
    MCP handle's declaration, and call it. Verify normalized name collisions,
    exact namespaced lookup, bounded remote metadata, and the untrusted output
    wrapper. Direct `MCP.<server>.<tool>({ ...input })` calls must agree, and
    `catalog.all()` must remain native after search.
11. Assert denied tools are absent and cannot be called by guessed id.
12. Start a nested tool call that resolves after `exec` returns `waiting`.
13. Call `wait` and assert the continued context receives the tool result.
14. Assert the final answer contains output produced after resume without replay.
15. Assert timeout, abort, and continuation expiry clean up runtime state.
16. Export trajectory and assert nested calls are visible under the parent
    code-mode call.

Docs-only changes to this page should still run `pnpm check:docs`.
