Skip to content

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.

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.

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.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.md

code 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 verify checks it in the docs lane, and the pressure that creates is deliberate, since anything longer belongs on the pages an entry points at.
  • Point code at roots that exist. A stale path fails the same lane.

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