Agent runtime
The seal agent runs inside a WebAssembly component, hosted by the seal daemon. That WASM envelope is a sandbox in its own right — independent of, and complementary to, the OS sandbox that wraps command_run subprocesses.
Two sandboxes, two boundaries
Section titled “Two sandboxes, two boundaries”| Sandbox | Wraps | Enforces |
|---|---|---|
| WASM (this page) | The agent loop itself. | The agent can only touch the world through a typed WIT interface. Zero direct syscalls. |
| OS | Every command the agent runs. | Subprocesses see only the paths and hosts the manifest declared. |
The WASM sandbox protects the host from the agent. The OS sandbox protects the host from the commands the agent spawns. The two layers compose: a command_run call leaves the WASM envelope through the WIT interface, hits the daemon, then enters the OS envelope around the subprocess.
Zero WASI imports
Section titled “Zero WASI imports”The agent compiles to a wasm32-wasip3 component. The critical decision: it imports zero WASI capabilities — no filesystem, no network, no process access, no clock beyond what the host explicitly provides. The only imports are custom seal:agent/* WIT interfaces:
world agent { import llm; // model-info, chat import tools; // file-read, file-write, file-delete, file-list, … import storage; // save, load, delete, list-keys (per-session) import console; // print, warn, ask
export init: func(session-id: string, project-context: string) -> result<_, string>; export handle-message: func(message: string) -> result<turn-result, string>;}In practice this means the agent cannot open a file, call connect, fork a process, read the clock past startup, or do anything outside the WIT surface above. Every operation the agent wants to perform — every tool the LLM decides to use — goes through a host-mediated function. The host checks the call against the manifest before executing.
What this gets you
Section titled “What this gets you”Prompt injection has nowhere to escalate. This is the main reason the agent runs in WASM. Tool results that the agent reads — file contents, command output, web fetches — can contain text crafted to manipulate the model into “do something malicious.” Without the WASM envelope, “do something malicious” means “the agent process tries to read ~/.ssh/, open a socket to attacker.example.com, fork a curl-pipe-sh.” With the WASM envelope, “do something malicious” means “the agent calls the WIT tools.file-read function with the path ~/.ssh/id_rsa” — which is a normal capability check, against the manifest, that fires a prompt or denies. The agent can’t bash on every door the OS would otherwise expose; the only doors that exist are the ones on the WIT surface.
The audit surface is bounded. Every interaction between the agent and the outside world is a WIT call. The daemon logs each one to the per-session audit log; you can reconstruct exactly what the agent did.
Capability checks are unbypassable. The capability layer (the permission model) runs in the host between the agent’s WIT call and the host’s syscall. The agent can’t reach around it.
What lives in the WASM sandbox today
Section titled “What lives in the WASM sandbox today”Just the agent loop — the part of seal that talks to the LLM, decides which tool to call, and dispatches that decision back through WIT. Everything else (the daemon RPC server, LLM backends, sandbox enforcement, the TUI itself) runs natively.
The split is:
| Crate | Target | Role |
|---|---|---|
seal-runtime | native | WASM host, OS sandbox, RPC server, LLM backends, crypto. |
seal-agent | wasm32-wasip3 | Agent loop, tool dispatch, session persistence. |
seal-cli | native | TUI, permission prompts, manifest signing. |
Future: hosting third-party code in the same envelope
Section titled “Future: hosting third-party code in the same envelope”The WASM sandbox is the same shape that MCP servers will run in once that ships. The plan is that an MCP server distributed as a WASM component lands in the same envelope — zero WASI imports, all interaction through a WIT interface — so the security guarantees the agent already has extend to anything Seal hosts.
The placeholder in the manifest schema for that future is [sandbox.wasm], currently empty. The OS-sandbox configuration lives under [sandbox.os], leaving room for the WASM-sandbox configuration to grow alongside it.
See also
Section titled “See also”- OS sandbox — the OS layer that wraps
command_run. - Permission model — what the capability check between WIT and the host does.