diff --git a/README.md b/README.md index 928bd2c..bc0a0f6 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,12 @@

- Architecture · + Architecture · Quick Start · - OCI Support · - Host Mounts · - Snapshots · - Observability + OCI Support · + Host Mounts · + Snapshots · + Observability

@@ -46,49 +46,30 @@ ## What You Get -- **Isolated execution** — Each stage runs inside its own micro-VM boundary (not shared-process containers). +- **Isolated execution** — Each stage runs inside its own micro-VM boundary, not shared-process containers. - **Policy-enforced runtime** — Command allowlists, resource limits, seccomp-BPF, and controlled network egress. - **Skill-native model** — MCP servers, SKILL files, and CLI tools mounted as declared capabilities. - **Composable pipelines** — Sequential `.pipe()`, parallel `.fan_out()`, with explicit stage-level failure domains. -- **Claude Code native runtime** — Each stage runs `claude-code`, backed by Claude (default) or Ollama via Claude-compatible provider mode. -- **OCI-native** — Auto-pulls guest images (kernel + initramfs) from GHCR on first run. Mount container images as base OS or as skill providers — no local build steps required. +- **Claude Code native runtime** — Each stage runs `claude-code`, backed by Claude or Ollama via provider mode. +- **OCI-native** — Auto-pulls guest images from GHCR; mount container images as base OS or skill providers. - **Observability native** — OTLP traces, metrics, structured logs, and stage-level telemetry emitted by design. -- **Persistent host mounts** — Share host directories into guest VMs via 9p/virtiofs with explicit read-only or read-write mode. Data in `mode: rw` mounts persists across VM restarts. +- **Persistent host mounts** — Share host directories into guest VMs via 9p/virtiofs with read-only or read-write mode. - **No root required** — Usermode SLIRP networking via smoltcp (no TAP devices). > Isolation is the primitive. Pipelines are compositions of bounded execution environments. ## Why Not Containers? -Containers share a host kernel. - -For general application isolation, this is often sufficient. -For AI agents executing tools, code, and external integrations, it creates shared failure domains. - -In a shared-process model: - -- Tool execution and agent runtime share the same kernel. -- Escape surfaces are reduced, but not eliminated. -- Resource isolation depends on cgroups and cooperative enforcement. - -VoidBox binds each agent stage to its own micro-VM boundary. - -Isolation is enforced by hardware virtualization — not advisory process controls. +Containers share a host kernel — sufficient for general isolation, but AI agents executing tools, code, and external integrations create shared failure domains. VoidBox binds each agent stage to its own micro-VM boundary, enforced by hardware virtualization rather than advisory process controls. See [Architecture](https://the-void-ia.github.io/void-box/docs/architecture/) ([source](docs/architecture.md)) for the full security model. --- ## Quick Start -### 1. Add dependency - ```bash cargo add void-box ``` -### 2. Define skills and build a VoidBox - -#### Rust API - ```rust use void_box::agent_box::VoidBox; use void_box::skill::Skill; @@ -105,15 +86,13 @@ let reasoning = Skill::agent("claude-code") let researcher = VoidBox::new("hn_researcher") .skill(hn_api) .skill(reasoning) - .llm(LlmProvider::ollama("qwen3-coder")) // claude-code runtime using Ollama backend + .llm(LlmProvider::ollama("qwen3-coder")) .memory_mb(1024) .network(true) .prompt("Analyze top HN stories for AI engineering trends") .build()?; ``` -#### Or use a YAML spec - ```yaml # hackernews_agent.yaml api_version: v1 @@ -137,421 +116,38 @@ agent: timeout_secs: 600 ``` -### 3. Run - -```rust -// Rust API -let result = researcher.run(None).await?; -println!("{}", result.claude_result.result_text); -``` - ```bash -# Or via CLI with a YAML spec voidbox run --file hackernews_agent.yaml ``` --- -## Architecture - -``` -┌───────────────────────────────────────────────────────┐ -│ Host │ -│ VoidBox Engine / Pipeline Orchestrator │ -│ │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ OCI Client (~/.voidbox/oci/) │ │ -│ │ guest image → kernel + initramfs (auto-pull) │ │ -│ │ base image → rootfs (pivot_root) │ │ -│ │ OCI skills → read-only mounts │ │ -│ └─────────────────────┬───────────────────────────┘ │ -│ │ │ -│ ┌─────────────────────▼───────────────────────────┐ │ -│ │ VMM (KVM / Virtualization.framework) │ │ -│ │ vsock ←→ guest-agent (PID 1) │ │ -│ │ SLIRP ←→ eth0 (10.0.2.15) │ │ -│ │ Linux/KVM: virtio-blk ←→ OCI base rootfs │ │ -│ │ 9p/virtiofs ←→ skills + host mounts │ │ -│ │ Snapshot: base/diff → ~/.void-box/snapshots │ │ -│ └─────────────────────────────────────────────────┘ │ -│ │ -│ Seccomp-BPF │ OTLP export │ -└──────────────┼────────────────────────────────────────┘ - Hardware │ Isolation -═══════════════╪════════════════════════════════════════ - │ -┌──────────────▼──────────────────────────────────────────┐ -│ Guest VM (Linux) │ -│ guest-agent: auth, allowlist, rlimits │ -│ claude-code runtime (Claude API or Ollama backend) │ -│ OCI rootfs (pivot_root) + skill mounts (/skills/...) │ -└─────────────────────────────────────────────────────────┘ -``` - -See [docs/architecture.md](docs/architecture.md) for the full component diagram, wire protocol, and security model. - -## Observability - -Every pipeline run is fully instrumented out of the box. Each VM stage emits -spans and metrics via OTLP, giving you end-to-end visibility across isolated -execution boundaries — from pipeline orchestration down to individual tool calls -inside each micro-VM. - -

- Pipeline trace waterfall in Grafana Tempo -

