with one click
iii-sandbox
Ephemeral microVM sandboxes for running untrusted or agent-generated code in isolation — a one-call run path, a create/exec/stop lifecycle, and a set of filesystem operations.
Ephemeral microVM sandboxes for running untrusted or agent-generated code in isolation — a one-call run path, a create/exec/stop lifecycle, and a set of filesystem operations.
Expose registered functions as HTTP endpoints via an `http` trigger, with a preHandler middleware chain for auth, rate limiting, and logging. Reach for it to serve REST without standing up a separate web server.
Connect this engine to another iii engine over a long-lived WebSocket so functions call across the boundary. Wire stable ids with `forward:`/`expose:`; `bridge.invoke` is the ad-hoc escape hatch.
Schedule any registered function on a 6- or 7-field cron expression, with once-only execution across a fleet when backed by the redis adapter. Its whole surface is the `cron` trigger type.
WebSocket-routed worker mesh — the engine's Function/Trigger/Worker model and the iii-sdk surface for authoring them. Teaches the ordered way to gain a capability before writing code — (1) check functions already registered in the engine, (2) search the public registry via iii-directory, (3) build a worker. Single self-contained skill — meant for system-prompt injection; do not re-fetch.
OpenTelemetry-backed tracing, structured logs, metrics with rollups, alerts, sampling, and baggage for the engine — emit and query telemetry through `engine::*` functions and react to logs with a `log` trigger.
Fire-and-forget topic pub/sub: broadcast an event with `publish` and every matching `subscribe` trigger receives it. Use for real-time notifications where missed events are acceptable.
| name | iii-sandbox |
| description | Ephemeral microVM sandboxes for running untrusted or agent-generated code in isolation — a one-call run path, a create/exec/stop lifecycle, and a set of filesystem operations. |
The iii-sandbox worker boots ephemeral libkrun microVMs and runs code inside them, isolated from the host. Each sandbox boots in a few hundred milliseconds, runs commands or file operations scoped to the engine it lives on, and is reaped when idle; the overlay filesystem is discarded on stop. Its sandbox::* functions are called like any other iii function.
There are two ways in. sandbox::run is the fast path: it boots a VM, runs a code snippet, captures stdout/stderr, and tears the VM down in a single call. For multi-step work — several commands, multiple files, or inspecting a VM between steps — use the sandbox::create → sandbox::exec / sandbox::fs::* → sandbox::stop lifecycle and carry the returned sandbox id across calls.
Prerequisites: the worker is enabled by adding iii-sandbox to config.yaml, and the host needs hardware virtualization (Apple Silicon, or /dev/kvm on Linux) — Intel Macs and Windows cannot boot sandboxes.
This page tells you WHEN and HOW to use the sandbox; the engine is the source of truth for every function's exact arguments and responses. Before you call any sandbox::* function, fetch its contract and build your payload from that — do not guess field names, types, or formats from memory:
engine::functions::info { function_id: "sandbox::<fn>" }
(e.g. { function_id: "sandbox::fs::write" }). The returned schema is authoritative; this skill never restates it.
To author an iii worker (read the iii skill first), you write the worker code into the sandbox, install its deps, and run it as a process there — but the worker must still join the HOST engine bus to be useful.
sandbox::create contract — fetch it), AND set the worker's engine-URL env (III_ENGINE_URL, e.g. ws://localhost:49134) IN THE sandbox::create env — NOT later at exec/run time. The localhost→host rewrite happens ONLY for the create-time env: a localhost / 127.0.0.1 engine URL set there is rewritten to the per-sandbox gateway so the worker reaches the host bus. The same localhost URL passed at sandbox::exec time is NOT rewritten — it points at the sandbox's own loopback, the worker silently fails to connect, and you will waste turns debugging TCP. So: put the engine URL in the create env; the worker process inherits it already rewritten.exec: starting the worker with sandbox::exec "node index.mjs" blocks and times out (S200 exec timed out), because the process never returns. Launch it detached (… &, nohup, or sandbox::run shell mode) so the exec call returns while the worker keeps running — see the serialized-exec boundary below.engine::functions::list and any http trigger it binds is served by the iii-http worker; verify endpoints with web::fetch, not curl.worker::add, see the iii skill) instead of hosting it in a sandbox.sandbox::run.http trigger is served by the iii-http worker) — do NOT start a server process (express, http.createServer, a framework listen()) inside the sandbox. A server you start here is not routed by iii, is unreachable as an iii endpoint, and as a foreground process hangs the exec slot until it times out. If the task is "build an iii worker," the deliverable is registered functions plus a trigger, not a running server.iii-state for persistence.node, python, or an operator-registered custom image), never arbitrary OCI references. Discover the live set with sandbox::catalog::list; an unknown name fails fast.sandbox::exec runs one command at a time per sandbox (serialized). A concurrent call is rejected, and waiting does NOT free the slot when the in-flight command is long-running or foreground (a server, npm install, a build) — it holds the slot until it exits. Run those in the background, or use sandbox::run in shell mode, or recover by replacing the sandbox (sandbox::stop then sandbox::create).sandbox::exec is not a shell — for pipes, &&, redirects, or variable expansion use sandbox::run in shell mode, or wrap the command in sh -c.engine::functions::info on sandbox::create for how to enable it.A map of what exists. For the arguments and response of any one, call engine::functions::info { function_id: "<id>" }.
sandbox::run — boot a VM, run a code snippet, capture output, and auto-stop, in one call.sandbox::create — boot a microVM you then drive with the lifecycle ops; returns the id every other op uses.sandbox::exec — run a single command inside a running sandbox.sandbox::stop — destroy a sandbox and reclaim its resources.sandbox::list — enumerate sandboxes currently running on this engine.sandbox::catalog::list — list bootable image names (bundled presets plus operator custom images).sandbox::fs::write — write a file into a sandbox.sandbox::fs::read — read a file out of a sandbox.sandbox::fs::ls — list the entries of a directory.sandbox::fs::stat — read metadata for a single path.sandbox::fs::mkdir — create a directory.sandbox::fs::rm — remove a file or directory.sandbox::fs::mv — move or rename a path.sandbox::fs::chmod — change a path's permissions (and optionally owner).sandbox::fs::grep — recursive regex search across files.sandbox::fs::sed — regex find-and-replace across files.Every error comes back structured with a machine-readable hint describing how to fix it — read it and apply the fix before retrying, rather than re-sending the same call.