Status: Accepted
The Code Mode engine must execute untrusted, LLM-generated JS/TS that calls
async host functions bridging to MCP tools. The realistic Rust options are
rquickjs (QuickJS-NG bindings), deno_core (raw V8), and boa (pure Rust).
A core product promise is a small, single, cross-platform binary with no heavy toolchain — so embedding cost matters as much as raw throughput.
Use rquickjs with the futures + macro features.
- Binary size & build: QuickJS adds ~1 MB and bundles its C source compiled
via
cc(no libclang/bindgen needed on common targets).deno_corepulls in thev8crate, producing 50–90 MB binaries with a heavy, cross-compile-hostile build — directly at odds with the project's goals. - Async bridging is first-class:
AsyncRuntime/AsyncContextplus theAsync/Promisedadapters convert Rust futures to JS promises and back, which is exactly theskarn.callTool(...)pattern we need. - Hard limits exist:
set_memory_limit,set_max_stack_size, and an interrupt handler (wall-clock deadline → uncatchable abort) cover the untrusted-execution requirements. - Startup: fresh contexts are cheap, which suits a per-execution isolate.
boa (pure Rust) remains an attractive portability escape hatch but is slower
and has weaker untrusted-execution controls today; it can return behind a feature
flag if a no-C-compiler target ever requires it.
- We get a tiny, statically-linkable, cross-compilable engine.
- We forgo V8's throughput, which is irrelevant for orchestration scripts whose latency is dominated by downstream tool calls, not JS execution.