- -- **OTLP traces** — Per-box spans, tool call events, pipeline-level trace -- **Metrics** — Token counts, cost, duration per stage -- **Structured logs** — `[vm:NAME]` prefixed, trace-correlated -- **Guest telemetry** — procfs metrics (CPU, memory) exported to host via vsock - -Enable with `--features opentelemetry` and set `VOIDBOX_OTLP_ENDPOINT`. -See the [playground](playground/) for a ready-to-run stack with Grafana, Tempo, and Prometheus. - -## Running & Testing - -### KVM mode (zero-setup) - -On a Linux host with `/dev/kvm`, VoidBox auto-pulls a pre-built guest image (kernel + initramfs) from GHCR on first run. No manual build steps required: - -```bash -# Just works — guest image is pulled and cached automatically -ANTHROPIC_API_KEY=sk-ant-xxx \ -cargo run --bin voidbox -- run --file examples/specs/oci/agent.yaml - -# Or with Ollama -cargo run --bin voidbox -- run --file examples/specs/oci/workflow.yaml -``` - -The guest image (`ghcr.io/the-void-ia/voidbox-guest`) contains the kernel and initramfs with guest-agent, busybox, and common tools. It's cached at `~/.voidbox/oci/guest/` after the first pull. - -**Resolution order** — VoidBox resolves the kernel/initramfs using: - -1. `sandbox.kernel` / `sandbox.initramfs` in the spec (explicit paths) -2. `VOID_BOX_KERNEL` / `VOID_BOX_INITRAMFS` env vars -3. `sandbox.guest_image` in the spec (explicit OCI ref) -4. Default: `ghcr.io/the-void-ia/voidbox-guest:v{version}` (auto-pull) -5. Mock fallback when `mode: auto` - -To use a custom guest image or disable auto-pull: - -```yaml -sandbox: - # Use a specific guest image - guest_image: "ghcr.io/the-void-ia/voidbox-guest:latest" - - # Or disable auto-pull (empty string) - # guest_image: "" -``` - -### KVM mode (manual build) - -If you prefer to build the guest image locally: - -```bash -# Build base guest initramfs (guest-agent + tools; no required Claude bundle) -scripts/build_guest_image.sh - -# Download a kernel -scripts/download_kernel.sh - -# Run with explicit paths -ANTHROPIC_API_KEY=sk-ant-xxx \ -VOID_BOX_KERNEL=target/vmlinuz-amd64 \ -VOID_BOX_INITRAMFS=/tmp/void-box-rootfs.cpio.gz \ -cargo run --example trading_pipeline -``` - -For a production Claude-capable initramfs, use: - -```bash -# Build production rootfs/initramfs with native claude-code + CA certs + sandbox user -scripts/build_claude_rootfs.sh -``` - -Script intent summary: - -- `scripts/build_guest_image.sh`: base runtime image for general VM/OCI work. -- `scripts/build_claude_rootfs.sh`: production image for direct Claude runtime in guest. -- `scripts/build_test_image.sh`: deterministic test image with `claudio` mock. - -### Mock mode (no KVM required) - -```bash -cargo run --example quick_demo -cargo run --example trading_pipeline -cargo run --example parallel_pipeline -``` - -### macOS mode (Apple Silicon) - -VoidBox runs natively on Apple Silicon Macs using Apple's Virtualization.framework — no Docker or Linux VM required. - -**One-time setup:** - -```bash -# Install the musl cross-compilation toolchain (compiles from source, ~30 min first time) -brew install filosottile/musl-cross/musl-cross - -# Add the Rust target for Linux ARM64 -rustup target add aarch64-unknown-linux-musl -``` - -**Build and run:** - -```bash -# Download an ARM64 Linux kernel (cached in target/) -scripts/download_kernel.sh - -# Build the guest initramfs (cross-compiles guest-agent, downloads claude-code + busybox) -scripts/build_claude_rootfs.sh - -# Build the example and sign it with the virtualization entitlement -cargo build --example ollama_local -codesign --force --sign - --entitlements voidbox.entitlements target/debug/examples/ollama_local - -# Run (Ollama must be listening on 0.0.0.0:11434) -OLLAMA_MODEL=qwen3-coder \ -VOID_BOX_KERNEL=target/vmlinux-arm64 \ -VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \ -target/debug/examples/ollama_local -``` - -> **Note:** Every `cargo build` invalidates the code signature. Re-run `codesign` after each rebuild. - -When using the `voidbox` CLI, `cargo run` automatically codesigns before executing (via `.cargo/config.toml` runner). Just run: - -```bash -cargo run --bin voidbox -- run --file examples/specs/oci/guest-image-workflow.yaml -``` - -If running the binary directly (e.g. `./target/debug/voidbox`), codesign manually first: - -```bash -codesign --force --sign - --entitlements voidbox.entitlements target/debug/voidbox -``` - -### Parallel pipeline with per-box models - -```bash -OLLAMA_MODEL=phi4-mini \ -OLLAMA_MODEL_QUANT=qwen3-coder \ -OLLAMA_MODEL_SENTIMENT=phi4-mini \ -VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \ -VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \ -cargo run --example parallel_pipeline -``` - -### Tests - -```bash -cargo test --lib # Unit tests -cargo test --test skill_pipeline # Integration tests (mock) -cargo test --test integration # Integration tests - -# E2E (requires KVM + test initramfs) -scripts/build_test_image.sh -VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \ -VOID_BOX_INITRAMFS=/tmp/void-box-test-rootfs.cpio.gz \ -cargo test --test e2e_skill_pipeline -- --ignored --test-threads=1 -``` - ---- - -## OCI Container Support - -VoidBox supports OCI container images in three ways: - -1. **`sandbox.guest_image`** — Pre-built kernel + initramfs distributed as an OCI image. Auto-pulled from GHCR on first run (no local build needed). See [KVM mode (zero-setup)](#kvm-mode-zero-setup). -2. **`sandbox.image`** — Use a container image as the base OS for the entire sandbox. The guest-agent performs `pivot_root` at boot, replacing the initramfs root with an overlayfs backed by the OCI image. On Linux/KVM, VoidBox builds a cached ext4 disk artifact from the extracted OCI rootfs and attaches it as `virtio-blk` (`/dev/vda` in guest). On macOS/VZ, the OCI rootfs remains directory-mounted via virtiofs. -3. **OCI skills** — Mount additional container images as read-only tool providers at arbitrary guest paths. This lets you compose language runtimes (Python, Go, Java, etc.) without baking them into the initramfs. - -Images are pulled from Docker Hub, GHCR, or any OCI-compliant registry and cached locally at `~/.voidbox/oci/`. OCI base rootfs transport is platform-specific (`virtio-blk` on Linux/KVM, virtiofs directory mount on macOS/VZ), while OCI skills and host mounts use `9p/virtiofs` shares. - -### Example: OCI skills - -Mount Python, Go, and Java into a single agent — no `sandbox.image` needed: - -```yaml -# examples/specs/oci/skills.yaml -api_version: v1 -kind: agent -name: multi-tool-agent - -sandbox: - mode: auto - memory_mb: 2048 - vcpus: 2 - network: true - -llm: - provider: ollama - model: "qwen2.5-coder:7b" - -agent: - prompt: > - You have Python, Go, and Java available as mounted skills. - Set up PATH to include the skill binaries: - export PATH=/skills/python/usr/local/bin:/skills/go/usr/local/go/bin:/skills/java/bin:$PATH - - Write a "Hello from " one-liner in each language and run all three. - Report which versions are installed. - skills: - - "agent:claude-code" - - image: "python:3.12-slim" - mount: "/skills/python" - - image: "golang:1.23-alpine" - mount: "/skills/go" - - image: "eclipse-temurin:21-jdk-alpine" - mount: "/skills/java" - timeout_secs: 300 -``` - -Run it: - -```bash -# Linux (KVM) -VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \ -VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \ -cargo run --bin voidbox -- run --file examples/specs/oci/skills.yaml - -# macOS (Virtualization.framework) — requires initramfs already built (see "macOS mode" above) -VOID_BOX_KERNEL=target/vmlinux-arm64 \ -VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \ -cargo run --bin voidbox -- run --file examples/specs/oci/skills.yaml -``` - -More OCI examples in [`examples/specs/oci/`](examples/specs/oci/): - -| Spec | Description | -|------|-------------| -| `agent.yaml` | Single agent with `sandbox.image: python:3.12-slim` | -| `workflow.yaml` | Workflow with `sandbox.image: alpine:3.20` (no LLM) | -| `pipeline.yaml` | Multi-language pipeline: Python base + Go and Java OCI skills | -| `skills.yaml` | OCI skills only (Python, Go, Java) mounted into default initramfs | -| `guest-image-workflow.yaml` | Workflow using `sandbox.guest_image` for auto-pulled kernel + initramfs (on macOS, codesign required; gzip kernel is auto-decompressed for VZ) | - -OpenClaw examples and runbook: - -- [`examples/openclaw/README.md`](examples/openclaw/README.md) - -## Host Mounts - -VoidBox can mount host directories into the guest VM using `sandbox.mounts`. Each mount specifies a `host` path, a `guest` mount point, and a `mode` (`"ro"` or `"rw"`, default `"ro"`). - -Read-write mounts write directly to the host directory — data persists across VM restarts since the host directory survives. This is the primary mechanism for stateful workloads. - -Transport is platform-specific: **9p** (virtio-9p) on Linux/KVM, **virtiofs** on macOS/VZ. - -```yaml -sandbox: - mounts: - - host: ./data - guest: /data - mode: rw # persistent — host directory survives VM restarts - - host: ./config - guest: /config - mode: ro # read-only (default) -``` - ---- - -## Snapshots - -VoidBox supports sub-second VM restore via snapshot/restore. Snapshots capture the full VM state (vCPU registers, memory, devices) and restore via COW `mmap` — the guest resumes execution without re-booting the kernel or re-running initialization. - -**All snapshot features are explicit opt-in only.** If you never set a snapshot field, the system behaves exactly as before — cold boot, zero snapshot code runs. - -### Snapshot types - -| Type | Description | -|------|-------------| -| **Base** | Full memory dump + KVM state from a cold-booted VM | -| **Diff** | Only dirty pages since last snapshot (smaller, faster) | - -### YAML spec - -```yaml -# Top-level snapshot — applies to all boxes -sandbox: - memory_mb: 256 - snapshot: "abc123def456" # hash prefix from `voidbox snapshot list` - -# Per-box override -pipeline: - boxes: - - name: analyst - prompt: "analyze data" - sandbox: - snapshot: "def789" # per-box snapshot override - - name: coder - prompt: "write code" - # no snapshot → cold boot (default) -``` - -### Rust API - -```rust -use void_box::agent_box::VoidBox; - -// Cold boot (default — no snapshot) -let box1 = VoidBox::new("analyst") - .prompt("analyze data") - .memory_mb(256) - .build()?; - -// Restore from snapshot (explicit opt-in) -let box2 = VoidBox::new("analyst") - .prompt("analyze data") - .snapshot("/path/to/snapshot/dir") // or hash prefix - .build()?; -``` - -### CLI - -```bash -# Create a snapshot from a running VM -voidbox snapshot create --config-hash - -# List stored snapshots -voidbox snapshot list - -# Delete a snapshot -voidbox snapshot delete - -# Run with a snapshot (via spec) -voidbox run --file spec.yaml # spec has sandbox.snapshot set -``` - -### Daemon API - -```bash -# POST /runs with snapshot override -curl -X POST http://localhost:8080/runs \ - -H 'Content-Type: application/json' \ - -d '{"file": "workflow.yaml", "snapshot": "abc123def456"}' -``` - -### Design principles - -- **No snapshot field set** → cold boot, zero snapshot code runs -- **No auto-detection** of existing snapshots -- **No auto-creation** of snapshots during normal runs -- **No auto-restore** — only if the user passes an explicit path or hash -- **No env var fallback** — spec or code only -- **Every new field defaults to `None`** — the system behaves identically to before if untouched - -Snapshot cache is stored at `~/.void-box/snapshots/` with LRU eviction support. - -### Benchmarks - -Measured on a single-vCPU, 256 MB VM (Linux/KVM): -| Metric | Time | -|--------|------| -| Cold boot | ~12 ms | -| Snapshot restore | ~2 ms | -| **Cold boot → restore speedup** | **~6x** | +## Documentation + +| | | +|---|---| +| **[Architecture](https://the-void-ia.github.io/void-box/docs/architecture/)** | Component diagram, data flow, security model | +| **[Runtime Model](https://the-void-ia.github.io/void-box/docs/runtime/)** | Claude Code runtime, LLM providers, skill types | +| **[CLI + TUI](https://the-void-ia.github.io/void-box/docs/cli-tui/)** | Command reference, daemon API endpoints | +| **[Events + Observability](https://the-void-ia.github.io/void-box/docs/events-observability/)** | Event types, OTLP traces, metrics | +| **[OCI Containers](https://the-void-ia.github.io/void-box/docs/oci-containers/)** | Guest images, base images, OCI skills | +| **[Snapshots](https://the-void-ia.github.io/void-box/docs/snapshots/)** | Sub-second VM restore, snapshot types | +| **[Host Mounts](https://the-void-ia.github.io/void-box/docs/host-mounts/)** | 9p/virtiofs host directory sharing | +| **[Security](https://the-void-ia.github.io/void-box/docs/security/)** | Defense in depth, session auth, seccomp | +| **[Wire Protocol](https://the-void-ia.github.io/void-box/docs/wire-protocol/)** | vsock framing, message types | + +### Guides + +| | | +|---|---| +| **[Getting Started](https://the-void-ia.github.io/void-box/guides/getting-started/)** | Install, first agent, first run | +| **[Running on Linux](https://the-void-ia.github.io/void-box/guides/running-on-linux/)** | KVM setup, manual build, mock mode, tests | +| **[Running on macOS](https://the-void-ia.github.io/void-box/guides/running-on-macos/)** | Apple Silicon, Virtualization.framework | +| **[Observability Setup](https://the-void-ia.github.io/void-box/guides/observability-setup/)** | OTLP config, Grafana playground | +| **[AI Agent Sandboxing](https://the-void-ia.github.io/void-box/guides/ai-agent-sandboxing/)** | Isolated micro-VM agent execution | +| **[Pipeline Composition](https://the-void-ia.github.io/void-box/guides/pipeline-composition/)** | Multi-stage pipelines with .pipe() and .fan_out() | +| **[YAML Specs](https://the-void-ia.github.io/void-box/guides/yaml-specs/)** | Declarative agent/pipeline definitions | +| **[Local LLMs](https://the-void-ia.github.io/void-box/guides/ollama-local/)** | Ollama integration via SLIRP networking | --- diff --git a/site/assets/css/site.css b/site/assets/css/site.css index bc6cf16..bea6f1d 100644 --- a/site/assets/css/site.css +++ b/site/assets/css/site.css @@ -1,12 +1,17 @@ +/* ── Void-Box — Dark theme ── */ :root { - --bg: #f5f7fb; - --text: #101828; - --muted: #475467; - --line: #e4e7ec; - --card: #ffffff; - --accent: #111827; - --accent-soft: #f2f4f7; - --success: #12b76a; + --bg: #0a0e1a; + --bg-alt: #0f1629; + --text: #e0faff; + --text-secondary: #c8f0ff; + --muted: #7b93ab; + --line: rgba(0,229,255,0.1); + --card: rgba(255,255,255,0.04); + --accent: #00e5ff; + --accent-teal: #14b8a6; + --accent-soft: rgba(0,229,255,0.06); + --accent-glow: rgba(0,229,255,0.15); + --purple: #2a1f5e; --max: 1100px; } @@ -19,14 +24,20 @@ body { line-height: 1.5; } -a { color: inherit; text-decoration: none; } -a:hover { text-decoration: underline; } +a { color: var(--accent); text-decoration: none; } +a:hover { color: #4ff8e8; text-decoration: underline; } .wrap { width: min(100% - 2rem, var(--max)); margin: 0 auto; } +/* ── Nav ── */ .site { border-bottom: 1px solid var(--line); - background: #fff; + background: rgba(10,14,26,0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + position: sticky; + top: 0; + z-index: 100; } .site .inner { display: flex; @@ -40,34 +51,77 @@ a:hover { text-decoration: underline; } align-items: center; gap: 0.55rem; font-weight: 700; + color: var(--text); } +.brand:hover { text-decoration: none; } .brand img { width: 32px; height: 32px; border-radius: 8px; object-fit: cover; } .top { display: flex; align-items: center; gap: 1.2rem; - color: #344054; + color: var(--muted); font-weight: 500; } +.top a { color: var(--muted); } +.top a:hover { color: var(--text); text-decoration: none; } main section { padding: 2.4rem 0; } +/* ── Hero ── */ .hero { text-align: center; padding-top: 3.8rem; + background: linear-gradient(165deg, #0a0e1a 0%, #0f1629 50%, #1a1f3a 100%); + position: relative; + overflow: hidden; +} +.hero::before { + content: ""; + position: absolute; + top: -40%; + left: 50%; + translate: -50% 0; + width: 700px; + height: 700px; + background: radial-gradient(circle, rgba(0,229,255,0.12) 0%, rgba(42,31,94,0.08) 40%, transparent 70%); + border-radius: 50%; + pointer-events: none; + animation: hero-pulse 6s ease-in-out infinite; +} +.hero::after { + content: ""; + position: absolute; + bottom: -20%; + right: -10%; + width: 500px; + height: 500px; + background: radial-gradient(circle, rgba(42,31,94,0.15) 0%, transparent 60%); + border-radius: 50%; + pointer-events: none; + animation: hero-pulse 8s ease-in-out infinite reverse; +} +@keyframes hero-pulse { + 0%, 100% { opacity: 0.7; transform: scale(1); } + 50% { opacity: 1; transform: scale(1.12); } +} +.hero > .wrap { + position: relative; + z-index: 1; } .hero h1 { margin: 0; font-size: clamp(2rem, 6vw, 4rem); letter-spacing: -0.03em; line-height: 1.05; + color: var(--text); + text-shadow: 0 0 60px var(--accent-glow); } .hero .lead { margin: 1.1rem auto 0; max-width: 780px; font-size: clamp(1rem, 1.8vw, 1.35rem); - color: #344054; + color: var(--text-secondary); font-weight: 600; } .hero .sub { @@ -81,9 +135,10 @@ main section { padding: 2.4rem 0; } display: inline-block; margin-top: 0.8rem; padding: 0.45rem 0.75rem; - border: 1px solid var(--line); + border: 1px solid rgba(0,229,255,0.25); border-radius: 999px; - background: #fff; + background: rgba(0,229,255,0.08); + color: #4ff8e8; font-family: "JetBrains Mono", "IBM Plex Mono", monospace; font-size: 0.9rem; } @@ -94,11 +149,11 @@ main section { padding: 2.4rem 0; } flex-wrap: wrap; gap: 1rem; margin-top: 1.2rem; - color: #344054; + color: var(--text-secondary); } .chips span::before { content: "\2713"; - color: var(--success); + color: var(--accent); margin-right: 0.45rem; font-weight: 700; } @@ -110,26 +165,40 @@ main section { padding: 2.4rem 0; } gap: 0.7rem; flex-wrap: wrap; } + +/* ── Buttons ── */ .btn { display: inline-block; - border: 1px solid #d0d5dd; - background: #fff; + border: 1px solid rgba(0,229,255,0.15); + background: rgba(255,255,255,0.06); + color: var(--text-secondary); border-radius: 0.55rem; padding: 0.62rem 1rem; font-weight: 600; + transition: border-color 0.2s, box-shadow 0.2s; +} +.btn:hover { + border-color: rgba(0,229,255,0.4); + text-decoration: none; } .btn.primary { - background: #101828; - color: #fff; - border-color: #101828; + background: linear-gradient(135deg, #00e5ff, #14b8a6); + color: #0a0e1a; + border: none; + box-shadow: 0 0 20px rgba(0,229,255,0.3); +} +.btn.primary:hover { + box-shadow: 0 0 30px rgba(0,229,255,0.5); + text-decoration: none; } +/* ── Code tabs ── */ .code-tabs { display: inline-flex; justify-content: center; gap: 0; margin: 2.2rem auto 0; - background: var(--accent-soft); + background: rgba(0,229,255,0.06); border-radius: 0.5rem; padding: 0.25rem; } @@ -147,8 +216,8 @@ main section { padding: 2.4rem 0; } .code-tab:hover { color: var(--text); } .code-tab.active { color: var(--text); - background: #fff; - box-shadow: 0 1px 3px rgba(0,0,0,0.08); + background: rgba(0,229,255,0.1); + box-shadow: none; } .code-tabs ~ .code-wrap { @@ -172,13 +241,8 @@ main section { padding: 2.4rem 0; } font-size: 0.9rem; color: #7ee787; } -.code-run span { - color: #7d8590; - margin-right: 0.3rem; -} -.code-run code { - color: #e8f2ff; -} +.code-run span { color: #7d8590; margin-right: 0.3rem; } +.code-run code { color: #e8f2ff; } .code-head { display: flex; align-items: center; @@ -203,11 +267,7 @@ pre { line-height: 1.65; text-align: left; } - -pre code { - white-space: pre; - display: block; -} +pre code { white-space: pre; display: block; } .tok-kw { color: #7cc4ff; font-weight: 600; } .tok-ty { color: #7ee787; } @@ -216,6 +276,7 @@ pre code { .tok-fn { color: #d2a8ff; } .tok-num { color: #79c0ff; } +/* ── Demo ── */ .demo { margin: 1.6rem auto 0; max-width: 760px; @@ -224,11 +285,7 @@ pre code { border: 1px solid #1f2a44; background: #0b1220; } -.demo img { - display: block; - width: 100%; - height: auto; -} +.demo img, .demo video { display: block; width: 100%; height: auto; } .demo-caption { margin: 1.2rem auto 0; max-width: 760px; @@ -237,6 +294,7 @@ pre code { font-size: 0.95rem; } +/* ── Sections ── */ .section-title { text-align: center; margin: 0; @@ -247,92 +305,388 @@ pre code { margin: 0.6rem auto 1.8rem; max-width: 760px; text-align: center; - color: #475467; + color: var(--muted); } +main > section:nth-child(even) { + background: var(--bg-alt); +} + +/* ── Glass cards ── */ .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } .card { - background: var(--card); - border: 1px solid var(--line); + background: rgba(255,255,255,0.04); + border: 1px solid rgba(0,229,255,0.08); border-radius: 0.8rem; padding: 1rem; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s, background 0.2s; } -.card h3 { - margin: 0; - font-size: 1.03rem; +.card:hover { + transform: translateY(-3px); + background: rgba(255,255,255,0.07); + border-color: rgba(0,229,255,0.25); + box-shadow: 0 8px 32px rgba(0,229,255,0.08), 0 0 0 1px rgba(0,229,255,0.1); } +.card h3 { margin: 0; font-size: 1.03rem; color: var(--text); } .card small { display: block; margin-top: 0.25rem; - color: #98a2b3; + color: var(--accent); font-weight: 600; } -.card p { - margin: 0.6rem 0 0; - color: #475467; -} +.card p { margin: 0.6rem 0 0; color: var(--muted); } +/* ── Doc pages ── */ .doc-main { padding-bottom: 2rem; } .doc-main h1 { margin: 0 0 0.7rem; font-size: clamp(1.8rem, 4vw, 2.6rem); + color: var(--text); +} +.doc-main h2 { + margin-top: 1.7rem; + color: var(--text-secondary); + border-bottom: 1px solid var(--line); + padding-bottom: 0.4rem; } -.doc-main h2 { margin-top: 1.7rem; } -.doc-main p, .doc-main li { color: #475467; } +.doc-main p, .doc-main li { color: var(--muted); } .doc-main ul { padding-left: 1.2rem; } -.doc-main code { color: #0f766e; } +.doc-main ol { color: var(--muted); } +.doc-main code { + color: var(--accent); + background: rgba(0,229,255,0.06); + padding: 0.15rem 0.35rem; + border-radius: 0.25rem; + font-size: 0.9em; +} +.doc-main pre code { + background: none; + padding: 0; + border-radius: 0; + color: #e8f2ff; +} +.doc-main pre { + background: #0b1220; + border: 1px solid #1f2a44; + border-radius: 0.6rem; + margin: 1rem 0; +} +.doc-main img { + border-radius: 0.6rem; + border: 1px solid var(--line); +} + +/* ── Tables ── */ +table { + width: 100%; + border-collapse: collapse; + margin: 1rem 0; +} +th { + text-align: left; + padding: 0.6rem 0.8rem; + font-weight: 600; + color: var(--text-secondary); + border-bottom: 2px solid rgba(0,229,255,0.15); + font-size: 0.9rem; +} +td { + padding: 0.55rem 0.8rem; + border-bottom: 1px solid var(--line); + color: var(--muted); +} +tr:hover td { + background: rgba(0,229,255,0.03); +} +/* ── List items (index pages) ── */ .list { display: grid; gap: 0.8rem; } .list a { display: block; - background: #fff; - border: 1px solid var(--line); + background: rgba(255,255,255,0.04); + border: 1px solid rgba(0,229,255,0.08); border-radius: 0.75rem; padding: 0.9rem; + transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s; + color: var(--text); } -.list strong { display: block; margin-bottom: 0.2rem; } -.list span { color: #667085; } +.list a:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0,229,255,0.06); + border-color: rgba(0,229,255,0.25); + text-decoration: none; +} +.list strong { display: block; margin-bottom: 0.2rem; color: var(--text); } +.list span { color: var(--muted); } +/* ── Footer ── */ footer { border-top: 1px solid var(--line); margin-top: 2.4rem; padding: 1.2rem 0 2rem; - color: #667085; + color: var(--muted); text-align: center; } +footer a { color: var(--muted); } +footer a:hover { color: var(--accent); text-decoration: none; } +/* ── Kicker ── */ .kicker { text-transform: uppercase; font-size: 0.82rem; font-weight: 700; letter-spacing: 0.08em; - color: var(--muted); + color: var(--accent); margin-bottom: 0.3rem; } +/* ── Star button ── */ .star-btn { display: inline-flex; align-items: center; gap: 0.3rem; - border: 1px solid var(--line); + border: 1px solid rgba(0,229,255,0.15); border-radius: 0.45rem; padding: 0.25rem 0.6rem; font-size: 0.85rem; font-weight: 600; - color: #344054; - background: #fff; - transition: border-color 0.15s; + color: var(--text-secondary); + background: rgba(255,255,255,0.06); + transition: border-color 0.15s, box-shadow 0.15s; } .star-btn:hover { - border-color: #98a2b3; + border-color: rgba(0,229,255,0.4); + text-decoration: none; + box-shadow: 0 0 12px rgba(0,229,255,0.25); +} + +.grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; +} + +/* Equal-height demo grid */ +.grid-2 > div { + display: flex; + flex-direction: column; +} +.grid-2 .demo { + max-width: none; + margin: 0; + flex: 1; + display: flex; +} +.grid-2 .demo img, .grid-2 .demo video { + width: 100%; + height: 100%; + object-fit: cover; + object-position: top left; +} + +/* ── Install section ── */ +.install-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; + margin-top: 1.5rem; +} +.install-card { + background: rgba(255,255,255,0.04); + border: 1px solid rgba(0,229,255,0.08); + border-radius: 0.8rem; + padding: 1.2rem; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + transition: border-color 0.2s; +} +.install-card:hover { + border-color: rgba(0,229,255,0.25); +} +.install-card h3 { + margin: 0 0 0.1rem; + font-size: 1rem; + color: var(--text); +} +.install-card .install-label { + font-size: 0.8rem; + color: var(--accent); + font-weight: 600; + margin-bottom: 0.6rem; +} +.install-card pre { + background: #0b1220; + border: 1px solid #1f2a44; + border-radius: 0.5rem; + padding: 0.7rem 0.9rem; + font-size: 0.78rem; + line-height: 1.5; + margin: 0; + overflow-x: auto; +} +.install-card pre code { + word-break: break-all; + white-space: pre-wrap; +} +.install-note { + text-align: center; + margin-top: 1.2rem; + color: var(--muted); + font-size: 0.9rem; +} +.install-note a { + color: var(--accent); +} +.install-platforms { + display: flex; + justify-content: center; + gap: 0.6rem; + flex-wrap: wrap; + margin-top: 1rem; +} +.install-platforms a { + display: inline-block; + padding: 0.45rem 0.9rem; + border: 1px solid rgba(0,229,255,0.15); + border-radius: 0.5rem; + background: rgba(255,255,255,0.04); + color: var(--text-secondary); + font-size: 0.85rem; + font-weight: 600; + transition: border-color 0.2s, box-shadow 0.2s; +} +.install-platforms a:hover { + border-color: rgba(0,229,255,0.4); + box-shadow: 0 0 12px rgba(0,229,255,0.15); + text-decoration: none; +} + +/* ── Doc layout + sidebar ── */ +.doc-layout { + display: grid; + grid-template-columns: 240px 1fr; + gap: 2rem; + align-items: start; +} + +.doc-sidebar { + position: sticky; + top: 4rem; + background: rgba(255,255,255,0.03); + border: 1px solid var(--line); + border-radius: 0.75rem; + padding: 1rem; +} + +.doc-sidebar nav { + display: flex; + flex-direction: column; + gap: 0.2rem; +} + +.doc-sidebar strong { + display: block; + margin-bottom: 0.5rem; + font-size: 0.82rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--accent); +} + +.doc-sidebar a { + display: block; + padding: 0.35rem 0.6rem; + border-radius: 0.4rem; + font-size: 0.9rem; + color: var(--muted); + transition: color 0.15s, background 0.15s; +} + +.doc-sidebar a:hover { + background: rgba(0,229,255,0.06); + color: var(--text); text-decoration: none; } +.doc-sidebar a.active { + background: rgba(0,229,255,0.1); + font-weight: 600; + color: var(--text); + border-left: 2px solid var(--accent); +} + +.doc-content { + min-width: 0; +} + +.breadcrumb { + display: flex; + gap: 0.4rem; + font-size: 0.85rem; + color: var(--muted); + margin-bottom: 0.8rem; +} +.breadcrumb a { color: var(--muted); } +.breadcrumb a:hover { color: var(--text); } +.breadcrumb span { color: #4a5568; } + +/* ── Steps ── */ +.steps { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; + counter-reset: step; +} + +.step { + text-align: center; + padding: 1.2rem; +} + +.step::before { + counter-increment: step; + content: counter(step); + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.2rem; + height: 2.2rem; + border-radius: 50%; + background: linear-gradient(135deg, #00e5ff, #14b8a6); + color: #0a0e1a; + font-weight: 700; + font-size: 1rem; + margin-bottom: 0.8rem; + box-shadow: 0 0 16px rgba(0,229,255,0.35); +} + +.step h3 { margin: 0 0 0.4rem; font-size: 1.05rem; } +.step p { margin: 0; color: var(--muted); font-size: 0.95rem; } + +/* ── Fade-in animation ── */ +.fade-in { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; +} +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* ── Responsive ── */ @media (max-width: 980px) { .grid-3 { grid-template-columns: 1fr; } + .grid-2 { grid-template-columns: 1fr; } + .doc-layout { grid-template-columns: 1fr; } + .doc-sidebar { position: static; } + .steps { grid-template-columns: 1fr; } .top { gap: 0.85rem; font-size: 0.95rem; } + .install-grid { grid-template-columns: 1fr; } } diff --git a/site/assets/img/void-box-openclaw-demo-2x.mp4 b/site/assets/img/void-box-openclaw-demo-2x.mp4 new file mode 100644 index 0000000..e70c4dc Binary files /dev/null and b/site/assets/img/void-box-openclaw-demo-2x.mp4 differ diff --git a/site/assets/js/site.js b/site/assets/js/site.js index 7ad7d1e..24130fa 100644 --- a/site/assets/js/site.js +++ b/site/assets/js/site.js @@ -98,4 +98,14 @@ history.replaceState(null, '', id); }); } + // Scroll fade-in + var faders = document.querySelectorAll('.fade-in'); + if (faders.length && 'IntersectionObserver' in window) { + var obs = new IntersectionObserver(function(entries) { + entries.forEach(function(e) { + if (e.isIntersecting) { e.target.classList.add('visible'); obs.unobserve(e.target); } + }); + }, { threshold: 0.15 }); + for (var i = 0; i < faders.length; i++) obs.observe(faders[i]); + } })(); diff --git a/site/docs/architecture/index.html b/site/docs/architecture/index.html index a41a3f0..7550509 100644 --- a/site/docs/architecture/index.html +++ b/site/docs/architecture/index.html @@ -1,7 +1,7 @@ -void-box architecture +Architecture | Void-Box -
+
+
+
+ +
+
Architecture

