What "code runtime" means here
packages/code-runtime/code-runtime defines ctx.codeRuntime — the seam that runs one model-written program against host-provided async bindings. The defining contract (from the class doc): "Runtimes know nothing about tools or sessions; consumers own those concerns." A consumer (the tools registry, for "Code Mode") hands in a program source plus a set of binding namespaces, and the runtime executes it as a hostile peer — reporting program failures as result fields, never exceptions.
The seam is deliberately portable-identifier driven: a program written for one backend must be valid on every backend. Only 'typescript' has a published backend today, but 'python' is a first-class portability target, so identifier validation is the union of both languages' reserved words.
Package versions
| Package | Role |
|---|---|
@deepseek-ai/dsh-code-runtime | Service Definition (CodeRuntime, ctx.codeRuntime) |
@deepseek-ai/dsh-code-runtime-worker-thread | Provider: fresh worker thread per run (TypeScript) |
@deepseek-ai/dsh-e2b | Core: shared E2B sandbox owner (ctx.e2b) |
@deepseek-ai/dsh-fs-e2b | Provider: E2B filesystem backend for ctx.fs |
@deepseek-ai/dsh-subprocess-e2b | Provider: E2B process backend for ctx.subprocess |
@deepseek-ai/dsh-subprocess | Service Definition (SubprocessRuntime, ctx.subprocess) |
@deepseek-ai/dsh-subprocess-local | Provider: local OS-process spawn |
The seam definition
CodeRuntime (packages/code-runtime/code-runtime/src/index.ts):
export abstract class CodeRuntime extends Service {
abstract readonly language: string // 'typescript' | 'python' (informational)
abstract readonly isolation: string // 'worker-thread' | 'process' | 'container' (informational)
constructor(ctx: Context) { super(ctx, 'codeRuntime') }
abstract run(request: CodeRunRequest): Promise<CodeRunResult>
}run resolves a CodeRunResult — an error is a field on a resolved result, never a rejection. Only Service Definition contract misuse rejects. The portable-identifier contract is enforced through three shared sets:
RESERVED_BINDING_GLOBALS—{ console, __dsh_main__, __builtins__, __name__, __debug__ }: slots some backend owns; one shared set keeps a namespace list that is valid on one backend valid on all.RESERVED_ERROR_MEMBERS—{ name, message, stack, args, with_traceback, add_note }, plus any dunder form (__x__) refused wholesale.PORTABLE_RESERVED_WORDS— the union of ECMAScript reserved words and Python 3 keywords/soft keywords (lambda,match,type,_, …). Adding a new language means widening this union (a breaking review of existing binding names, by design).
The request/result shapes
CodeRunRequest carries everything the runtime acts on (explicit-over-implicit — no hidden ?? tuning knobs):
export interface CodeRunRequest {
program: string // runs as the body of an async function: top-level return/await legal
bindings: CodeBindingNamespace[] // host functions, one global object per namespace
signal?: AbortSignal // abort stops the program hard, even mid-loop
}A CodeBindingNamespace is { global, functions, errorClass? }: global must match the portable identifier subset [A-Za-z_][A-Za-z0-9_]* (a JS-only spelling like $tools is rejected by design); functions is a Record<string, CodeBindingFunction> mapping callable member names to functions (args: unknown) => Promise<CodeJsonValue>, where CodeJsonValue is a lossless JSON type; errorClass names a typed rejection constructor the runtime injects under name with a memberNameProperty.
CodeRunResult = optional value (the top-level return, if it crossed the lossless-JSON boundary), ordered logs: string[], and optional error. One of three taxonomy kinds:
export type CodeRunFailureKind =
| 'exception' // program threw or failed to parse/transform
| 'timeout' // an implementation budget expired
| 'abort' // the request signal fired
| 'worker-exit' // the substrate died without settling (e.g. OOM)
| 'invalid-output' // completion value was not lossless JSON
| 'output-limit' // serialized logs/value/diagnostic exceeded the capThe worker-thread provider
@deepseek-ai/dsh-code-runtime-worker-thread (packages/code-runtime/code-runtime-worker-thread/src/index.ts) is the only published backend. Its own doc is explicit about the trust model: "This is containment, not a security boundary: model code has bash-equivalent trust." It runs a fresh Worker per run, wrapping the program in async function __dsh_program__() { … } and stripping TypeScript types with the position-preserving native type-strip, bridging bindings over the worker's message port.
Config (every execution cap is declared in the provider's Config schema — changeable from cordis.yml):
| Key | Default | Meaning |
|---|---|---|
computeMs | — | busy-time budget: fails kind:'timeout' when the worker's measured event-loop active time (eventLoopUtilization) exceeds it. Metering measured busy time (not wall time) makes the budget fair (a program awaiting a slow tool accrues nothing) and ungameable. |
maxWallMs | — | wall-clock ceiling (backstop for promises nobody resolves), at most 2_147_483_647 (Node's max setTimeout delay). |
maxOutputBytes | — | hard cap for serialized log-array / value / failure-message payloads. |
maxOldGenerationSizeMb | — | worker max old-gen heap in MiB (resourceLimits); overflow kills the worker → kind:'worker-exit'. |
Runtime mechanics worth noting:
- Fresh worker per run isolates runs from one another, and termination also stops synchronous loops (
worker.terminate()). - The worker entry runs unbuilt from
src/worker.ts(erasable-only with type-only imports); the built package ships it as a sibling CommonJS bundle (lib/worker.cjs). - Inbound port traffic is re-validated and rebuilt field by field. The doc is blunt: the peer runs MODEL CODE and can post anything — so the compile-time
WorkerToHosttype means nothing and a forged extra field never rides along. - Bindings cross the port via
snapshotJsonValue; resolution values must be lossless JSON or the run failsinvalid-output. RESERVED_BINDING_GLOBALS/PORTABLE_RESERVED_WORDSare enforced at request time so a namespace list valid on this backend is valid on any future backend.
The worker→host wire protocol
packages/code-runtime/code-runtime-worker-thread/src/protocol.ts is a versionless, structured-clone protocol between co-shipped host and worker code. The direction of trust is asymmetric and stated explicitly: the host treats inbound traffic as hostile (model code can forge parentPort messages), so it re-validates and rebuilds every message; the worker trusts host replies. The host hands the worker WorkerBootData at spawn via workerData — the type-stripped program code, the binding namespaces to materialize (function bodies stay host-side), and the combined maxOutputBytes cap.
The message union (WorkerToHost):
| Message | Payload | Meaning |
|---|---|---|
call | { id, global, name, args } | one bridged binding call; the host answers each id at most once and ignores duplicates |
log | { text } | captured text, streamed eagerly so output survives a mid-run termination (timeout, abort, OOM) |
output-limit | — | worker-side capture or completion measurement exceeded the outer cap |
done | { value? / error? } | program settled; logs are not carried (they streamed already) |
The host answers a call with a ReplyMessage (ok: true + lossless value, or ok: false + message). Because budgets, aborts, and substrate death are observed host-side, done carries only program-exception / invalid-output / output-limit errors; timeout, abort, and worker-exit are classified by the host around the settled worker.
E2B: the remote sandboxing backend
packages/e2b/e2b owns one shared E2B sandbox (ctx.e2b) that both fundamental E2B providers share, so filesystem and process operations inhabit the same remote Linux runtime. Config:
| Key | Default | Meaning |
|---|---|---|
apiKey | $E2B_API_KEY | E2B API key; never forwarded into the sandbox |
cwd | /home/user/workspace | shared remote working directory, created before adapters receive the sandbox |
timeoutMs | 300_000 | sandbox lifetime; expiry always deletes the sandbox |
E2BRuntime exposes getSandbox() — creation begins at plugin construction; adapters await the same handle. It quotes args for the SDK's hard-coded /bin/bash -l -c layer (quoteE2BShellArg) and isolates the login shell behind a fresh randomized HOME (e2bControlEnvs). On disposal or timeout the sandbox is deleted.
The two E2B-backed providers are the same file-substrate pair under the E2B world:
fs-e2b(packages/e2b/fs-e2b) — implementsFileSystemover the remote sandbox filesystem, soctx.fsreads/writes become remote-Linux file operations andprocessPathreturns a remote in-sandbox path.subprocess-e2b(packages/e2b/subprocess-e2b) — implementsSubprocessRuntimeoverSandbox.command/PTY, mapping theCommandHandle/CommandResultvocabulary (output.ts,process.ts,environment.ts,remote.ts,terminal.ts).
Composing fs-e2b + subprocess-e2b gives one coherent remote execution world: a shell command's workdir path and a ctx.fs writeText target resolve against the same in-sandbox filesystem.
The subprocess service
packages/subprocess/subprocess defines ctx.subprocess — the seam the shell executors, the PTY backend, the LSP host, and the out-of-process subagent transports all spawn through. It is the substrate bash-local/bash-sandbox/terminal-bash build on (their env layering, output caps, and kill escalation all come from here).
SubprocessRuntime semantics (from packages/subprocess/subprocess/src/index.ts):
- One execution world shared with the mounted filesystem provider — executable paths and file paths agree.
spawnreturns immediately with aSubprocessHandle;doneresolves at process close with exit facts and rejects only for spawn-level failures.- Collect-mode readers are offset-based and non-consuming, so independent readers never consume one another's output; lossy reads report truncation and the spill file holding the complete stream.
terminate(and the spec's abort signal) escalates SIGTERM → grace → SIGKILL, tree-scoped on every platform — the only termination verb.- Piped stdio is handed to the caller raw, never buffered here.
- Disposal terminates all still-running managed processes and awaits their exit.
Environment hygiene: scrubbedParentEnv() is the canonical base every harness child starts from — it drops credential-shaped names (SENSITIVE_ENV_PATTERN = /KEY|PASSWORD|SECRET|TOKEN/i) and all ambient DSH_* names (matching DSH_ENV_PREFIX), so PATH/HOME/locale/proxies survive but harness identity never leaks implicitly. A deliberately supplied entry survives because explicit env layers merge after the scrub.
subprocess-local
@deepseek-ai/dsh-subprocess-local is the local OS-process provider (spawn.ts, terminal.ts, process-inspector.ts). Process coordinates (process-inspector) let it deliver tree-scoped PID-group termination. bash-local's LocalBashExecutor injects subprocess and hands it a fully-specified SubprocessSpawnSpec (argv, cwd, per-stream collect budgets, graceMs, signal, layered env).
Relationship to the sandbox
subprocess-localspawns unconfined OS processes; the bash layer decides policy.bash-localis bare, whilebash-sandboxwraps the same argv throughctx.sandbox(see Shell & Terminal and Sandbox Architecture).fs-sandboxfencesctx.fsmutations by the shared sandbox mode (see Filesystem and Filesystem Observation & Sandbox Policy).- E2B is itself a sandbox boundary — a remote, disposable Linux VM/container — so
subprocess-e2b/fs-e2bneed no local OS sandbox wrapper; the substrate is the containment.ctx.e2bis listed ascore(not a seam) indocs/capability-seams.md. code-runtime-worker-threadis containment, not a security boundary — the worker isolates, but the code carries bash-equivalent trust; prefer a sandboxed/E2B composition for truly untrusted programs.
Further reading
- Shell & Terminal —
bash-local/bash-sandboxasctx.subprocessconsumers. - Filesystem Tools & Policies —
fs-e2bas the remotectx.fsbackend. - Sandbox Architecture — the mode/enforcement story E2B participates in.
- Permissions & Approval — the escalation flow shared by the executors.
packages/code-runtime/code-runtime/src/index.ts— theCodeRuntimedefinition and portability contract.packages/subprocess/subprocess/src/index.ts— theSubprocessRuntimedefinition and scrub rules.