
Give coding agents a disposable Linux VM, not your laptop
Give a coding agent its own disposable Linux machine, not yours.
Install · Quickstart · Why a VM? · How it works · Compared to · FAQ · Docs
A coding agent is only useful when you let it actually do things: install
packages, run the code it writes, start servers, use the network. On your own
machine that leaves two bad options. You approve every command (and babysit a
prompt every few seconds), or you run --dangerously-skip-permissions and hope
nothing important is one rm -rf or one leaked token away.
clawk is a third option. cd into a repo, type clawk, and Claude Code (or
Codex, or pi, or a shell) is working inside a disposable Linux VM (your code mounted
in, root in the guest, no permission prompts) while your files, your keychain,
and the rest of your machine stay out of reach. The agent gets its own
machine instead of yours.
One command to a working agent; an attempt to send data to an
unknown server, blocked by the network allow-list; clawk attach
resumes the session later.
The boundary isn't a rule in a prompt the agent could be talked out of. It's a separate machine, and the only openings are the ones you mounted. From a shell inside a sandbox:
$ curl https://tracker.evil.example # not on the allow-list: blocked
curl: (7) Failed to connect to tracker.evil.example port 443 after 2 ms: Connection refused
$ cat ~/.ssh/id_rsa # your keys never entered the VM
cat: /home/agent/.ssh/id_rsa: No such file or directory
$ git push # ...yet this works: ssh-agent is forwarded
Enumerating objects: 5, done.
To be honest about the limits, the allow-list blocks connections to unknown servers, not to ones you've allowed: github.com is pre-allowed and the forwarded ssh-agent can push, so treat anything the agent can read as something it could publish. The security model spells this out.
And if the agent wrecks the VM, run clawk destroy && clawk: a fresh VM, same
repo, and --resume restores the conversation.
[!IMPORTANT] Pre-1.0 and moving fast. Expect breaking changes between releases and the occasional rough edge; things can and will break. Please file issues; that feedback is shaping 1.0.
rm -rf, package installs, and untrusted code can't reach your
host, your files, or anything you didn't explicitly share.cd into a repo and run clawk. No
Dockerfile, devcontainer, or setup file. First boot builds a rootfs from
your image; every boot after takes seconds.git push works without keys entering the VM.clawk is a general-purpose local environment for autonomous coding agents. The VM is the point: it's a whole machine the agent can own, not a process wrapped in policy on the one you're using.
/dev/kvm-shaped expectations, so tools behave the way their docs say,
without a syscall-filter surprise./etc, load a module,
bind a privileged port. It's the agent's box to reconfigure.clawk destroy && clawk away, with your repo and conversations
untouched on the host.That combination runs workloads a restricted process sandbox tends to fight you on:
None of this is the product; clawk is for local agent work in general. Docker and Kubernetes are just the sharpest example of "needs a real machine, not a sandboxed process."
Requires macOS 14+ on Apple silicon. (Linux is supported via firecracker and currently experimental — start with docs/linux-quickstart.md, which covers setup, the workflow, and the gaps. This README is macOS-first.)
brew install clawkwork/tap/clawk
From source (contributors, or if you don't use Homebrew), needs Go 1.26+:
git clone https://github.com/clawkwork/clawk && cd clawk
make install
Either way there's no extra host tooling: no Docker, no qemu, no sudo. The hypervisor is Apple's Virtualization.framework, linked into the binary, and the release binaries carry the in-guest agent prebuilt — so a Go toolchain is only needed if you build from source, in which case you have one. First run probes for anything missing and offers to fix it.
Uninstall: clawk destroy your sandboxes, rm -rf ~/.clawk, then remove
the binary with brew uninstall clawk (or delete it from $GOBIN for a
source install). Nothing else was installed: there are no launchd jobs; the
per-sandbox daemons are ordinary processes that exit with their VMs.
The everyday case, a sandbox for the directory you're in:
cd ~/code/my-project
clawk # boot a sandbox for this dir + attach claude
clawk run shell # drop into a shell in the same sandbox
clawk run codex # or another agent: codex, pi, opencode, shell
clawk down # stop the VM (repo + agent state persist)
clawk attach # come back later — boots if stopped, reattaches claude
clawk destroy # remove the VM (conversation history is kept)
Common options:
clawk run claude -- --resume # pass args through to the agent
clawk forward add my-project 3000 # expose a guest dev server on localhost:3000
clawk network allow my-project api.example.com
Working on a ticket that spans several repositories? One command creates a
sandbox with a git worktree per repo on a fresh branch, and clawk pr later
opens cross-linked PRs for whatever changed:
cd ~/code/my-workspace # contains a clawk.mod listing the repos
clawk work INFRA-123 # one sandbox, a worktree per repo, claude attached
clawk pr INFRA-123 # push branches + open one PR per repo
The full ticket lifecycle (status, follow-up branches after merges, rebases) is in docs/ticket-mode.md.
Tip: using Claude Code? Run
claude setup-tokenthenclawk auth set-tokenonce, and every sandbox comes up already signed in, with no/loginand no login conflicts between parallel sandboxes. See docs/claude-auth.md.
One rule governs persistence: the VM is disposable; everything you'd miss lives on the host.
* Two exceptions: resuming a clawk snapshot restores the disk and
memory exactly as suspended, and the Linux/firecracker provider keeps
its disk until destroy. Tools every boot needs belong in the image
(vm ( image … )); per-boot setup belongs in on up hooks.
Agent state is host-mounted per sandbox: each runner's home directory —
claude's ~/.claude/, codex's ~/.codex/, pi's ~/.pi/, opencode's two XDG
dirs — live under
~/.clawk/namespaces/default/state/<name>/ on the host, so a recreated
sandbox picks up its old conversations with --resume. That mount is what
makes the promise real: the VM disk itself is re-cloned from the image on
every boot, so anything a runner writes outside those directories is gone
at the next clawk up.
--safe opt-out)Runners launch in their "externally sandboxed" modes: claude gets
--dangerously-skip-permissions, codex gets
--dangerously-bypass-approvals-and-sandbox, pi gets --approve (it has no
approval prompts to bypass — it ships no sandbox at all — but it does gate
project-local .pi/ settings and extensions behind a trust prompt), and
opencode gets --auto. On your own machine those flags
would be reckless; here they are the point: the VM boundary and the network
allow-list provide the containment, so the agent works at full speed without
per-action prompts. The agent can only affect what you mounted and
allow-listed, nothing more (see SECURITY.md).
Prefer the confirmation prompts anyway? Add --safe to any attach
(clawk --safe, clawk run claude --safe) and the runner starts without its
bypass flags for that session.
Outbound traffic is denied by default; each sandbox has its own allow-list.
DNS resolves everything; TCP, UDP (including QUIC), and ICMP echo to unlisted
hosts are refused. Common registries (npm, PyPI, crates.io, GitHub,
Anthropic, …) are pre-allowed, and the filter is DNS-aware, so allowing
example.com keeps working as its IPs rotate.
clawk network allow my-project api.stripe.com '*.internal.mycorp.com' 10.0.0.5
clawk network denials my-project # what the agent tried that got blocked
clawk forward add my-project 3000 # localhost:3000 → the guest's dev server
clawk forward add-reverse my-project 63342 # and the other way: a service on YOUR
# localhost, reachable inside the guest
Denials are recorded by the hostname the guest resolved, so clawk network denials reads as a log of what the agent tried to reach. Reusable named
policies (including subscribing to external blocklists like oisd) and the
use chain that layers them are in
docs/networking.md.
clawk.modNo config file is required; defaults are sensible. When a project needs
more, a clawk.mod file describes it, in a go.mod-style syntax:
sandbox my-project (
vm (
cpu 4
memory 8GiB
image golang:1.25 # any OCI image is the rootfs
)
network ( allow api.example.com )
forwards ( 3000 )
env ( DATABASE_URL ) # forward a host var; values come from your shell
# also: GH=${OTHER_NAME}, LOG=${LOG:-info} defaults, API=${API:?required}
mcp ( # MCP servers, ready on first boot
linear https://mcp.linear.app/mcp header "Authorization: Bearer ${LINEAR_TOKEN}"
)
on create ( "go mod download" )
agent (
instructions "Ask before running destructive commands."
)
)
The block is a template: snapshotted when the sandbox is created, so a running sandbox never changes unexpectedly. The full reference (shares, secret files, skills, agent memory seeding, multi-repo workspace roots) is in docs/configuration.md; MCP servers and how their credentials stay off disk are in docs/mcp.md; putting a USB-serial board from your Mac inside the sandbox for microcontroller work is in docs/serial.md; images and custom guest kernels (including the KVM-enabled kernel used for nested virtualization) are in docs/images.md.
clawk list # all sandboxes
clawk status [<name>] # state, forwards, blocked hosts; --json for scripts
clawk up / down # boot / stop
clawk pause / resume # suspend / resume the running VM in memory
clawk snapshot # save to disk: RAM freed, guest intact; resume restores it
clawk destroy # remove the VM; host-side state persists
clawk snapshot is hibernation for sandboxes: the guest's memory is saved
beside its disk and the next boot restores the guest exactly where it was.
Background processes and dev servers continue as if nothing happened, and
clawk attach puts you back in front of the agent. The full command surface,
runner dispatch, and the idle-management machinery (ballooning, admission
control, auto-stop) are in docs/commands.md.
you ──▶ clawk CLI ──▶ per-sandbox daemon (detached; owns the VM)
├─ gvproxy: in-process userspace TCP/IP stack —
│ the DNS-aware outbound filter the guest can't reconfigure
├─ vsock bridge to the in-guest pty-agent (no sshd)
├─ ssh-agent proxy, macOS (signing stays on the host)
└─ VM: Virtualization.framework (macOS) / firecracker (Linux)
├─ clawk-init, PID 1 (no systemd, no cloud-init)
├─ your repo, live-mounted over virtio-fs
└─ claude / codex / pi / shell on a PTY
A few deliberate choices, in brief:
clonefile / FICLONE), so per-sandbox disk cost is what the guest
writes.The full picture (the guest stack, both providers, the frame-level networking) is in ARCHITECTURE.md, and the reasoning behind each decision in DESIGN.md.
Dockerfile/devcontainer.json to write: any OCI image is the rootfs.Two boundaries do the work: the VM (the host filesystem is invisible except what you mount) and the outbound allow-list (enforced in userspace below the guest, for every protocol that can leave it). What clawk does not protect against:
files ( … ) and shares ( … )
contents, forwarded env vars, and the Claude token are the agent's to read
(and, if a destination is allow-listed, to send there). Share the minimum.If you find a way to break a boundary (guest-to-host escape, network-filter bypass, credential leakage), please report it privately via SECURITY.md.
What's the overhead? The first boot from an image pays a one-time rootfs build (pull → flatten → ext4). After that, disks are copy-on-write clones and the kernel direct-boots, with no firmware and no installer. Idle VMs release memory down to ~1 GiB, stop automatically after 30 idle minutes, and can be snapshotted to disk so they cost only storage.
Does it work on Intel Macs? Windows? No. macOS needs Apple silicon (macOS 14+). On Linux, the firecracker provider works but is experimental (see docs/commands.md). No Windows support.
Do I need Docker installed? No. clawk pulls OCI images and builds bootable disks itself. Docker images are the input format; the Docker engine is not involved. (Running a Docker daemon inside a sandbox is a separate, opt-in feature; see Images for the hardware and kernel requirements.)
Why "clawk"? The mark is a claw; clawkwork is a play on A Clockwork Orange. A VM you wind up, set loose, and can always reset.
Next up: running more sandboxes than your RAM can hold at once.
clawk snapshot / clawk resume; next, the automatic idle stop uses it
too, so dev servers survive the stop and a suspended sandbox costs only
disk.Pre-1.0 and under active development, and evolving quickly: expect breaking changes between releases. The CLI surface changes least and internals most, but nothing is frozen until 1.0.
Issues and PRs are welcome. See CONTRIBUTING.md to build and test, ARCHITECTURE.md for how it's built, and DESIGN.md for where it's headed.
Apache License 2.0. clawk vendors two third-party components under their own licenses (gvisor-tap-vsock, Apache-2.0; an hcsshim ext4 writer, MIT); see NOTICE.
clawk downclawk destroy |
|---|
| Your repo (mounted worktree; commits, branches) | ✅ | ✅ |
| Agent state (Claude/Codex/pi/opencode conversations, memory) | ✅ | ✅ |
The VM disk (apt installs, caches, $HOME) | ❌ (rebuilt fresh at every boot*) | ❌ (that's the point) |