Agent(Skills) + Isolation Boundary

-

VoidBox composes declared skills with a hardware-isolated execution environment. Each run is provisioned through host orchestration and enforced by guest runtime controls.

+

void-box is a composable agent runtime where each agent runs in a hardware-isolated micro-VM. On Linux this uses KVM; on macOS (Apple Silicon) it uses Virtualization.framework (VZ). The core equation is:

+
VoidBox = Agent(Skills) + Isolation
+

A VoidBox binds declared skills (MCP servers, CLI tools, procedural knowledge files, reasoning engines) to an isolated execution environment. Boxes compose into pipelines where output flows between stages, each in a fresh VM.

+
+ +
+

Component Diagram

+
┌──────────────────────────────────────────────────────────────────┐
+│ User / Daemon / CLI                                              │
+│                                                                  │
+│  ┌──────────────────────────────────────────────────────────┐    │
+│  │ VoidBox (agent_box.rs)                                   │    │
+│  │  name: "analyst"                                         │    │
+│  │  prompt: "Analyze AAPL..."                               │    │
+│  │  skills: [claude-code, financial-data.md, market-mcp]    │    │
+│  │  config: memory=1024MB, vcpus=1, network=true            │    │
+│  └─────────────────────┬────────────────────────────────────┘    │
+│                        │ resolve_guest_image() → .build() → .run()
+│  ┌─────────────────────▼───────────────────────────────────┐     │
+│  │ OCI Client (voidbox-oci/)                               │     │
+│  │  guest image → kernel + initramfs  (auto-pull, cached)  │     │
+│  │  base image  → rootfs              (pivot_root)         │     │
+│  │  OCI skills  → read-only mounts    (/skills/...)        │     │
+│  │  cache: ~/.voidbox/oci/{blobs,rootfs,guest}/            │     │
+│  └─────────────────────┬───────────────────────────────────┘     │
+│                        │                                         │
+│  ┌─────────────────────▼───────────────────────────────────┐     │
+│  │ Sandbox (sandbox/)                                      │     │
+│  │  ┌─────────────┐  ┌──────────────┐                      │     │
+│  │  │ MockSandbox │  │ LocalSandbox │                      │     │
+│  │  │ (testing)   │  │ (KVM / VZ)   │                      │     │
+│  │  └─────────────┘  └──────┬───────┘                      │     │
+│  └──────────────────────────┼──────────────────────────────┘     │
+│                             │                                    │
+│  ┌──────────────────────────▼──────────────────────────────┐     │
+│  │ MicroVm (vmm/)                                          │     │
+│  │  ┌────────┐ ┌────────┐ ┌─────────────┐ ┌──────────────┐ │     │
+│  │  │ KVM VM │ │ vCPU   │ │ VsockDevice │ │ VirtioNet    │ │     │
+│  │  │        │ │ thread │ │ (AF_VSOCK)  │ │ (SLIRP)      │ │     │
+│  │  └────────┘ └────────┘ └───────┬─────┘ └───────┬──────┘ │     │
+│  │  Linux/KVM: virtio-blk (OCI rootfs)            │        │     │
+│  │  9p/virtiofs: skills + host mounts             │        │     │
+│  │  Seccomp-BPF on VMM thread    │               │        │     │
+│  └────────────────────────────────┼───────────────┼────────┘     │
+│                                   │               │              │
+└═══════════════════════════════════╪═══════════════╪══════════════┘
+              Hardware Isolation    │               │
+                                    │ vsock:1234    │ SLIRP NAT
+┌───────────────────────────────────▼───────────────▼───────────────┐
+│ Guest VM (Linux kernel)                                           │
+│                                                                   │
+│  ┌──────────────────────────────────────────────────────────────┐ │
+│  │ guest-agent (PID 1)                                          │ │
+│  │  - Authenticates via session secret (kernel cmdline)         │ │
+│  │  - Reads /etc/voidbox/allowed_commands.json                  │ │
+│  │  - Reads /etc/voidbox/resource_limits.json                   │ │
+│  │  - Applies setrlimit + command allowlist                     │ │
+│  │  - Drops privileges to uid:1000                              │ │
+│  │  - Listens on vsock port 1234                                │ │
+│  │  - pivot_root to OCI rootfs (if sandbox.image set)           │ │
+│  └────────────────────────┬─────────────────────────────────────┘ │
+│                           │ fork+exec                             │
+│  ┌────────────────────────▼─────────────────────────────────────┐ │
+│  │ claude-code (or claudio mock)                                │ │
+│  │  --output-format stream-json                                 │ │
+│  │  --dangerously-skip-permissions                              │ │
+│  │  Skills: ~/.claude/skills/*.md                               │ │
+│  │  MCP:    ~/.claude/mcp.json                                  │ │
+│  │  OCI skills: /skills/{python,go,...} (read-only mounts)      │ │
+│  │  LLM:    Claude API / Ollama (via SLIRP → host:11434)        │ │
+│  └──────────────────────────────────────────────────────────────┘ │
+│                                                                   │
+│  eth0: 10.0.2.15/24  gw: 10.0.2.2  dns: 10.0.2.3                  │
+└───────────────────────────────────────────────────────────────────┘
+
+ +
+

Data Flow

+ +

Single VoidBox Execution

+
1. VoidBox::new("name")           User declares skills, prompt, config
+       │
+2. resolve_guest_image()          Resolve kernel + initramfs (5-step chain)
+       │                          Pulls from GHCR if no local paths found
+       │
+3. .build()                       Creates Sandbox (mock or local VM backend: KVM/VZ)
+       │                          Mounts OCI rootfs + skill images if configured
+       │
+4. .run(input)                    Execution begins
+       │
+   ├─ provision_security()        Write resource limits + allowlist to /etc/voidbox/
+   ├─ provision_skills()          Write SKILL.md files to ~/.claude/skills/
+   │                              Write mcp.json to ~/.claude/
+   ├─ write input                 Write /workspace/input.json (if piped from previous stage)
+   │
+   ├─ sandbox.exec_claude()       Send ExecRequest over vsock
+   │       │
+   │   [vsock port 1234]
+   │       │
+   │   guest-agent receives       Validates session secret
+   │       │                      Checks command allowlist
+   │       │                      Applies resource limits (setrlimit)
+   │       │                      Drops privileges (uid:1000)
+   │       │
+   │   fork+exec claude-code      Runs with --output-format stream-json
+   │       │
+   │   claude-code executes       Reads skills, calls LLM, uses tools
+   │       │
+   │   ExecResponse sent          stdout/stderr/exit_code over vsock
+   │       │
+   ├─ parse stream-json           Extract ClaudeExecResult (tokens, cost, tools)
+   ├─ read output file            /workspace/output.json
+   │
+5. StageResult                    box_name, claude_result, file_output
+ +

Pipeline Execution

+
Pipeline::named("analysis", box1)
+    .pipe(box2)                    Sequential: box1.output → box2.input
+    .fan_out(vec![box3, box4])     Parallel: both receive box2.output
+    .pipe(box5)                    Sequential: merged [box3, box4] → box5.input
+    .run()
+
+Stage flow:
+  box1.run(None)          → carry_data = output bytes
+  box2.run(carry_data)    → carry_data = output bytes
+  [box3, box4].run(carry) → carry_data = JSON array merge
+  box5.run(carry_data)    → PipelineResult
+

For parallel stages (fan_out), each box runs in a separate tokio::task::JoinSet. Their outputs are merged as a JSON array for the next stage.

+
+ +
+

Network Layout (SLIRP)

+

void-box uses smoltcp-based usermode networking (SLIRP) -- no root, no TAP devices, no bridge configuration.

+
Guest VM                                    Host
+┌─────────────────────┐                    ┌──────────────────┐
+│ eth0: 10.0.2.15/24  │                    │                  │
+│ gw:   10.0.2.2      │── virtio-net ──────│ SLIRP stack      │
+│ dns:  10.0.2.3      │   (MMIO)           │ (smoltcp)        │
+└─────────────────────┘                    │                  │
+                                           │ 10.0.2.2 → NAT   │
+                                           │   → 127.0.0.1    │
+                                           └──────────────────┘
+
    +
  • Guest IP: 10.0.2.15/24
  • +
  • Gateway: 10.0.2.2 (mapped to host 127.0.0.1)
  • +
  • DNS: 10.0.2.3 (forwarded to host resolver)
  • +
  • Outbound TCP/UDP is NATed through the host
  • +
  • The guest reaches host services (Ollama on :11434) via 10.0.2.2
  • +
+
+ +
+

Key Layers

Host Layer

CLI/daemon orchestrates runs, provisions skills/config, manages KVM VM lifecycle, and records run events.

-

Guest Layer

`guest-agent` authenticates host requests, enforces command allowlist + rlimits, drops privilege, then executes `claude-code`.

-

Communication

vsock protocol frames requests/responses and supports streaming chunks plus telemetry.

-

Security Model

KVM isolation + seccomp + session auth + policy controls + controlled networking.

+

Guest Layer

guest-agent authenticates host requests, enforces command allowlist + rlimits, drops privilege, then executes claude-code.

+

Communication

vsock protocol frames requests/responses and supports streaming chunks plus telemetry. See the Wire Protocol page for frame format details.

+

Security Model

KVM isolation + seccomp + session auth + policy controls + controlled networking. See the Security page for defense-in-depth details.

-
-

Execution Flow

-
spec -> env provision -> skill mount -> claude-code run -> events/report
-

For pipelines, stages compose sequentially and in fan-out mode with explicit failure boundaries per stage.

-
+ +
+
diff --git a/site/docs/cli-tui/index.html b/site/docs/cli-tui/index.html index 30ea74c..2d0583e 100644 --- a/site/docs/cli-tui/index.html +++ b/site/docs/cli-tui/index.html @@ -1,7 +1,7 @@ -void-box cli and tui +CLI + TUI | Void-Box -
+
+
+
+ +
+
CLI / TUI

Current Interface Surface

-

The CLI provides run/validate/status/log flows and a TUI command mode layered on daemon HTTP endpoints.

-
-

CLI Commands

serve, run, validate, status, logs, tui

-

TUI Commands

/run, /input, /status, /logs, /cancel, /history

-
+

The CLI provides run/validate/status/log flows. The TUI layers an interactive command mode on top of the daemon HTTP endpoints. Both communicate with the same daemon process.

+
-

Daemon APIs used by TUI

-
    -
  • POST /v1/runs
  • -
  • GET /v1/runs/:id
  • -
  • GET /v1/runs/:id/events
  • -
  • POST /v1/runs/:id/cancel
  • -
  • POST /v1/sessions/:id/messages
  • -
  • GET /v1/sessions/:id/messages
  • -
+

CLI Commands

+ + + + + + + + + + + + + + + +
CommandDescription
voidbox serveStart the daemon HTTP server. All other commands (except validate) require the daemon to be running.
voidbox run --file <spec>Execute a spec file (agent, pipeline, or workflow). Submits the run to the daemon and streams events to stdout.
voidbox validate --file <spec>Validate a spec file without running it. Checks schema, skill references, and sandbox configuration for errors.
voidbox statusShow daemon status and active runs. Displays run IDs, current stage, and elapsed time.
voidbox logs <run-id>Stream logs for a specific run. Follows the event stream until the run completes or is cancelled.
voidbox tuiLaunch the interactive TUI interface. Connects to the daemon and provides a command prompt for managing runs.
voidbox snapshot create --config-hash <hash>Create a snapshot from a running or stopped VM, keyed by its configuration hash.
voidbox snapshot listList all stored snapshots with their hash prefixes, sizes, and creation timestamps.
voidbox snapshot delete <hash-prefix>Delete a snapshot by its hash prefix. Removes the state file and memory dumps.
+ +
+

Daemon API Endpoints

+

The daemon exposes an HTTP API used by both the CLI and TUI. These endpoints are also available for direct integration:

+ + + + + + + + + + + + +
MethodPathDescription
POST/v1/runsCreate a new run. Accepts a spec payload and returns a run ID.
GET/v1/runs/:idGet run status. Returns current state, stage progress, and timing information.
GET/v1/runs/:id/eventsStream run events via Server-Sent Events (SSE). Provides real-time progress updates.
POST/v1/runs/:id/cancelCancel a running run. Sends SIGKILL to the guest process and tears down the VM.
POST/v1/sessions/:id/messagesSend a message to an active session. Used for interactive/conversational workflows.
GET/v1/sessions/:id/messagesGet session messages. Returns the full message history for a session.
+
+ +
+

TUI Commands

+

The TUI provides an interactive command prompt connected to the daemon. Available commands:

+ + + + + + + + + + + + +
CommandDescription
/runStart a new run from a spec file or inline definition.
/inputSend input to an active interactive session.
/statusDisplay the status of all active and recent runs.
/logsStream logs for a specific run ID.
/cancelCancel a running run by its ID.
/historyShow the history of completed runs with their results.
+
+

Known UX Gap

-

Current TUI is functional but minimal: polling-oriented and plain text. A richer panel-based, live-streaming UX can be layered on top of event streaming APIs.

+
+

Minimal but Functional

+

The current TUI is functional but minimal: polling-oriented and plain text. A richer panel-based, live-streaming UX is planned and can be layered on top of the existing SSE event streaming APIs without changes to the daemon.

+
+ +
+
diff --git a/site/docs/events-observability/index.html b/site/docs/events-observability/index.html index ea757df..d48900b 100644 --- a/site/docs/events-observability/index.html +++ b/site/docs/events-observability/index.html @@ -1,7 +1,7 @@ -void-box events and observability +Events + Observability | Void-Box -
+
+
+
+ +
+
Events + Observability

Run Event Model

-

VoidBox events are designed to keep capability and boundary context explicit for every action.

-

Identity fields

run_id, box_name, skill_id, environment_id, mode, stream, seq.

+

Every pipeline run in VoidBox is fully instrumented. The event system provides structured identity fields on every action, OTLP-compatible traces and metrics, and structured logs -- all designed to keep capability and boundary context explicit.

+
+ +
+

Identity Fields

+
+

Every event carries these fields

+

run_id -- unique identifier for the pipeline run.
+ box_name -- the VoidBox that emitted the event.
+ skill_id -- which skill is active.
+ environment_id -- the execution environment (VM) identifier.
+ mode -- execution mode (single, pipeline, workflow).
+ stream -- output stream (stdout, stderr).
+ seq -- monotonic sequence number for ordering.

+
+

Core Event Types

-
    -
  • run.started, run.finished, run.failed, run.cancelled
  • -
  • env.provisioned
  • -
  • skill.mounted
  • -
  • box.started, workflow.planned
  • -
  • log.chunk, log.closed
  • -
+ + + + + + + + + + + + + + + + +
EventDescription
run.startedPipeline run has begun execution.
run.finishedPipeline run completed successfully.
run.failedPipeline run failed with an error.
run.cancelledPipeline run was cancelled by the user.
env.provisionedGuest environment has been provisioned (skills, config, mounts).
skill.mountedA skill has been written to the guest filesystem.
box.startedA VoidBox has started execution within a stage.
workflow.plannedA workflow planner has generated a pipeline plan.
log.chunkA chunk of streaming output from the guest (stdout/stderr).
log.closedThe output stream for a box has closed.
+
+ +
+

Trace Structure

+

VoidBox emits OpenTelemetry-compatible traces that capture the full execution hierarchy:

+
Pipeline span
+  └─ Stage 1 span (box_name="data_analyst")
+       ├─ tool_call event: Read("input.json")
+       ├─ tool_call event: Bash("curl ...")
+       └─ attributes: tokens_in, tokens_out, cost_usd, model
+  └─ Stage 2 span (box_name="quant_analyst")
+       └─ ...
+

Each stage span includes attributes for token counts, cost, model used, and individual tool call events. Fan-out stages create parallel child spans under the same pipeline parent.

+VoidBox tracing visualization +
+ +
+

Instrumentation

+
+
+

OTLP Traces

+

Full distributed traces exported via OTLP gRPC. Pipeline, stage, and tool-call spans with rich attributes for token usage, cost, model, and timing.

+
+
+

Metrics

+

Token counts (input/output), cost in USD, execution duration, and VM lifecycle timing. Exported as OTLP metrics alongside traces.

+
+
+

Structured Logs

+

All log output is prefixed with [vm:NAME] for easy filtering. Stream-json output from claude-code is parsed into structured events.

+
+
+

Guest Telemetry

+

The guest-agent reads /proc/stat and /proc/meminfo periodically, sending TelemetryBatch messages over vsock. The host-side TelemetryAggregator ingests these and exports as OTLP metrics.

+
+
+
+ +
+

Configuration

+ + + + + + + + +
Env varDescription
VOIDBOX_OTLP_ENDPOINTOTLP gRPC endpoint (e.g. http://localhost:4317)
OTEL_SERVICE_NAMEService name for traces (default: void-box)
+

OpenTelemetry support is enabled at compile time:

+
cargo build --features opentelemetry
+

For a full OTLP setup walkthrough with Jaeger or Grafana, see the Observability Setup guide.

+ +
+

Guest Telemetry Pipeline

+

The guest-side telemetry pipeline works independently from the host tracing system:

+
    +
  1. The guest-agent periodically reads /proc/stat (CPU usage) and /proc/meminfo (memory usage).
  2. +
  3. Readings are batched into a TelemetryBatch message and sent to the host over the vsock channel.
  4. +
  5. The host-side TelemetryAggregator receives batches, computes deltas, and exports them as OTLP metrics.
  6. +
+

This gives visibility into guest resource consumption without any instrumentation inside the workload itself.

+
+

Persistence Providers

-

Daemon run/session state uses a provider abstraction: disk (default), plus example adapters for sqlite and valkey.

+

Daemon run and session state uses a provider abstraction, allowing different storage backends:

+
+
+

Disk (default)

+

File-based persistence. Run state and events are stored as JSON files on the local filesystem. No external dependencies.

+
+
+

SQLite / Valkey

+

Adapter implementations for sqlite and valkey (Redis-compatible) backends. Useful for shared state in multi-node deployments.

+
+
+ +
+
diff --git a/site/docs/host-mounts/index.html b/site/docs/host-mounts/index.html new file mode 100644 index 0000000..7ba832b --- /dev/null +++ b/site/docs/host-mounts/index.html @@ -0,0 +1,110 @@ + + + +Host Mounts | Void-Box + + + + +
+
+
+ +
+
+
Host Mounts
+

Mount Host Directories into Guest VMs

+

VoidBox can mount host directories into the guest VM using sandbox.mounts. Each mount specifies a host path, a guest mount point, and a mode ("ro" or "rw", default "ro").

+

Read-write mounts write directly to the host directory — data persists across VM restarts since the host directory survives. This is the primary mechanism for stateful workloads.

+
+ +
+

Transport

+
+
+

Linux/KVM

+

9p (virtio-9p) — kernel-based 9P filesystem protocol over virtio transport.

+
+
+

macOS/VZ

+

virtiofs — Apple Virtualization.framework native shared directory support.

+
+
+
+ +
+

Mount Configuration

+

Each mount entry has three fields:

+ + + + + + + +
FieldDescriptionDefault
hostPath on the host filesystem(required)
guestMount point inside the guest VM(required)
mode"ro" (read-only) or "rw" (read-write)"ro"
+
+ +
+

YAML Example

+
+
sandbox.mounts
+
sandbox:
+  mounts:
+    - host: ./data
+      guest: /data
+      mode: rw        # persistent — host directory survives VM restarts
+    - host: ./config
+      guest: /config
+      mode: ro        # read-only (default)
+
+
+ +
+

Use Cases

+
+
+

Stateful Workloads

+

Use mode: rw mounts to persist agent output, databases, or generated artifacts across VM restarts. The host directory is the source of truth.

+
+
+

Shared Configuration

+

Use mode: ro mounts to inject configuration files, credentials, or reference data into the guest without risk of modification.

+
+
+
+
+

Persistent Data

+

Mount a host directory as rw to collect logs, results, or checkpoint files that survive VM lifecycle. Ideal for long-running pipelines.

+
+
+

Development Workflow

+

Mount your project source tree as ro to let the agent read and analyze code without modifying the host copy.

+
+
+
+
+
+
+ + + diff --git a/site/docs/index.html b/site/docs/index.html index 03486d4..a7103f4 100644 --- a/site/docs/index.html +++ b/site/docs/index.html @@ -3,7 +3,7 @@ - void-box docs + Docs | Void-Box @@ -20,7 +20,8 @@

Next

diff --git a/site/docs/oci-containers/index.html b/site/docs/oci-containers/index.html new file mode 100644 index 0000000..d4f43e0 --- /dev/null +++ b/site/docs/oci-containers/index.html @@ -0,0 +1,184 @@ + + + +OCI Containers | Void-Box + + + + +
+
+
+ +
+
+
OCI Containers
+

OCI Container Image Support

+

VoidBox supports OCI container images in three ways: as a pre-built guest image containing the kernel and initramfs, as a base image providing the full guest root filesystem, and as OCI skills that mount additional container images as read-only tool providers.

+

Images are pulled from Docker Hub, GHCR, or any OCI-compliant registry and cached locally at ~/.voidbox/oci/.

+
+ +
+

Guest Image (sandbox.guest_image)

+

Pre-built kernel + initramfs distributed as a FROM scratch OCI image containing two files: vmlinuz and rootfs.cpio.gz. Auto-pulled from GHCR on first run — no local toolchain needed.

+ +

Resolution Order

+

VoidBox resolves the kernel/initramfs using a 5-step chain:

+
+
Resolution chain
+
1. sandbox.kernel / sandbox.initramfs   (explicit paths in spec)
+2. VOID_BOX_KERNEL / VOID_BOX_INITRAMFS (env vars)
+3. sandbox.guest_image                  (explicit OCI ref)
+4. ghcr.io/the-void-ia/voidbox-guest:v{version}  (default auto-pull)
+5. None → mock fallback (mode: auto)
+
+

Cache layout: ~/.voidbox/oci/guest/<sha256>/vmlinuz + rootfs.cpio.gz + <sha256>.done marker.

+
+ +
+

Base Image (sandbox.image)

+

A full container image (e.g. python:3.12-slim) used as the guest root filesystem. The guest-agent switches root with overlayfs + pivot_root (or secure switch-root fallback when kernel returns EINVAL for initramfs root).

+ +
+
+

Linux/KVM

+

Host builds a cached ext4 disk artifact from the extracted OCI rootfs and attaches it as virtio-blk (guest sees /dev/vda).

+
+
+

macOS/VZ

+

Rootfs remains directory-mounted via virtiofs path. No block device needed.

+
+
+ +

Security properties are preserved across both paths: OCI root switch is driven only by kernel cmdline flags set by the trusted host, command allowlist + authenticated vsock control channel still gate execution, and the writable layer is tmpfs-backed while the base OCI lowerdir remains read-only.

+

Cache layout: ~/.voidbox/oci/rootfs/<sha256>/ (full layer extraction with whiteout handling).

+
+ +
+

OCI Skills

+

Mount additional container images as read-only tool providers at arbitrary guest paths. Each skill image is pulled, extracted, and mounted independently — no sandbox.image required. This lets you compose language runtimes (Python, Go, Java, etc.) without baking them into the initramfs.

+ +
+
examples/specs/oci/skills.yaml
+
api_version: v1
+kind: agent
+name: multi-tool-agent
+
+sandbox:
+  mode: auto
+  memory_mb: 2048
+  vcpus: 2
+  network: true
+
+llm:
+  provider: ollama
+  model: "qwen2.5-coder:7b"
+
+agent:
+  prompt: >
+    You have Python, Go, and Java available as mounted skills.
+    Set up PATH to include the skill binaries:
+      export PATH=/skills/python/usr/local/bin:/skills/go/usr/local/go/bin:/skills/java/bin:$PATH
+
+    Write a "Hello from <language>" one-liner in each language and run all three.
+    Report which versions are installed.
+  skills:
+    - "agent:claude-code"
+    - image: "python:3.12-slim"
+      mount: "/skills/python"
+    - image: "golang:1.23-alpine"
+      mount: "/skills/go"
+    - image: "eclipse-temurin:21-jdk-alpine"
+      mount: "/skills/java"
+  timeout_secs: 300
+
+
+ +
+

Cache Layout

+
~/.voidbox/oci/
+  blobs/     # Content-addressed blob cache
+  rootfs/    # Extracted OCI rootfs layers (per sha256)
+  guest/     # Guest image cache (kernel + initramfs)
+
+ +
+

OCI Client Internals

+

The voidbox-oci/ crate provides the OCI distribution client:

+ + + + + + + + + +
ModulePurpose
registry.rsOCI Distribution HTTP client (anonymous + bearer auth, HTTP for localhost)
manifest.rsManifest / image index parsing, platform selection
cache.rsContent-addressed blob cache + rootfs/guest done markers
unpack.rsLayer extraction (full rootfs with whiteouts, or selective guest file extraction)
lib.rsOciClient: pull(), resolve_rootfs(), resolve_guest_files()
+
+ +
+

Example Specs

+

All OCI examples are in examples/specs/oci/:

+ + + + + + + + + +
SpecDescription
agent.yamlSingle agent with sandbox.image: python:3.12-slim
workflow.yamlWorkflow with sandbox.image: alpine:3.20 (no LLM)
pipeline.yamlMulti-language pipeline: Python base + Go and Java OCI skills
skills.yamlOCI skills only (Python, Go, Java) mounted into default initramfs
guest-image-workflow.yamlWorkflow using sandbox.guest_image for auto-pulled kernel + initramfs
+
+ +
+

Running

+
+
+

Linux (KVM)

+
+
code-run
+
VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \
+VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \
+cargo run --bin voidbox -- run \
+  --file examples/specs/oci/skills.yaml
+
+
+
+

macOS (Virtualization.framework)

+
+
code-run
+
VOID_BOX_KERNEL=target/vmlinux-arm64 \
+VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \
+cargo run --bin voidbox -- run \
+  --file examples/specs/oci/skills.yaml
+
+
+
+
+
+
+
+ + + diff --git a/site/docs/runtime/index.html b/site/docs/runtime/index.html index 8d2a7f4..fee10bb 100644 --- a/site/docs/runtime/index.html +++ b/site/docs/runtime/index.html @@ -1,7 +1,7 @@ -void-box runtime model +Runtime Model | Void-Box -
+
+
+
+ +
+
Runtime Model

Claude Code First-Class Runtime

-

VoidBox uses claude-code as the canonical agent runtime. This is the execution identity in guest environments.

-

Important Clarification

When configured for Ollama, VoidBox still runs claude-code; only the provider backend changes via runtime env config.

+

VoidBox uses claude-code as the canonical agent runtime. This is the execution identity inside every guest environment -- regardless of which LLM provider backend is configured, the guest always runs claude-code.

+ +
+

LLM Provider Backends

+
+
+

Claude API (default)

+

The default path. VoidBox provisions your ANTHROPIC_API_KEY into the guest environment and claude-code calls the Claude API directly over the SLIRP network.

+
+
+

Ollama (Claude-compatible mode)

+

When configured for Ollama, VoidBox still runs claude-code -- only the provider backend changes. The guest reaches Ollama on the host via the SLIRP gateway (10.0.2.2:11434). Claude-code's provider compatibility layer handles the translation.

+
+
+
+

Backend Selection

-
# default provider path
+
# Default provider path (Claude API)
 cargo run --bin voidbox -- run --file examples/specs/hackernews_agent.json
 
-# same spec, ollama backend through claude-code compatibility
+# Same spec, Ollama backend through claude-code compatibility
 VOIDBOX_LLM_PROVIDER=ollama \
 VOIDBOX_LLM_MODEL=qwen2.5-coder:7b \
 cargo run --bin voidbox -- run --file examples/specs/hackernews_agent.json
+ +
+

Skill Types

+

Skills are the composable units of capability injected into a VoidBox. Each type is provisioned differently in the guest environment:

+ + + + + + + + + + + +
TypeConstructorProvisioned asExample
AgentSkill::agent("claude-code")Reasoning engine designationThe LLM itself
FileSkill::file("path/to/SKILL.md")~/.claude/skills/{name}.mdDomain methodology
RemoteSkill::remote("owner/repo/skill")Fetched from GitHub, written to skills/obra/superpowers/brainstorming
MCPSkill::mcp("server-name")Entry in ~/.claude/mcp.jsonStructured tool server
CLISkill::cli("jq")Expected in guest initramfsBinary tool
+
+ +
+

Guest Execution Model

+

Inside the micro-VM, the guest-agent runs as PID 1 and controls the full execution lifecycle:

+
    +
  1. Authentication -- Validates the session secret received over vsock against the value injected via kernel cmdline at boot.
  2. +
  3. Policy enforcement -- Reads /etc/voidbox/allowed_commands.json (command allowlist) and /etc/voidbox/resource_limits.json (rlimits). Applies setrlimit constraints for memory, file descriptors, and process count.
  4. +
  5. Privilege drop -- Drops from root to uid:1000 before executing any user workload.
  6. +
  7. Fork + exec -- Launches claude-code with --output-format stream-json, streaming structured output back to the host over vsock.
  8. +
+

Skills are pre-provisioned before execution: file skills are written to ~/.claude/skills/, MCP entries go to ~/.claude/mcp.json, and OCI skill images are mounted read-only at their declared paths.

+
+

Compatibility Guardrails

-

Runs should fail fast when guest image/runtime is incompatible with required execution mode. Use production guest image builds for runtime examples.

+

Runs fail fast when the guest image or runtime is incompatible with the required execution mode. This prevents silent failures where a spec expects capabilities not present in the guest. Use production guest image builds for runtime examples.

+ +
+
diff --git a/site/docs/security/index.html b/site/docs/security/index.html new file mode 100644 index 0000000..f04a479 --- /dev/null +++ b/site/docs/security/index.html @@ -0,0 +1,151 @@ + + + +Security | Void-Box + + + + +
+
+
+ +
+
+
Security Model
+

Defense in Depth

+

VoidBox uses a layered security model with five distinct isolation boundaries. Each layer provides independent protection — compromise of one layer does not grant access through subsequent layers.

+
+ +
+

Five Layers of Defense

+
+
Defense in depth
+
Layer 1: Hardware isolation (KVM)
+  — Separate kernel, memory space, devices per VM
+
+Layer 2: Seccomp-BPF (VMM process)
+  — VMM thread restricted to KVM ioctls + vsock + networking syscalls
+
+Layer 3: Session authentication (vsock)
+  — 32-byte random secret, per-VM, injected at boot
+
+Layer 4: Guest hardening (guest-agent)
+  — Command allowlist, rlimits, privilege drop, timeout watchdog
+
+Layer 5: Network isolation (SLIRP)
+  — Rate limiting, max connections, CIDR deny list
+
+
+ +
+

Layer 1: Hardware Isolation (KVM)

+

Each VoidBox runs in its own micro-VM with a separate kernel, memory space, and devices. Hardware virtualization enforces isolation — not advisory process controls. On macOS, Apple's Virtualization.framework provides equivalent hypervisor-level isolation.

+
+ +
+

Layer 2: Seccomp-BPF (VMM Process)

+

The VMM thread is restricted via seccomp-BPF to only the syscalls needed for KVM operation: KVM ioctls, vsock communication, and networking syscalls. All other syscalls are blocked at the kernel level.

+
+ +
+

Layer 3: Session Authentication (vsock)

+

Every VM gets a unique 32-byte random session secret, injected via kernel command line. The guest-agent requires this secret on every request.

+
+
Session secret flow
+
Host                                    Guest
+  |                                       |
+  +-- getrandom(32 bytes)                 |
+  +-- hex-encode -> kernel cmdline        |
+  |   voidbox.secret=abc123...            |
+  |                                       |
+  |              boot                     |
+  | ------------------------------------> |
+  |                                       +-- parse /proc/cmdline
+  |                                       +-- store in OnceLock
+  |                                       |
+  +-- ExecRequest { secret: "abc123..." } |
+  | ------------------------------------> |
+  |                                       +-- verify secret
+  |                                       +-- execute if match
+  | <------------------------------------ |
+  |  ExecResponse { ... }                 |
+
+
+ +
+

Layer 4: Guest Hardening (guest-agent)

+

The guest-agent (PID 1) enforces four independent controls:

+
+
+

Command Allowlist

+

Only approved binaries execute. The allowlist is read from /etc/voidbox/allowed_commands.json, provisioned by the trusted host at boot.

+
+
+

Resource Limits

+

setrlimit enforces memory, file descriptor, and process count limits. Read from /etc/voidbox/resource_limits.json.

+
+
+

Privilege Drop

+

Child processes run as uid:1000. The guest-agent drops privileges before executing any command, preventing root access inside the VM.

+
+
+

Timeout Watchdog

+

A watchdog timer sends SIGKILL to child processes that exceed the configured timeout, preventing runaway execution.

+
+
+
+ +
+

Layer 5: Network Isolation (SLIRP)

+

VoidBox uses smoltcp-based usermode networking (SLIRP) — no root, no TAP devices, no bridge configuration.

+
    +
  • Rate limiting on new connections — prevents connection floods from guest
  • +
  • Maximum concurrent connection limit — bounds host resource usage
  • +
  • CIDR deny list — configurable via ipnet, blocks access to specified network ranges
  • +
+
+ +
+

Snapshot Security Considerations

+

Snapshot cloning shares identical VM state across restored instances. Three areas require awareness:

+
+
+

RNG Entropy

+

Restored VMs inherit the same /dev/urandom pool. Mitigated by: fresh CID per restore, hardware RDRAND re-seeding on rdtsc.

+
+
+

ASLR

+

Clones share guest page table layout. Mitigated by: short-lived tasks, no direct network addressability (SLIRP NAT), command allowlist limiting attack surface.

+
+
+
+

Session Isolation

+

Restored VMs reuse the snapshot's stored session secret for vsock authentication (the secret is baked into the guest's kernel cmdline in snapshot memory). Per-restore secret rotation would require guest-side support.

+
+
+
+
+
+ + + diff --git a/site/docs/snapshots/index.html b/site/docs/snapshots/index.html new file mode 100644 index 0000000..6891ce3 --- /dev/null +++ b/site/docs/snapshots/index.html @@ -0,0 +1,266 @@ + + + +Snapshots | Void-Box + + + + +
+
+
+ +
+
+
Snapshots
+

Sub-Second VM Restore

+

VoidBox supports sub-second VM restore via snapshot/restore. Snapshots capture the full VM state (vCPU registers, memory, devices) and restore via COW mmap — the guest resumes execution without re-booting the kernel or re-running initialization.

+

All snapshot features are explicit opt-in only. If you never set a snapshot field, the system behaves exactly as before — cold boot, zero snapshot code runs.

+
+ +
+

Snapshot Types

+ + + + + + +
TypeWhen CreatedContentsUse Case
BaseAfter cold boot, VM stoppedFull memory dump + all KVM stateGolden image for repeated boots
DiffAfter dirty tracking enabled, VM stoppedOnly modified pages since baseLayered caching (base + delta)
+
+ +
+

YAML Spec

+
+
+

Top-level snapshot

+
# Applies to all boxes
+sandbox:
+  memory_mb: 256
+  snapshot: "abc123def456"
+
+
+

Per-box override

+
pipeline:
+  boxes:
+    - name: analyst
+      prompt: "analyze data"
+      sandbox:
+        snapshot: "def789"
+    - name: coder
+      prompt: "write code"
+      # no snapshot = cold boot
+
+
+
+ +
+

Rust API

+
+
Rust
+
use void_box::agent_box::VoidBox;
+
+// Cold boot (default — no snapshot)
+let box1 = VoidBox::new("analyst")
+    .prompt("analyze data")
+    .memory_mb(256)
+    .build()?;
+
+// Restore from snapshot (explicit opt-in)
+let box2 = VoidBox::new("analyst")
+    .prompt("analyze data")
+    .snapshot("/path/to/snapshot/dir")   // or hash prefix
+    .build()?;
+
+
+ +
+

CLI Commands

+
+
Shell
+
# Create a snapshot from a running VM
+voidbox snapshot create --config-hash <hash>
+
+# List stored snapshots
+voidbox snapshot list
+
+# Delete a snapshot
+voidbox snapshot delete <hash-prefix>
+
+# Run with a snapshot (via spec)
+voidbox run --file spec.yaml   # spec has sandbox.snapshot set
+
+
+ +
+

Daemon API

+
+
code-run
+
# POST /runs with snapshot override
+curl -X POST http://localhost:8080/runs \
+  -H 'Content-Type: application/json' \
+  -d '{"file": "workflow.yaml", "snapshot": "abc123def456"}'
+
+
+ +
+

Design Principles

+
    +
  • No snapshot field set → cold boot, zero snapshot code runs
  • +
  • No auto-detection of existing snapshots
  • +
  • No auto-creation of snapshots during normal runs
  • +
  • No auto-restore — only if the user passes an explicit path or hash
  • +
  • No env var fallback — spec or code only
  • +
  • Every new field defaults to None — the system behaves identically to before if untouched
  • +
+
+ +
+

Performance Benchmarks

+

Measured on Linux/KVM with 256 MB RAM, 1 vCPU, userspace virtio-vsock:

+ + + + + + + + + + + +
PhaseTimeNotes
Cold boot~10 ms
Base snapshot~420 msFull 256 MB memory dump
Base restore~1.3 msCOW mmap, lazy page loading
Diff snapshot~270 msOnly dirty pages (~1.5 MB, 0.6% of RAM)
Diff restore~3 msBase COW mmap + dirty page overlay
Base speedup~8xCold boot / base restore
Diff savings99.4%Memory file size reduction
+
+ +
+

Storage Layout

+
~/.void-box/snapshots/
+  <hash-prefix>/        # first 16 chars of config hash
+      state.bin          # bincode: VmSnapshot (vCPU regs, irqchip, PIT, vsock, config)
+      memory.mem         # full memory dump (base)
+      memory.diff        # dirty pages only (diff snapshots)
+
+ +
+

Restore Flow

+

The 7-step restore process:

+
+
Restore sequence
+
1. VmSnapshot::load(dir)           Read state.bin (vCPU, irqchip, PIT, vsock, config)
+2. Vm::new(memory_mb)              Create KVM VM with matching memory size
+3. restore_memory(mem, path)       COW mmap(MAP_PRIVATE|MAP_FIXED) — lazy page loading
+4. vm.restore_irqchip(state)       Restore PIC master/slave + IOAPIC
+5. VirtioVsockMmio::restore()      Restore vsock device registers (userspace backend)
+6. create_vcpu_restored(state)     Per-vCPU restore (see register restore order below)
+7. vCPU threads resume             Guest continues execution from snapshot point
+
+
+ +
+

Memory Restore

+

Memory restore uses kernel MAP_PRIVATE lazy page loading — pages are demand-faulted from the file, writes create anonymous copies. No userfaultfd required.

+
+ +
+

vCPU Register Restore Order

+

The restore sequence in cpu.rs is order-sensitive. Getting it wrong causes silent guest crashes (kernel panic → reboot via port 0x64).

+
+
Register restore order (7-step, order-sensitive)
+
1. MSRs              KVM_SET_MSRS
+2. sregs             KVM_SET_SREGS (segment regs, CR0/CR3/CR4)
+3. LAPIC             KVM_SET_LAPIC + periodic timer bootstrap (see below)
+4. vcpu_events       KVM_SET_VCPU_EVENTS (exception/interrupt state)
+5. XCRs (XCR0)       KVM_SET_XCRS — MUST come before xsave
+6. xsave (FPU/SSE)   KVM_SET_XSAVE — depends on XCR0 for feature mask
+7. regs              KVM_SET_REGS (GP registers, RIP, RFLAGS)
+
+

XCR0 restore is critical. XCR0 controls which XSAVE features (x87, SSE, AVX) are active. Without it, the guest's XRSTORS instruction triggers a #GP because the default XCR0 only enables x87, but the guest's XSAVE area references SSE/AVX features.

+
+ +
+

LAPIC Timer Bootstrap

+

When the guest was idle (NO_HZ) at snapshot time, the LAPIC timer is masked with vector=0 (LVTT=0x10000). After restore, no timer interrupt ever fires, so the scheduler never runs. The restore code detects this state and bootstraps a periodic LAPIC timer (mode=periodic, vector=0xEC, TMICT=0x200000, TDCR=divide-by-1) to kick the scheduler back to life.

+
+ +
+

Vsock Backend for Snapshot

+

The userspace virtio-vsock backend must be used for VMs that will be snapshotted. The kernel vhost backend (/dev/vhost-vsock) does not expose internal vring indices, making queue state capture incomplete. The userspace backend tracks last_avail_idx/last_used_idx directly, ensuring clean snapshot/restore of the virtqueue state.

+
+ +
+

CID Preservation

+

The snapshot stores the VM's actual CID (assigned at cold boot). On restore, the same CID is reused — the guest kernel caches the CID during virtio-vsock probe and silently drops packets with mismatched dst_cid.

+
+ +
+

Opt-in Plumbing

+

Every layer has an optional snapshot field that defaults to None:

+ + + + + + + + + +
LayerFieldTypeDefault
SandboxBuilder.snapshot(path)Option<PathBuf>None
BoxConfigsnapshotOption<PathBuf>None
SandboxSpec (YAML)sandbox.snapshotOption<String>None
BoxSandboxOverridesandbox.snapshotOption<String>None
CreateRunRequest (API)snapshotOption<String>None
+

Resolution chain: per-box override → top-level spec → None (cold boot).

+
+ +
+

Snapshot Resolution

+

When a snapshot string is provided, the runtime resolves it as:

+
    +
  1. Hash prefix~/.void-box/snapshots/<prefix>/ (if state.bin exists)
  2. +
  3. Literal path → treat as directory path (if state.bin exists)
  4. +
  5. Neither → warning printed, cold boot
  6. +
+

No env var fallback, no auto-detection.

+
+ +
+

Cache Management

+
    +
  • LRU eviction: evict_lru(max_bytes) removes oldest snapshots first
  • +
  • Layer hashing: compute_layer_hash(base, layer, content) for deterministic cache keys
  • +
  • Listing: list_snapshots() / voidbox snapshot list
  • +
  • Deletion: delete_snapshot(prefix) / voidbox snapshot delete <prefix>
  • +
+

Snapshot cache is stored at ~/.void-box/snapshots/.

+
+ +
+

Security Considerations

+

Snapshot cloning shares identical VM state across restored instances:

+
    +
  • RNG entropy: Restored VMs inherit the same /dev/urandom pool. Mitigated by: fresh CID per restore, hardware RDRAND re-seeding on rdtsc.
  • +
  • ASLR: Clones share guest page table layout. Mitigated by: short-lived tasks, no direct network addressability (SLIRP NAT), command allowlist limiting attack surface.
  • +
  • Session isolation: Restored VMs reuse the snapshot's stored session secret for vsock authentication (the secret is baked into the guest's kernel cmdline in snapshot memory). Per-restore secret rotation would require guest-side support.
  • +
+
+
+
+
+ + + diff --git a/site/docs/wire-protocol/index.html b/site/docs/wire-protocol/index.html new file mode 100644 index 0000000..e06fae0 --- /dev/null +++ b/site/docs/wire-protocol/index.html @@ -0,0 +1,132 @@ + + + +Wire Protocol | Void-Box + + + + +
+
+
+ +
+
+
Wire Protocol
+

Host-Guest Communication

+

Host and guest communicate over AF_VSOCK (port 1234) using the void-box-protocol crate. The protocol uses a simple length-prefixed binary framing with JSON payloads.

+
+ +
+

Frame Format

+
+
Binary frame layout
+
+---------------+-----------+--------------------+
+| length (4 B)  | type (1B) | payload (N bytes)  |
++---------------+-----------+--------------------+
+
+ + + + + + + + +
FieldSizeDescription
length4 bytesu32 little-endian, payload size only (excludes the 5-byte header)
type1 byteMessage type discriminant
payloadN bytesJSON-encoded body
+
+ +
+

Message Types

+ + + + + + + + + + + + + + + + + +
Type ByteDirectionMessageDescription
0x01host → guestExecRequestExecute a command (program, args, env, timeout)
0x02guest → hostExecResponseCommand result (stdout, stderr, exit_code)
0x03bothPingSession authentication handshake
0x04guest → hostPongAuthentication reply with protocol version
0x05host → guestShutdownRequest guest shutdown
0x0Ahost → guestSubscribeTelemetryStart telemetry stream
0x0Bhost → guestWriteFileWrite file to guest filesystem
0x0Cguest → hostWriteFileResponseWrite file acknowledgement
0x0Dhost → guestMkdirPCreate directory tree
0x0Eguest → hostMkdirPResponseMkdir acknowledgement
0x0Fguest → hostExecOutputChunkStreaming output chunk (stream, data, seq)
0x10host → guestExecOutputAckFlow control ack (optional)
0x11bothSnapshotReadyGuest signals readiness for live snapshot
+
+ +
+

Security

+
+
+

MAX_MESSAGE_SIZE

+

64 MB — prevents OOM from untrusted length fields. Messages exceeding this limit are rejected before allocation.

+
+
+

Session Secret

+

32-byte hex token injected as voidbox.secret=<hex> in kernel cmdline. The guest-agent reads it from /proc/cmdline at boot and requires it in every ExecRequest.

+
+
+
+

ExecRequest Debug Redaction

+

The Debug impl for ExecRequest redacts environment variables matching KEY, SECRET, TOKEN, PASSWORD patterns — preventing accidental credential exposure in logs.

+
+
+ +
+

Network Layout (SLIRP)

+

VoidBox uses smoltcp-based usermode networking (SLIRP) — no root, no TAP devices, no bridge configuration.

+
+
Network topology
+
Guest VM                                    Host
++---------------------+                    +------------------+
+| eth0: 10.0.2.15/24  |                    |                  |
+| gw:   10.0.2.2      |-- virtio-net ------| SLIRP stack      |
+| dns:  10.0.2.3      |   (MMIO)           | (smoltcp)        |
++---------------------+                    |                  |
+                                           | 10.0.2.2 -> NAT  |
+                                           |   -> 127.0.0.1   |
+                                           +------------------+
+
+
+ +
+

Guest/Host IP Details

+ + + + + + + +
EndpointAddressDescription
Guest IP10.0.2.15/24Static IP assigned to guest eth0
Gateway10.0.2.2Mapped to host 127.0.0.1 — guest reaches host services via this address
DNS10.0.2.3Forwarded to host resolver
+

Outbound TCP/UDP is NATed through the host. The guest reaches host services (e.g. Ollama on :11434) via 10.0.2.2.

+
+
+
+
+ + + diff --git a/site/guides/ai-agent-sandboxing/index.html b/site/guides/ai-agent-sandboxing/index.html index 436786b..da2b43b 100644 --- a/site/guides/ai-agent-sandboxing/index.html +++ b/site/guides/ai-agent-sandboxing/index.html @@ -3,7 +3,7 @@ - AI Agent Sandboxing | void-box guide + AI Agent Sandboxing | Void-Box @@ -20,7 +20,8 @@
void-box logoVoid-Box diff --git a/site/guides/getting-started/index.html b/site/guides/getting-started/index.html new file mode 100644 index 0000000..f1cdd12 --- /dev/null +++ b/site/guides/getting-started/index.html @@ -0,0 +1,142 @@ + + + + + + Getting Started | Void-Box + + + + + + +
+
+ void-box logoVoid-Box + +
+
+ +
+
+
Guide
+

Getting Started

+

This guide walks you through installing VoidBox, defining your first agent, and running it. By the end you will have an isolated micro-VM executing a prompt-driven workflow.

+ +

Prerequisites

+
+
    +
  • Linux — Any host with /dev/kvm available (most cloud instances and bare-metal servers).
  • +
  • macOS — Apple Silicon Mac (M1 or later). Uses Virtualization.framework natively.
  • +
  • Rust 1.83+ — Install via rustup if you do not have it.
  • +
+
+ +

Install

+

Add VoidBox as a library dependency:

+
+
Terminal
+
cargo add void-box
+
+ +

Or install the CLI binary:

+
+
Terminal
+
cargo install void-box
+
+ +

First Agent (Rust API)

+

Declare skills, bind them to an isolated execution boundary, and run:

+
use void_box::agent_box::VoidBox;
+use void_box::skill::Skill;
+use void_box::llm::LlmProvider;
+
+// Skills = declared capabilities
+let hn_api = Skill::file("skills/hackernews-api.md")
+    .description("HN API via curl + jq");
+
+let reasoning = Skill::agent("claude-code")
+    .description("Autonomous reasoning and code execution");
+
+// VoidBox = Agent(Skills) + Isolation
+let researcher = VoidBox::new("hn_researcher")
+    .skill(hn_api)
+    .skill(reasoning)
+    .llm(LlmProvider::ollama("qwen3-coder"))
+    .memory_mb(1024)
+    .network(true)
+    .prompt("Analyze top HN stories for AI engineering trends")
+    .build()?;
+ +

First Agent (YAML)

+

The same agent defined declaratively:

+
# hackernews_agent.yaml
+api_version: v1
+kind: agent
+name: hn_researcher
+
+sandbox:
+  mode: auto
+  memory_mb: 1024
+  network: true
+
+llm:
+  provider: ollama
+  model: qwen3-coder
+
+agent:
+  prompt: "Analyze top HN stories for AI engineering trends"
+  skills:
+    - "file:skills/hackernews-api.md"
+    - "agent:claude-code"
+  timeout_secs: 600
+ +

Run It

+

With the Rust API:

+
+
Terminal
+
cargo run
+
+ +

With the CLI and a YAML spec:

+
+
Terminal
+
voidbox run --file hackernews_agent.yaml
+
+ +

What Happens

+

When you run a VoidBox agent, the following sequence executes automatically:

+
    +
  1. OCI image auto-pull — The guest image (kernel + initramfs) is pulled from GHCR and cached locally. No manual build steps required.
  2. +
  3. VM boot — A micro-VM boots with hardware isolation (KVM on Linux, Virtualization.framework on macOS).
  4. +
  5. Guest-agent init — The guest-agent (PID 1) authenticates over vsock, applies security policies, and drops privileges.
  6. +
  7. claude-code execution — The Claude Code runtime executes your prompt with the declared skills, calling the configured LLM backend.
  8. +
  9. Result return — Structured output (tokens, cost, tool calls, result text) is returned over vsock to the host.
  10. +
+ +

Next Steps

+ +
+
+ + + + + diff --git a/site/guides/index.html b/site/guides/index.html index 41e75bb..9f43420 100644 --- a/site/guides/index.html +++ b/site/guides/index.html @@ -3,7 +3,7 @@ - void-box guides + Guides | Void-Box @@ -20,7 +20,8 @@
void-box logoVoid-Box @@ -32,6 +33,10 @@

Guides

Practical implementation walkthroughs.

+ Getting StartedInstall void-box, create your first agent, and run it inside a micro-VM. + Running on LinuxKVM zero-setup with auto-pulled guest images, manual builds, mock mode, and testing. + Running on macOSApple Silicon setup with Virtualization.framework — native micro-VMs, no Docker needed. + Observability SetupOTLP traces, metrics, and a ready-to-run Grafana + Tempo + Prometheus playground. AI Agent SandboxingExecute capability-driven agents inside isolated micro-VM boundaries. Pipeline CompositionBuild multi-stage pipelines with .pipe() and .fan_out() — fresh VM per stage, no state leaks. Declarative YAML SpecsDefine agents and pipelines as config files and run them with void-box run. diff --git a/site/guides/observability-setup/index.html b/site/guides/observability-setup/index.html new file mode 100644 index 0000000..c916180 --- /dev/null +++ b/site/guides/observability-setup/index.html @@ -0,0 +1,109 @@ + + + + + + Observability Setup | Void-Box + + + + + + +
+
+ void-box logoVoid-Box + +
+
+ +
+
+
Guide
+

Observability Setup

+

Every pipeline run is fully instrumented out of the box. Each VM stage emits spans and metrics via OTLP, giving you end-to-end visibility across isolated execution boundaries — from pipeline orchestration down to individual tool calls inside each micro-VM.

+ +

+ Pipeline trace waterfall in Grafana Tempo +

+ +

What's Included

+
+
    +
  • OTLP traces — Per-box spans, tool call events, pipeline-level trace context.
  • +
  • Metrics — Token counts, cost, and duration per stage.
  • +
  • Structured logs[vm:NAME] prefixed and trace-correlated for easy filtering.
  • +
  • Guest telemetry — procfs metrics (CPU, memory) exported from the guest to the host via vsock.
  • +
+
+ +

Enable OTLP

+

Build with the opentelemetry feature flag and set the OTLP endpoint:

+
+
Terminal
+
cargo build --features opentelemetry
+
+ +

Then set the endpoint environment variable when running:

+
+
Terminal
+
VOIDBOX_OTLP_ENDPOINT=http://localhost:4317 \
+cargo run --bin voidbox -- run --file agent.yaml
+
+ +

Configuration

+
+ + + + + + +
Environment VariableDescription
VOIDBOX_OTLP_ENDPOINTOTLP gRPC endpoint (e.g. http://localhost:4317)
OTEL_SERVICE_NAMEService name for traces (default: void-box)
+
+ +

Trace Structure

+

Traces follow a hierarchical structure from the pipeline level down to individual tool calls within each VM stage:

+
Pipeline span
+  └─ Stage 1 span (box_name="data_analyst")
+       ├─ tool_call event: Read("input.json")
+       ├─ tool_call event: Bash("curl ...")
+       └─ attributes: tokens_in, tokens_out, cost_usd, model
+  └─ Stage 2 span (box_name="quant_analyst")
+       └─ ...
+

Each stage span carries attributes for token counts, cost, model used, and duration. Tool call events are recorded as span events within the stage span.

+ +

Guest Telemetry

+

The guest-agent inside each micro-VM periodically reads /proc/stat and /proc/meminfo, then sends TelemetryBatch messages over vsock to the host. On the host side, the TelemetryAggregator ingests these batches and exports them as OTLP metrics.

+
+

Guest telemetry gives you per-VM resource utilization without any agent-side instrumentation. CPU and memory metrics flow automatically as long as the guest-agent is running.

+
+ +

Playground

+

The repository includes a ready-to-run observability stack in the playground/ directory with pre-configured:

+
    +
  • Grafana — Dashboards for pipeline traces and metrics.
  • +
  • Tempo — Distributed trace backend for OTLP ingestion.
  • +
  • Prometheus — Metrics collection and storage.
  • +
+

See the playground/ directory in the repository for setup instructions.

+
+
+ + + + + diff --git a/site/guides/ollama-local/index.html b/site/guides/ollama-local/index.html index c793210..b21c603 100644 --- a/site/guides/ollama-local/index.html +++ b/site/guides/ollama-local/index.html @@ -3,7 +3,7 @@ - Local LLMs with Ollama | void-box guide + Local LLMs with Ollama | Void-Box @@ -20,7 +20,8 @@
void-box logoVoid-Box diff --git a/site/guides/pipeline-composition/index.html b/site/guides/pipeline-composition/index.html index fd30feb..f0c46b3 100644 --- a/site/guides/pipeline-composition/index.html +++ b/site/guides/pipeline-composition/index.html @@ -3,7 +3,7 @@ - Pipeline Composition | void-box guide + Pipeline Composition | Void-Box @@ -20,7 +20,8 @@
void-box logoVoid-Box diff --git a/site/guides/running-on-linux/index.html b/site/guides/running-on-linux/index.html new file mode 100644 index 0000000..4bce1d8 --- /dev/null +++ b/site/guides/running-on-linux/index.html @@ -0,0 +1,163 @@ + + + + + + Running on Linux | Void-Box + + + + + + +
+
+ void-box logoVoid-Box + +
+
+ +
+
+
Guide
+

Running on Linux

+

VoidBox runs natively on any Linux host with /dev/kvm. This guide covers zero-setup mode, manual image builds, mock mode for development, and running the test suite.

+ +

KVM Mode (Zero-Setup)

+

On a Linux host with /dev/kvm, VoidBox auto-pulls a pre-built guest image (kernel + initramfs) from GHCR on first run. No manual build steps required:

+
+
Terminal
+
# Just works — guest image is pulled and cached automatically
+ANTHROPIC_API_KEY=sk-ant-xxx \
+cargo run --bin voidbox -- run --file examples/specs/oci/agent.yaml
+
+# Or with Ollama
+cargo run --bin voidbox -- run --file examples/specs/oci/workflow.yaml
+
+ +

The guest image (ghcr.io/the-void-ia/voidbox-guest) contains the kernel and initramfs with guest-agent, busybox, and common tools. It is cached at ~/.voidbox/oci/guest/ after the first pull.

+ +

Resolution Order

+

VoidBox resolves the kernel and initramfs using a 5-step chain:

+
    +
  1. sandbox.kernel / sandbox.initramfs in the spec (explicit paths)
  2. +
  3. VOID_BOX_KERNEL / VOID_BOX_INITRAMFS env vars
  4. +
  5. sandbox.guest_image in the spec (explicit OCI ref)
  6. +
  7. Default: ghcr.io/the-void-ia/voidbox-guest:v{version} (auto-pull)
  8. +
  9. Mock fallback when mode: auto
  10. +
+ +

Custom Guest Image

+

To use a custom guest image or disable auto-pull:

+
sandbox:
+  # Use a specific guest image
+  guest_image: "ghcr.io/the-void-ia/voidbox-guest:latest"
+
+  # Or disable auto-pull (empty string)
+  # guest_image: ""
+ +

KVM Mode (Manual Build)

+

If you prefer to build the guest image locally:

+
+
Terminal
+
# Build base guest initramfs (guest-agent + tools; no Claude bundle)
+scripts/build_guest_image.sh
+
+# Download a kernel
+scripts/download_kernel.sh
+
+# Run with explicit paths
+ANTHROPIC_API_KEY=sk-ant-xxx \
+VOID_BOX_KERNEL=target/vmlinuz-amd64 \
+VOID_BOX_INITRAMFS=/tmp/void-box-rootfs.cpio.gz \
+cargo run --example trading_pipeline
+
+ +

For a production Claude-capable initramfs:

+
+
Terminal
+
# Build production rootfs/initramfs with native claude-code + CA certs + sandbox user
+scripts/build_claude_rootfs.sh
+
+ +

Script Intent Summary

+
+ + + + + + + +
ScriptPurpose
scripts/build_guest_image.shBase runtime image for general VM/OCI work
scripts/build_claude_rootfs.shProduction image for direct Claude runtime in guest
scripts/build_test_image.shDeterministic test image with claudio mock
+
+ +

Mock Mode

+

No KVM required. Mock mode lets you develop and test pipeline logic without hardware virtualization:

+
+
Terminal
+
cargo run --example quick_demo
+cargo run --example trading_pipeline
+cargo run --example parallel_pipeline
+
+ +

Parallel Pipeline

+

Run a parallel pipeline with per-box model overrides using environment variables:

+
+
Terminal
+
OLLAMA_MODEL=phi4-mini \
+OLLAMA_MODEL_QUANT=qwen3-coder \
+OLLAMA_MODEL_SENTIMENT=phi4-mini \
+VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \
+VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \
+cargo run --example parallel_pipeline
+
+ +

Running Tests

+ +

Unit Tests

+
+
Terminal
+
cargo test --lib
+
+ +

Integration Tests (Mock)

+
+
Terminal
+
cargo test --test skill_pipeline
+
+ +

Integration Tests

+
+
Terminal
+
cargo test --test integration
+
+ +

E2E Tests (KVM + test initramfs)

+
+
Terminal
+
scripts/build_test_image.sh
+VOID_BOX_KERNEL=/boot/vmlinuz-$(uname -r) \
+VOID_BOX_INITRAMFS=/tmp/void-box-test-rootfs.cpio.gz \
+cargo test --test e2e_skill_pipeline -- --ignored --test-threads=1
+
+
+
+ + + + + diff --git a/site/guides/running-on-macos/index.html b/site/guides/running-on-macos/index.html new file mode 100644 index 0000000..9740291 --- /dev/null +++ b/site/guides/running-on-macos/index.html @@ -0,0 +1,111 @@ + + + + + + Running on macOS | Void-Box + + + + + + +
+
+ void-box logoVoid-Box + +
+
+ +
+
+
Guide
+

Running on macOS

+

VoidBox runs natively on Apple Silicon Macs using Apple's Virtualization.framework. No Docker or Linux VM required.

+ +

Overview

+
+

VoidBox on macOS uses Virtualization.framework (VZ) directly on Apple Silicon (M1 or later). This gives you the same hardware-isolated micro-VM execution model as Linux/KVM, with no container runtime dependency.

+
+ +

One-Time Setup

+

Install the musl cross-compilation toolchain. This compiles from source and takes approximately 30 minutes the first time:

+
+
Terminal
+
# Install the musl cross-compilation toolchain
+brew install filosottile/musl-cross/musl-cross
+
+ +

Add the Rust target for Linux ARM64:

+
+
Terminal
+
rustup target add aarch64-unknown-linux-musl
+
+ +

Build and Run

+

Download the kernel, build the guest initramfs, compile, codesign, and run:

+
+
Terminal
+
# Download an ARM64 Linux kernel (cached in target/)
+scripts/download_kernel.sh
+
+# Build the guest initramfs (cross-compiles guest-agent, downloads claude-code + busybox)
+scripts/build_claude_rootfs.sh
+
+# Build the example and sign it with the virtualization entitlement
+cargo build --example ollama_local
+codesign --force --sign - --entitlements voidbox.entitlements target/debug/examples/ollama_local
+
+# Run (Ollama must be listening on 0.0.0.0:11434)
+OLLAMA_MODEL=qwen3-coder \
+VOID_BOX_KERNEL=target/vmlinux-arm64 \
+VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \
+target/debug/examples/ollama_local
+
+ +

Important: Code Signing

+
+

Every cargo build invalidates the code signature. You must re-run codesign after each rebuild, or macOS will refuse to grant the virtualization entitlement and the VM will fail to start.

+
+ +

CLI Shortcut

+

When using the voidbox CLI, cargo run automatically codesigns before executing (via .cargo/config.toml runner). Just run:

+
+
Terminal
+
cargo run --bin voidbox -- run --file examples/specs/oci/guest-image-workflow.yaml
+
+ +

Direct Binary

+

If running the binary directly (e.g. ./target/debug/voidbox), you must codesign manually first:

+
+
Terminal
+
codesign --force --sign - --entitlements voidbox.entitlements target/debug/voidbox
+
+ +

Then run with the required environment variables:

+
+
Terminal
+
VOID_BOX_KERNEL=target/vmlinux-arm64 \
+VOID_BOX_INITRAMFS=target/void-box-rootfs.cpio.gz \
+./target/debug/voidbox run --file examples/specs/oci/agent.yaml
+
+
+
+ + + + + diff --git a/site/guides/yaml-specs/index.html b/site/guides/yaml-specs/index.html index fc9daee..dfbf6c6 100644 --- a/site/guides/yaml-specs/index.html +++ b/site/guides/yaml-specs/index.html @@ -3,7 +3,7 @@ - Declarative YAML Specs | void-box guide + Declarative YAML Specs | Void-Box @@ -20,7 +20,8 @@
void-box logoVoid-Box diff --git a/site/index.html b/site/index.html index 5bf4b84..1f0bdb3 100644 --- a/site/index.html +++ b/site/index.html @@ -3,7 +3,7 @@ - Void-Box | Composable agent runtime with hardware isolation + Void-Box | Composable Agent Runtime with Hardware Isolation @@ -24,6 +24,8 @@ Void-Box @@ -43,10 +45,13 @@

Capability-Bound Agent Runtime

Agent-native skills Claude Code runtime Pipeline composition + Snapshot / restore + OCI containers + Host mounts
@@ -119,7 +124,7 @@

Capability-Bound Agent Runtime

-
+

Why Choose VoidBox?

Agent runtime boundaries with the simplicity of declarative skills.

@@ -157,11 +162,97 @@

Observability Native

+ +
+
+

How It Works

+

Three steps from declaration to isolated execution.

+
+
+

Declare Skills

+

Define capabilities as MCP servers, SKILL files, CLI tools, or OCI images. Skills are what your agent can do.

+
+
+

Define Sandbox

+

Set memory, vCPUs, network access, and mounts. Each sandbox is a hardware-isolated micro-VM boundary.

+
+
+

Run Isolated

+

VoidBox boots a micro-VM, provisions skills, runs claude-code, and returns results. No shared kernel. No escape surface.

+
+
+
+
+ +
+
+

Install

+

One command. Binary + kernel + initramfs — everything bundled.

+
+
+

Shell installer

+
Linux & macOS — recommended
+
curl -fsSL https://raw.githubusercontent.com/the-void-ia/void-box/main/scripts/install.sh | sh
+
+
+

Homebrew

+
macOS
+
brew tap the-void-ia/tap
+brew install voidbox
+
+
+

Debian / Ubuntu

+
amd64 & arm64
+
curl -fsSLO https://github.com/the-void-ia/void-box/releases/download/v0.1.2/voidbox_0.1.2_amd64.deb
+sudo dpkg -i voidbox_0.1.2_amd64.deb
+
+
+

Fedora / RHEL

+
x86_64 & aarch64
+
sudo rpm -i https://github.com/the-void-ia/void-box/releases/download/v0.1.2/voidbox-0.1.2-1.x86_64.rpm
+
+
+ +

v0.1.2 · All releases →

+
+
+ +
+
+

See It In Action

+

Real agent runs inside hardware-isolated micro-VMs.

+
+
+
+ +
+

OpenClaw agent — live demo running inside a VoidBox micro-VM

+
+
+
+ Code review agent demo +
+

Code review pipeline — multi-stage analysis with fan-out

+
+
+
+