Firecracker-class microVMs for macOS. Built for AI agents.
Install · For agents · vs Docker / Apple container / Lima · Design · Performance · Roadmap
Boot a hardware-isolated Linux VM from any OCI image in about 300 ms, run commands in it at ~10 ms each, throw it away. No daemon, no Docker, no root. The guest has no network card unless you give it one.
curl -fsSL https://raw.githubusercontent.com/las7/HakoVM/main/install.sh | sh hako run --mount $PWD:/work --cwd /work -- python3 -c 'print("hello from a VM")'
$ hako bench
rootfs prepare : 1 ms
boot to init : 240 ms
exec p50/p90 : 8 / 12 ms (n=20)
stop : 10 ms
| Fresh env → first command | Exec in running env | Isolation layer RSS |
|---|---|---|
~300 ms (Docker: ~200, Apple container: ~900, Lima: 12 s) |
8 ms (Lima: 48, Docker: 75, Apple: 93) | ~20 MB per VM (Docker Desktop: ~430) |
Full numbers and caveats in docs/comparison.md.
Why microvm?
Firecracker needs KVM, so it does not run on a Mac. Docker Desktop, OrbStack
and Lima give you one big shared VM. Apple's container CLI is close, but it
is a general container tool with a daemon and a network stack you may not want.
HakoVM is a thin Swift runtime on Apple's open-source Containerization framework, shaped for one job: giving an AI agent a disposable machine it cannot escape from.
| Docker / OrbStack | Apple container |
hako | |
|---|---|---|---|
| Isolation boundary | shared kernel | per-container VM | per-sandbox VM |
| Boot from OCI image | n/a | ~0.9 s | ~0.3 s |
| Guest network by default | yes | yes | none |
| Daemon | yes | yes | no |
| Root / sudo | Docker: yes | install only | no |
| Designed for | dev containers | dev containers | agent sandboxes |
flowchart LR
A["agent<br/>(Claude Code · MCP · CLI)"] -->|"hako run"| H["hako<br/>one process, no daemon"]
H -->|"Virtualization.framework"| VM["microVM<br/>own Linux kernel · no NIC"]
H -->|"clonefile"| D["~/.hako<br/>base images · commits"]
W["your project dir"] <-->|"virtiofs, only what you --mount"| VM
VM -->|"stdout · exit code"| A
What it does today
- Boots a Linux microVM from any OCI image via Virtualization.framework.
- Runs commands over vsock with streamed stdout/stderr and exit codes.
- Shares host directories into the guest with virtiofs, read-write.
- No NIC by default. Loopback only. Host access is exactly the mounts you declare.
--networkopts one run into a NAT interface. - No daemon, no root. One signed binary. Images cache under
~/.hako/store. - Claude Code hook that routes every Bash call into a VM with only the project mounted.
Using it for AI work
Code interpreter. Run model-generated code, get stdout, exit code and files back. The guest cannot reach the network or any host path you did not mount.
hako run --image python:3.12-alpine --mount ./out:/work --cwd /work -- python3 /work/task.py echo "exit=$?"; cat out/result.json
Dependencies. The guest is offline by default. Install once with
--network and commit the result; every later run boots a copy-on-write
clone of it, offline, in about a second:
hako run --network --image python:3.12-alpine --commit py-deps -- pip install numpy pandas requests hako run --from py-deps --mount .:/work --cwd /work -- python3 analysis.py
Commits layer (--from py-deps --commit py-deps-ml), and ten agents booting
from one commit each get their own clone. Mounting a host venv or
node_modules works too, and so does any image from a registry. See
docs/dependencies.md for when to use which.
Claude Code. Put every Bash call the agent makes inside a VM. Add to
.claude/settings.json:
{"hooks": {"PreToolUse": [{"matcher": "Bash",
"hooks": [{"type": "command", "command": "python3 ~/hakovm/hooks/claude-code-bash.py"}]}]}}The project directory is mounted at the same path, so the agent's relative and
absolute paths keep working. HAKO_IMAGE, HAKO_NETWORK=1 and HAKO_MOUNT
tune it. Round trip per command is about 0.7 s including the boot; a warm pool
is next on the roadmap to bring that to the exec latency.
MCP server. One command registers HakoVM as a tool for any MCP client:
claude mcp add hako -- hako mcp --image python:3.12-alpine --mount "$PWD:/work"The model gets hako_run (command, image or commit, timeout, cwd) and
hako_commits. Network and extra mounts are refused unless you start the
server with --allow-network / --allow-mounts.
Any language. hako run --json --timeout 60 -- ... prints one JSON
object with stdout, stderr, exit code and timings. See
docs/agents.md for all four integration paths and the
patterns that work.
CLI
hako setup # one-time: kernel + guest init + alpine hako pull [image] # cache an image for offline boots hako run [opts] -- <cmd...> # fresh VM, run one command, destroy hako run --image python:3.12-alpine -- ... # any OCI image; short names resolve like Docker hako run --mount /host/dir:/work -- ... # share a directory (repeatable) hako run --network -- ... # give this run a NAT interface hako run --commit NAME -- ... # save the rootfs after the command exits 0 hako run --from NAME -- ... # boot a clone of a commit hako commit ls | hako commit rm NAME # manage commits hako run --json --timeout 60 -- ... # machine-readable result, kill after 60 s (exit 124) hako run --lean -- ... # minimal guest mounts, no VM overhead: ~30 ms faster hako mcp [--allow-network] [--allow-mounts] # MCP tool server on stdio hako run --cpus 1 --memory 256 -- ... # size the VM hako run --kernel-arg quiet -- ... # extra kernel command line hako bench [--execs N] # boot / exec / stop timings
Install
Apple Silicon and macOS 26 or later. No sudo, no developer account.
curl -fsSL https://raw.githubusercontent.com/las7/HakoVM/main/install.sh | shThat drops hako in ~/.local/bin and runs hako setup, which downloads a
28 MB Linux kernel built from Apple's Containerization config and caches
Apple's guest init plus alpine. Everything lives under ~/.hako.
From source, with Xcode 26:
git clone https://github.com/las7/HakoVM && cd hakovm make install # build, sign with the virtualization entitlement, copy to ~/.local/bin hako setup
Where it is going
hako is being built around six agent workloads: coding-agent shell, code interpreter, parallel fan-out, browser agent, eval runs, and hosting untrusted MCP servers. The design doc describes the primitives that serve them: profiles, warm pools, host-terminated egress with hostname allowlists, a credential broker, and commit/fork of prepared rootfs images.
See the roadmap for order and status.
Documentation
| Topic | Link |
|---|---|
| Architecture | docs/architecture.md |
| Using it from agents (CLI JSON, MCP, Claude Code hook) | docs/agents.md |
| Security model and red-team results | docs/security.md |
| Design for AI workloads | docs/design.md |
| Dependencies: commit, mounts, images | docs/dependencies.md |
| vs Docker, Apple container, Lima | docs/comparison.md |
| Performance and tuning | docs/performance.md |
| Roadmap | docs/roadmap.md |
| Contributing | CONTRIBUTING.md |