API Reference
Host API
Last updated 2026-04-14
Host API
This document describes the current host boundary and the near-term rules the runtime is expected to preserve as it grows.
Structured Host Values
Allowed values:
undefinednull- booleans
- strings
- numbers, including
NaN,Infinity, and-0 - arrays of allowed values, including sparse arrays with preserved hole positions up to 1,000,000 elements
- plain objects with string keys and allowed values
Rejected values:
- functions
- symbols
- guest
BigIntvalues and host bigints MapandSet- proxies and other trap-bearing wrapper objects
- cycles
- guest-exported arrays or plain objects with shared references
- class instances
- boxed primitives,
RegExp, guestErrorobjects, and other built-in objects - accessors
- custom prototypes
- host objects
Guest Map and Set values are runtime-internal heap objects. They may appear
inside guest execution, snapshots, and guest-visible data structures, but they
do not cross the structured host boundary in either addon mode or sidecar mode.
Guest BigInt values now follow the same rule: they are available inside guest
execution and snapshots, but results, inputs, capability arguments, and resume
payloads still reject them at the structured boundary.
Structured host-boundary traversal is depth-limited and fails closed with a
typed error instead of recursing until the JS or Rust stack overflows.
Structured values are trees, not identity graphs. Guest results and suspended
capability arguments therefore fail closed on shared guest arrays or plain
objects instead of alias-expanding them during export.
Boundary-decoded plain objects may use shared internal shape-backed storage for
faster repeated static property reads, but mutation and unsupported accesses
still fall back to the same plain-object semantics documented here.
Capability Calls
- Capabilities are named host functions.
- Capability lookup is explicit.
- The core runtime represents capability calls as suspension points.
- In synchronous guest code, a capability call suspends immediately.
- In async guest code, a capability call produces an internal guest promise, queues the host request, and suspends at the next runtime checkpoint.
start()returns a suspension object containing the capability name, the converted arguments, and a resumable snapshot. In the current addon path, that live snapshot stays in a process-local opaque native handle until the host asks forprogress.snapshotorProgress.dump(). The dumped addon snapshot still excludes immutable compiled-program bytes and stays bound to the originating program identity instead.- Snapshots loaded from bytes must be rebound to explicit host policy before their capability metadata is trusted or resume is allowed to continue.
- Raw native snapshot restore also requires a
limitsfield plussnapshot_id,snapshot_key_base64,snapshot_key_digest, and matchingsnapshot_tokeninside the snapshot policy JSON. The current addon wrapper keeps livestart()/run()/resume()traffic on opaque snapshot handles, while raw byte restore still usesinspectDetachedSnapshot(program, snapshot, ...)/resumeDetachedProgram(program, snapshot, ...), and legacy self-contained snapshots still work throughinspectSnapshot(...)/resumeProgram(...). In the raw-restore path, the token is the HMAC-SHA256 of the detachedsnapshot_idunder the caller-chosen snapshot key, and restore recomputessnapshot_idfrom the raw snapshot bytes before inspection or resume. Those fields bind raw restore to trusted detached dump metadata, but hosts still need ordinary integrity controls when storing or transporting snapshots. Passing{}is the explicit way to request default runtime limits during raw restore. resume()accepts either a structured success value or a sanitized host error payload. Raw native and sidecar resume transport also accepts an explicitcancelledpayload shape for host-driven cancellation.Progress.cancel()injects an explicit cooperative cancellation failure into a suspended execution instead of resuming it with a host value.- The Node wrapper accepts sync JavaScript capability functions and real
Promise-returning async handlers; it does not adopt arbitrary thenables or proxy-backed handler registries. - The Node wrapper also exposes an
ExecutionContexthelper that caches a validated capability map, limits object, and snapshot key for repeatedrun()/start()/Progress.load()calls. run()andstart()accept an optionalAbortSignal, andresume()/resumeError()accept an optional{ signal }object for the resumed compute segment.limits.maxOutstandingHostCallsbounds the combined number of queued and currently suspended host requests for async guest execution.- Hosts restoring dumped progress must provide either an
ExecutionContextor explicitcapabilitiesorconsole, explicitlimits, and the samesnapshotKeyonProgress.load(...), even in the same process.
Error Sanitization
Host failures cross the boundary with:
namemessage- optional
code - optional
details
Resumed host failures re-enter guest execution as guest-visible error objects
using those fields. Guest try / catch can inspect name, message,
optional code, and optional details, and uncaught failures render with the
same guest-safe summary.
The Node wrapper only trusts own data properties for those fields. Inherited
getters, proxy traps, coercion hooks, and accessor-backed details fail closed
instead of executing during host-error sanitization. If name or message are
missing, the sanitized fallback is Error plus an empty message. code is
accepted only as an own string data property; missing or non-string code
values are dropped instead of being coerced.
The Node wrapper rethrows core failures as typed JavaScript errors:
MustardParseError, MustardValidationError, MustardRuntimeError,
MustardLimitError, and MustardSerializationError. The original native error is
preserved as the JavaScript cause.
When those failures resume into guest execution, the runtime also renders a
guest-only traceback with guest function names and source spans.
Console Contract
- A
consoleglobal object exists so the global name is reserved. console.log,console.warn, andconsole.errorare exposed only when the host provides the matching callback explicitly.- Console callbacks receive the same structured guest values as ordinary host capabilities.
- Guest-visible console calls always evaluate to
undefined, regardless of what the host callback returns. - If the host does not provide a callback, the corresponding console method is absent and guest calls fail as ordinary guest runtime errors.
Reentrancy
- Execution is single-threaded and non-reentrant.
- The Node
Progresswrapper is single-use and rejects repeatedresume()/resumeError()calls for the same suspended snapshot. Progress.load(...)also rejects already-consumed same-process dumps before exposing authoritativeprogress.capability/progress.args, so stale blobs cannot be replayed into duplicated side effects after the real resume already happened.- Consumed progress tokens stay burned for the lifetime of the current process,
including across
worker_threadsand duplicate physical package/addon copies in the same PID, so unrelated same-process progress churn cannot make an old dumped snapshot replayable again. Progress.dump()includes detachedsnapshot_id,snapshot_key_digest, andtokenmetadata authenticated by the configuredsnapshotKey. Current addon dumps also carry detachedprogrambytes plusprogram_id, alongside an authenticated suspended-manifest blob for capability metadata, andProgress.load()verifies that bundle, applies the explicit restore policy once when it rebuilds a live native snapshot handle, and only falls back to legacy snapshot inspection when the authenticated suspended manifest is absent.- In the Node wrapper,
Progress.load(...)always requires the host to reassert either anExecutionContextor explicitcapabilitiesorconsole, explicitlimits, and the originalsnapshotKeybefore it exposes authoritativeprogress.capability/progress.args. limitsmust be present as a plain object even when the caller intentionally wants default limits and therefore passes{}.- Hosts must not attempt to run nested guest execution on the same runtime
state while another
run(),start(), orresume()is active.
Cancellation and Abort Propagation
- The Rust core now exposes a pollable cooperative cancellation token and checks
it before each instruction dispatch, before idle microtask or queued-host-call
checkpoints, on every
resume()entry, and inside long-running native helper loops such asArray.prototype.sort()andObject.keys(). - Cancellation fails as a top-level guest-safe limit error with the message
execution cancelled. It is host authority, not guest control flow, so guesttry/catchdoes not intercept it. - In the Node wrapper, hosts use
AbortSignalto cancel active compute segments andProgress.cancel()to abort a currently suspended execution. - Already-aborted
AbortSignals fail closed before Node starts structured host boundary traversal, so cancellation does not depend on first scanning large host payloads. - Cancelling a suspended async host wait stops guest execution immediately, but it does not force-stop the host promise or capability handler that was already started.
- The in-process addon still runs on the Node main thread, so a same-thread
AbortSignalcannot preempt synchronous guest compute until control returns to the event loop. Hosts that need stronger kill guarantees should still use sidecar mode plus OS-level termination controls. - Cancellation handles are runtime-only state. Serialized snapshots do not preserve them, so hosts resuming a loaded snapshot must provide a fresh cancellation signal or token if they want later compute to remain cancellable.
- The native addon keeps cancellation token ids process-local and unguessable; guessed ids fail closed instead of cancelling unrelated executions.