crucible
Sandbox runtime for AI coding agents. Firecracker microVMs, a single Go binary, snapshot/fork as first-class primitives.

Boot nginx in a microVM with docker run ergonomics, cp content in, then snapshot the running server and fork it onto its own port: two VMs, two answers, zero interference (CLI · how fork works).
AI coding agents write code and want to run it: check it compiles, run the tests they just wrote, try three approaches in parallel. Today's options are all wrong in different ways: raw Docker (shared kernel, weak isolation, no fork), hosted sandbox services (lock-in, usage-priced), or rolling your own Firecracker stack (months of operational work).
crucible is the fourth option: a single self-hosted Go binary on top of Firecracker, with snapshot/fork as first-class primitives and observability baked in, tuned for running AI-generated code. Think of it as a safe docker run for code you don't trust: a real guest kernel (a container escape is a VM escape), default-deny egress, and one-command fork to explore approaches in parallel.
crucible run nginx:alpine -p 8080:80 # boot an unmodified image, publish a port
crucible cp ./script.py <id>:/work # drop local code in, no image build, no Dockerfile
crucible shell <id> # a real /bin/sh inside it (cd/env persist)Full motivation and design: docs/VISION.md.
Ephemeral by design. A daemon restart does not resurrect running sandboxes (their registry records and durable logs persist; the live VMs do not). That is exactly the right contract for "run a sketchy repo, test it, tear it down." Durable, self-healing long-lived workloads are v0.4.
Highlights
- Real isolation, not containers. Every sandbox is a Firecracker microVM under jailer: its own chroot, mount/PID namespaces, a dropped uid, and cgroup v2 quotas. Not a shared kernel.
- Snapshot & fork as primitives. Run setup once, snapshot the warm state, fork N parallel children from it. Forks restore with lazy
userfaultfdmemory: guest RAM is served from the snapshot on demand, never byte-copied per fork (the AWS Lambda SnapStart technique). - Clone-safety. Each fork wakes with a fresh kernel RNG seed, a rotated
machine-id, and its own hostname, ordered before the fork is reachable, so no two forks silently share UUIDs, secrets, or entropy. - Default-deny networking. No egress unless you allowlist hostnames, and only those; resolved IPs are range-filtered so a guest can't SSRF cloud metadata or private ranges. Enforced in host nftables + a DNS proxy the guest is forced through.
- Three ways to drive it. A CLI, a live TUI dashboard, and an MCP server: all thin clients over one REST API, so they can't drift.
- Scoped tokens. Bind an API key to a policy the daemon enforces (allowed operations, egress ceiling, profile allowlist, resource caps, expiry). See docs/policy.md.
- Observability. Per-exec structured results (exit code, wall-clock, and CPU/memory/I/O usage), durable per-sandbox logs, and a Prometheus
/metricsendpoint. - Self-hosted, single binary. Daemon and CLI are one Go binary. No cloud, no account, no telemetry.
Maturity. crucible is pre-1.0 and not yet hardened for production or untrusted multi-tenant use. The daemon binds loopback by default, with optional bearer-key auth (required, plus TLS, to bind a non-loopback address). See SECURITY.md for the exact isolation model and its limits.
Quick start
crucible is a Linux daemon (it needs KVM + Firecracker) plus a cross-platform client: the CLI, TUI, and crucible mcp serve are thin HTTP clients, so they run on macOS and Windows too, driving a remote Linux daemon.
Linux (a host where ls /dev/kvm works): one command fetches and checksum-verifies firecracker + jailer, a guest kernel, and a rootfs, then starts the service:
curl -fsSL https://raw.githubusercontent.com/gnana997/crucible/main/install.sh | sudo bash -s -- --with-deps --enableThen run your first sandbox:
crucible run nginx:alpine -p 8080:80 && curl localhost:8080 # boots + serves
crucible tui # live dashboardmacOS / Windows: install just the client (no root, no VM) and point it at a Linux daemon:
curl -fsSL https://raw.githubusercontent.com/gnana997/crucible/main/install.sh | sh -s -- --client --addr https://YOUR-LINUX-HOST:7878 --token <key>The daemon installer's --connect-token mints a scoped key and prints that exact client line plus an MCP snippet to paste into Claude Code / Cursor. Manual setup and the platform matrix are in install.sh --help and docs/cli.md; building from source is in CONTRIBUTING.md.
Usage
Daemon-authoritative: the CLI, TUI, and MCP server are thin clients over one REST API; point them with --addr (or CRUCIBLE_ADDR; default 127.0.0.1:7878) and --token.
crucible run nginx:alpine -p 8080:80 # boot an OCI image, publish a port (long-lived)
crucible build -t myapp . && crucible run myapp # a repo's Dockerfile → running, in two lines
crucible cp ./app.py <id>:/work # drop local code in, no image build
crucible shell <id> # interactive shell inside it (no PTY)
SBX=$(crucible run --profile python-3.12)
crucible snapshot create $SBX | xargs crucible fork --count 5 # explore 5 approaches in parallel- CLI: the full reference (all commands, flags, exit codes) is in docs/cli.md. Add
-o jsonto any command for machine-readable output. - TUI:
crucible tuiopens a live dashboard: running sandboxes, the fork tree, streamingexec, and a k9s-style logs view, all gated on the token's scope. docs/tui.md. - MCP:
crucible mcp serveexposes crucible to any MCP agent (Claude Code, Cursor, …) as native tools (create, run, exec, snapshot, fork,write_files,read_file, and more) with operator guardrails. docs/mcp.md. - REST: everything above is the daemon's HTTP API: endpoints, the exec frame protocol, and error codes are in docs/api.md.
How it works
A single Go binary is both the daemon and the CLI; each guest runs a small vsock agent. The daemon boots Firecracker microVMs under jailer, runs commands over vsock with streamed output, captures snapshots, and forks end-to-end, each fork restored with lazy userfaultfd memory, its own netns + DHCP-assigned IP behind a default-deny allowlist, and a per-fork identity refresh. A durable registry is journaled and reconciled on restart (orphaned VMs / netns / nft rules are reaped). Full walkthrough: docs/architecture.md; networking has its own design doc.
Performance
Measured on one 24-core box, 512 MiB sandboxes. The --work-base filesystem is the biggest lever: reflink (btrfs/XFS) makes fork's rootfs clone O(1), while ext4 has no reflink, so it byte-copies, so here's both. Full methodology in docs/benchmarks.md:
| ext4 (common default) | btrfs / XFS (reflink) | |
|---|---|---|
| Fork (warm → child) | ~690 ms | ~207 ms |
| Fork throughput (64-way) | 3.7/s | 45/s |
| 128 forks, host RAM | 4.9 GB | 1.2 GB (vs 64 GB naïve copy) |
| Exec roundtrip | ~3 ms | ~3 ms |
Fork is ~9× faster than a cold boot either way, and we ran 512 concurrent microVMs on the laptop (reflink, RAM-bound).
By the numbers: one static binary · no guest RAM copied per fork · 3 interfaces (CLI · TUI · MCP) · 15 MCP tools · 8 prebuilt profiles · 512 MB / 1 vCPU / 60 s safe defaults
Roadmap
- v0.3.2 (current): the safe
docker runfor untrusted/AI code: OCI image boot +crucible build,crucible cp+ MCPwrite_files/read_file(drop code in and run it, no Dockerfile), an interactivecrucible shell, a TUI logs view,--disksizing, top-levelstop/rm, and durable logs. Sandboxes are ephemeral (durability is v0.4). - v0.4 (planned): durable, self-healing long-lived workloads that survive a daemon restart, plus a PTY for full-terminal interactive sessions.
Full shipped-vs-planned capability matrix: docs/ROADMAP.md.
Security
crucible runs untrusted code, so isolation is a core property, but it is pre-1.0 and not yet hardened for production or untrusted multi-tenant use. The daemon binds loopback by default and ships with optional bearer-key auth (required, with TLS, to bind a non-loopback address). See SECURITY.md for the isolation model, current caveats, and how to report a vulnerability.
Contributing
Early days: the API is stabilizing. If you're building a coding agent and want crucible to fit your workflow, open an issue describing it; concrete use cases shape priorities more than wishlists. Build/test setup, style, and PR guidelines are in CONTRIBUTING.md; the codebase walk-through is in docs/architecture.md. By participating you agree to the Code of Conduct.
License
Apache License 2.0. See LICENSE.