Skip to main content

site-architecture

Capsem system architecture: service, per-VM processes, CLI, guest agent, vsock, network proxy. Use when you need the design to write, review, or debug across components.

Source facts

Repository
google/capsem
Last source activity
September 25, 2026 at 00:49
Detected SKILL.md language
English
Stars
79
Forks
15

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
6 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
site-architecture
description
Capsem system architecture: service, per-VM processes, CLI, guest agent, vsock, network proxy. Use when you need the design to write, review, or debug across components.
# Capsem Architecture ## System overview Capsem sandboxes AI agents in air-gapped Linux VMs on macOS using Apple's Virtualization.framework (with a KVM backend for Linux). It runs as a daemon service (like Docker). The system has these layers: **Host-side:** - **capsem-service** (daemon): always-running background service. Axum HTTP server over Unix Domain Socket (`~/.capsem/run/service.sock`). Manages VM lifecycle, routes API calls to per-VM processes. It is the only client of a VM owner: container setup (service-owned OCI pull and staging), exposures (`/vms/{id}/exposures`, admitted by the owner as `network.lifecycle` events), and the `capsem.stream.v1` WebSocket at `/vms/{id}/stream` (terminal, streaming exec, container attach) all translate to typed owner IPC here; CLI, TUI, web and SDKs never dial a per-VM socket. - **capsem-process** (per-VM): one process per sandbox. Boots the VM, bridges vsock connections (terminal + control), manages structured jobs (exec, file I/O) via a job store. - **capsem** (CLI): user-facing CLI. Sessions are created from profiles and named by the service (`<profile-id>-N` unless the user supplies a name). `capsem shell` opens the TUI/session picker, creates or attaches through the service, and talks to capsem-service over UDS HTTP. User-facing copy says sessions; implementation/debug output may say VM when describing the virtualization layer. - **@capsem/mcp** (npm MCP server): separately installed stdio server for AI agents. Uses the TypeScript SDK and an explicit gateway URL/token; it has no UDS, VM-runtime, or virtualization access. - **capsem-gateway** (HTTP gateway): TCP-to-UDS reverse proxy (default port 19222). Bearer token auth, CORS, 10MB body limit. Provides an explicit route table plus `/status` (cached 1s) and `/vms/{id}/stream` (authenticated `capsem.stream.v1` WebSocket upgrade tunneled unchanged to the service, which translates it to typed VM-owner IPC). Unknown routes return 404; the frontend and tray app connect through the gateway. Writes runtime files to `~/.capsem/run/` (gateway.token, gateway.port, gateway.pid). - **capsem-app** (Tauri GUI): thin webview shell. Connects to gateway at `http://127.0.0.1:19222`. No VM logic, no capsem-core dependency. Only 2 IPC commands: `open_url` (opens URL in system browser) and `check_for_app_update` (Tauri updater). Bundles `web/app/dist` so the app can render the service-unavailable screen when gateway is unreachable. - **capsem-tray** (system tray): menu-bar companion process. Polls the gateway for VM status, shows running/stopped counts, and provides quick actions (open dashboard, quit). Non-standalone: refuses to run without `--parent-pid` pointing at a live capsem-service, acquires a system-wide singleton lock at `~/.capsem/run/tray.lock` (only one tray ever in the menu bar), and self-exits within 500ms when its parent dies. Contract enforced by `capsem-guard` on the companion side, not the spawner. - **capsem-guard** (shared library): parent-watch + singleton primitives used by capsem-tray and capsem-gateway. Provides `watch_parent_or_exit`, `Singleton::try_acquire`, and the umbrella `install(parent_pid, lock_path)`. Guarantees companions die with their parent and can't run standalone or as multiple instances -- closes the orphan-accumulation class of bug that `kill_on_drop(true)` alone cannot cover under SIGKILL/OOM/test-harness termination. See `/dev-rust-patterns` lesson 18. **Guest-side:** - **capsem-init** (`capsem-init`): PID 1, sets up air-gapped networking, mounts filesystems, deploys guest binaries, launches daemons, writes boot timing JSONL - **capsem-pty-agent** (`capsem-pty-agent`): main guest agent -- PTY bridge, control channel, exec, file I/O, shutdown handler (see "Guest agent architecture" below) - **capsem-tun** (`capsem-tun`): guest end of a network cable. One tap per attached network, MAC `capsem_proto::privatelink::mac_of(address)`, MTU 65521, pumping ethernet frames as u16-framed records over that cable's own vsock:5009 connection. The VM owner holds each cable's stream and hands a duplicate to that network's switch on `plug()`. A wire, not a stack: it parses nothing, and every protocol crosses it. - **capsem-sysutil** (`capsem-sysutil`): guest suspend helper. Opens its own vsock:5004 connection independently of the agent, so suspend works even if the agent is hung. Symlinked by capsem-init only to `/usr/local/bin/suspend`; in-VM shutdown commands are disabled. - **capsem-net-proxy** (`capsem-net-proxy`): redirects HTTPS traffic to host MITM proxy via vsock - **capsem-mcp-server** (`capsem-mcp-server`): guest MCP stdio-to-framed-vsock relay for tool calls to the host MITM MCP endpoint ## Reference routing - Read `references/service-and-guest-protocols.md` before changing the service/process topology, CLI or MCP execution paths, gateway/service routes, host IPC, vsock framing or ports, or any guest agent binary. - Read `references/storage-network-and-lifecycle.md` before changing VM storage or forks, network interception, security or logger ownership, ephemeral sessions, installation, service registration, companion launch, or updates. - Read `references/crate-and-privilege-model.md` before moving responsibilities between crates, changing capsem-process permissions or environment, changing session/socket/share boundaries, or changing MITM CA-key handling. - Read `references/key-files.md` before locating the implementation owner for an architectural change; it is the full annotated source map. - Read `references/tauri-v2.md` before changing capsem-app or its Tauri v2 configuration and IPC. The app remains a thin webview shell: only `open_url` and `check_for_app_update`; VM operations route through gateway. ## Core invariants - All VM operations route through `capsem-service` to one `capsem-process` per session. No other host binary boots a VM or talks to guest vsock directly. - The service and gateway expose an explicit route table. Unknown routes return 404; do not add compatibility aliases or generic forwarding. Every public method/path pair is approval-locked in `config/public-surface.toml`. - Terminal bytes, control messages, lifecycle requests, and exec output use distinct vsock responsibilities. Preserve the port and framing contract in `references/service-and-guest-protocols.md`. - The guest is air-gapped: it has no real NIC, DNS, or direct internet. HTTPS reaches the host only through the guest net proxy and the MITM/security path. - VMs start unplugged. A private network is one confined L2 switch process (`capsem-router --network`); `plug()`/`unplug()` connect a VM's cable to it. Plugged VMs talk over any protocol. The switch forwards on MAC only and is a network, not a security boundary: never add per-flow relays, admission, or IP/TCP parsing to it. See `references/storage-network-and-lifecycle.md`. - Corp config owns enterprise constraints; profiles own VM assets and runtime policy; settings own UI preferences. All enforcement and detection compiles into one `SecurityRuleSet` over `SecurityEvent`. - Credential capture/injection belongs to the credential broker. Durable ledger storage belongs to `capsem-logger`; routes, MCP helpers, UI handlers, benchmarks, and network formatters must not open SQLite or own projection caches. Missing tables or columns are schema failures, never empty data. - Sessions run profiles. Workspace and overlay bytes are session state, never a hidden image-authoring rail; package changes go through profile-owned inputs and the profile-derived asset build. - `capsem-process` stays low privilege: a cleared allowlisted environment, 0600 sockets, a 0700 session directory, read-only assets and guest binaries, and only `session_dir/guest/` shared with the VM. - capsem-app contains no VM logic or `capsem-core` dependency. Gateway and tray are service-owned companions and must self-exit with their parent. ## Key source files Read `references/key-files.md` for the full annotated source map. ## Tauri v2 reference Read `references/tauri-v2.md` for Tauri v2 patterns. capsem-app is a thin webview shell -- only 2 IPC commands (`open_url`, `check_for_app_update`). All VM operations route through the gateway.
View on GitHub