Architecture
Model-written JavaScript runs here in a V8 isolate, inside a supervised child process, under bounds the program cannot reach. The threat model states which boundaries this code enforces, which attack classes are out of scope, and which controls belong to whoever runs it.
Path of one execution
Section titled “Path of one execution”A request reaches an executor in the host’s own process, waits in the pool’s queue when every worker is busy, and runs in a fresh V8 isolate inside a child process. Its result returns along the same path, and the isolate is disposed. Internals walks those layers with a diagram of the boundary at the isolate and the boundary at the process, and the executor protocol specifies the contract each of them implements. Where a deployment puts a socket in front of the pool, the operator guide covers the daemon that composes it, and a host wanting that daemon inside its own process imports it as a library.
Runtime capability doctrine
Section titled “Runtime capability doctrine”These rules govern the inside of the isolate: what exists there, what it is made of, and what this product may promise about it. Module design states the rules shaping the modules that implement them.
- Start the sandbox global empty, and let every capability arrive as an explicit, tested addition with a place in the allowlist. Subtraction is proven complete only by enumerating a surface nobody has ever fully enumerated.
- Target ECMA-429, the minimum common web API, and follow the standard governing each interface. Every divergence is a row in Runtime deviations, and the differential suite proves compatibility with the dialect.
- Choose the thinnest material that provides a capability: a reference implementation of the specification where pure JavaScript suffices, a thin in-sandbox facade where the specification is thin, a host bridge only where a real privilege is needed. Only the last of those three hands the isolate something it did not have.
- Keep the environment uniform. Capability sources are emitted unconditionally, never gated on what the submitted code appears to use, so two programs using the same capability get the same runtime however each was written.
- Write no extensive instructions for the model. Familiar code works because the runtime is standard, and where the runtime diverges a pinned error names the replacement at the moment the model touches the name.
- Report what the entry reported. A promise rejected with no handler never replaces the outcome of a run and never fails an unrelated call, because the call that happened to be running when it surfaced is not the run.
- Run every execution in a fresh isolate. But across executions only the standard library is cached, serialized once per process into a V8 startup snapshot that every isolate is restored from. Retire a long-lived child process after a bounded number of executions.
- Default concurrency inside a child to one execution, so a native crash kills exactly the culprit. The pool bounds total concurrency and the queue applies backpressure above it.
- Treat the memory limit inside the engine as soft, because isolated-vm documents it as a guideline and not a strict bound. A process-level memory watch and the container’s own limit are the hard backstop.
- Treat the protocol and the executor semantics as the product contract, never the sandbox implementation. The runtime is swappable inside one package, and the differential suite proves the outside unchanged.
Primitives map
Section titled “Primitives map”primitives.yaml next to this page is a machine-readable inventory of the kinds of thing this system is made of. Every entry names a primitive, places it in a group, and points at the code implementing it:
- id: isolate-lifecycle group: sandbox name: Isolate lifecycle summary: 'Creates a V8 context through isolated-vm, from a startup snapshot when given one, and disposes it on settlement.' code: - packages/executor/src/sandbox/isolate.ts docs: - ./index.mdcode resolves from the repository root and docs from the directory of primitives.yaml, and the docs lane checks both. Invariants sit apart from the primitives, because an invariant is not owned by a directory: it holds across the whole system.
An inventory of kinds holds still while features move, and it tells a reader who has never opened the tree what kinds of thing exist here. These rules keep it an inventory of kinds:
- Add an entry when its code enters the tree, never before. A planned primitive is not a primitive.
- Edit an entry when the thing appears, disappears, or changes meaning. Nothing else is a reason to touch the file.
- Never record history. The map has no room for what was renamed, split, deprecated or shipped.
- Keep every summary to one line inside the cap.
pnpm verifychecks it in the docs lane, and the pressure that creates is deliberate, since anything longer belongs on the pages an entry points at. - Point
codeat roots that exist. A stale path fails the same lane.
Where each concept lives in code
Section titled “Where each concept lives in code”pnpm verify checks every path below against the tree, so a file that moves without its row here turns the gate red. No lane reads the left column. A behaviour and its row change in the same commit, and review is the only check on that.
| Concept | Code and pages |
|---|---|
Wire protocol, the native Executor contract and its specification |
packages/protocol/src/protocol.ts, the executor protocol |
| Provider name rules and the reserved sets | packages/protocol/src/provider-name.ts |
Typed error taxonomy carried by code across boundaries |
packages/protocol/src/errors.ts |
| Binary-safe dispatch codec | packages/protocol/src/codec.ts, packages/executor/src/sandbox/codec.ts |
| Native remote executor, session rotation and reconnect | packages/cloudflare-codemode/src/remote-executor.ts, packages/cloudflare-codemode/src/session.ts |
| Codemode dialect adapter, one facade over both transports | packages/cloudflare-codemode/src/codemode-executor.ts |
| Execution planning of the dialect’s providers and connectors | packages/cloudflare-codemode/src/execution-plan.ts |
| Raw model output normalized into the entry contract form | packages/cloudflare-codemode/src/normalize.ts |
| Tool name sanitizing of the dialect | packages/cloudflare-codemode/src/tool-name.ts |
| Native in-process executor over the pool | packages/executor/src/executor/isolate-executor.ts |
| Caller-side result capping | packages/executor/src/executor/result-limiter.ts |
| Pool composition, admission and dispatch | packages/executor/src/pool/pool.ts |
| Bounded queue and per-worker load accounting | packages/executor/src/pool/queue.ts |
| Child supervision, spawn, heartbeat and crash handling | packages/executor/src/pool/supervisor.ts |
| Child process entry point | packages/executor/src/pool/child-entry.ts |
| IPC transport and the parent-to-child contract | packages/executor/src/pool/ipc-transport.ts, packages/executor/src/pool/protocol.ts |
| Worker retirement and drain rules | packages/executor/src/pool/lifecycle.ts |
| Published pool events and the OpenTelemetry API attachment | packages/executor/src/pool/events.ts, packages/executor/src/pool/instrumentation.ts |
| Sandbox composition, one execution end to end | packages/executor/src/sandbox/sandbox.ts |
| Isolate creation and disposal | packages/executor/src/sandbox/isolate.ts |
| Installed capabilities | packages/executor/src/sandbox/console.ts, packages/executor/src/sandbox/timers.ts, packages/executor/src/sandbox/fetch.ts, packages/executor/src/sandbox/runtime.ts |
| Standard library the sandbox installs, one module per governing standard | packages/executor/src/sandbox/runtime/ |
| Web IDL binding every interface passes through | packages/executor/src/sandbox/runtime/webidl.ts, packages/executor/src/sandbox/runtime/converters.ts |
| Where the standard library diverges from the standard that governs it | Runtime deviations |
| Generated runtime bundle and its generator | packages/executor/src/sandbox/runtime-bundle.generated.ts, tools/executor/generate-runtime-bundle.ts |
| Module linking, import lifting and the CommonJS wrapper | packages/executor/src/sandbox/modules.ts, packages/protocol/src/imports.ts, packages/executor/src/sandbox/cjs.ts |
| Which module a specifier names, for the linker and for require alike | packages/executor/src/sandbox/resolver.ts |
| Tool dispatch bridge and the provider proxies the model calls | packages/executor/src/sandbox/dispatch.ts, packages/executor/src/sandbox/proxy-source.ts |
| Timeout layering across the synchronous and asynchronous phases | packages/executor/src/sandbox/timeout.ts |
| Retained executions and the handles a host invokes | packages/executor/src/sandbox/handles.ts |
| Webcrypto operations performed on the host | packages/executor/src/sandbox/crypto.ts |
| WebSocket listener and connection policy | packages/executor/src/server/listener.ts |
| Per-execution bridge between the caller session and the pool | packages/executor/src/server/bridge.ts |
| Liveness and readiness probes and the metrics scrape | packages/executor/src/server/probes.ts |
| Connection metrics and the per-identity request span | packages/executor/src/server/instrumentation.ts |
| Span settling shared by the pool and the server | packages/executor/src/spans.ts |
| Daemon command line, its settings and their provenance | apps/daemon/src/cli |
| Admin app and the client the command line calls it with | apps/daemon/src/admin.ts |
| Sandbox check, one real job end to end | apps/daemon/src/check.ts |
| Daemon composition, lifecycle events and the process entry | apps/daemon/src/daemon.ts, apps/daemon/src/bin.ts |
| Telemetry and logging composed for the daemon | apps/daemon/src/telemetry.ts, apps/daemon/src/logger.ts |
| Container image and the manifests that run it | apps/daemon/Dockerfile, deploy |
| Differential compatibility suite and its reference harness | apps/executor-testbed/src/compatibility, apps/executor-testbed/src/reference |
| Property suite and the latency benchmark of the two run bounds | apps/executor-benchmark/src, the benchmark |
| Quality gate and repository scripts | tools/ci/verify.ts, Tooling |