Pure Bash Claude Code sandbox manager on top of bare QEMU.
Run Claude Code with full permissions in an isolated VM with near-native filesystem performance.
Shallow copies of one base image.
Claude Code works best with --dangerously-skip-permissions, but running an AI agent with unrestricted access to your host is a reasonable concern. claude-vm gives Claude Code a full Linux environment with sudo, network access, and every tool it needs -- inside a VM that can't touch your host filesystem outside the project directory.
- Isolated: QEMU VM with KVM acceleration. Claude Code can
rm -rf /and your host is fine. - Fast: virtiofs gives near-native filesystem performance. No copying files in or out.
- Lightweight: Linked QCOW2 snapshots share a base image. Each project adds only its delta (~200KB initially).
- Multi-instance: Run multiple Claude Code sessions in the same project VM simultaneously.
- Batteries included: Git identity, GitHub/GitLab CLI auth, and Claude Code config (settings, plugins, skills, agents, commands, workflows, keybindings) are synced automatically.
- Linux with KVM support (
/dev/kvmaccessible) - QEMU (
qemu-system-x86_64,qemu-img) - virtiofsd
newuidmap/newgidmap— virtiofsd uses them to build its user namespace when run unprivileged (Debian/Ubuntu:uidmappackage; elsewhere part ofshadow)- An ISO creation tool (
genisoimage,mkisofs, orxorrisofs) - curl, rsync, jq
Arch / CachyOS:
sudo pacman -S qemu-full virtiofsd cdrtools curl rsync jqUbuntu / Debian:
sudo apt install qemu-system-x86 qemu-utils virtiofsd genisoimage curl rsync jq uidmapFedora:
sudo dnf install qemu-system-x86 qemu-img virtiofsd genisoimage curl rsync jq shadow-utilscurl -fsSL https://raw.githubusercontent.com/shudza/claude-vm/master/install.sh | bashgit clone https://github.com/shudza/claude-vm.git
cd claude-vm
sudo make installThis installs claude-vm to /usr/local/bin/ and library scripts to /usr/local/lib/claude-vm/. To uninstall: sudo make uninstall.
To install elsewhere: make install PREFIX=/opt/claude-vm
For development, run directly from the repo (no install needed):
./claude-vmcd ~/my-project
claude-vmFirst run builds a base image (2-3 minutes plus the cloud image download), creates a project snapshot, and launches the VM. Subsequent runs resume in seconds.
| Command | Description |
|---|---|
claude-vm [-- ARGS...] |
Launch sandbox and enter Claude Code |
claude-vm launch [DIR] [-- ARGS...] |
Launch sandbox for a specific directory |
claude-vm build [--flavor X] |
Build (or rebuild) the base image |
claude-vm ssh |
Shell into the running VM |
claude-vm stop [--all] |
Stop the VM (preserves snapshot) |
claude-vm reset |
Reset project snapshot to fresh state |
claude-vm rebase [--force] [--yes] |
Rebuild base, migrate VM state |
claude-vm destroy [--all] |
Remove sandbox artifacts (current project, or all with --all) |
claude-vm list |
List all project snapshots |
claude-vm status |
Show current project status |
claude-vm show |
Print the full QEMU and SSH commands for this project |
claude-vm config |
Show/set configuration |
claude-vm help |
Show help |
See docs/usage.md for the full reference with all flags and examples.
claude-vm config set VM_RAM 8G
claude-vm config set VM_CPUS 4
claude-vm config set FLAVOR debian-slim
claude-vm config set VM_USER alice
claude-vm config set SSH_PORT_BASE 10022
claude-vm config set FORWARD_PORTS "8080,3000:3000" # per-project
claude-vm config set CLAUDE_ARGS "--dangerously-skip-permissions --model sonnet"
claude-vm config set REBASE_BACKUP_PATHS "/etc/ssh,~/.ssh" # extra paths kept through rebaseOr edit directly:
# ~/.claude-vm/config
FLAVOR="debian-slim"
VM_USER="alice"
VM_RAM="8G"
VM_CPUS="4"
SSH_PORT_BASE="10022"
CLAUDE_ARGS="--dangerously-skip-permissions --model sonnet"Environment variables override config: VM_RAM=16G claude-vm. FORWARD_PORTS is stored per project (sidecar file), see docs/usage.md for spec formats.
Every distro comes in two variants: slim (fast to build — git, Node.js, Python, gh, and core tools) and full (slim plus build tools, tmux, vim, and debug utilities). Bare distro names (debian, ubuntu, ...) alias to the -full variant for backward compatibility.
| Flavor | Base Image | Notes |
|---|---|---|
debian-slim (default) |
Debian 13 (trixie) genericcloud | Minimal, no snapd |
debian-full |
Debian 13 (trixie) genericcloud | Adds build-essential, cmake, tmux, ... |
ubuntu-slim / ubuntu-full |
Ubuntu 24.04 minimal | snapd auto-removed |
archlinux-slim / archlinux-full |
Arch Linux cloud image | Rolling release, uses pacman |
fedora-slim / fedora-full |
Fedora 44 Cloud Base | Uses dnf |
claude-vm build --flavor debian-full
claude-vm build --flavor ubuntu-slim
claude-vm build --flavor fedora-slim
claude-vm build --flavor ubuntu # alias for ubuntu-fullEach flavor gets its own base image (~/.claude-vm/base/base-<flavor>.qcow2), so multiple flavors coexist — different projects can use different flavors side by side.
- Base image is built once: downloaded cloud image is verified against the upstream checksum file (SHA256/SHA512), then cloud-init provisions Claude Code, dev tools, and SSH
- Linked snapshots (QCOW2 copy-on-write) give each project its own VM state backed by the shared base
- virtiofs mounts your project directory into the VM at
/workspacewith near-native I/O - Config sync (rsync) copies your Claude Code settings, git identity, and gh/glab auth into the VM on first VM creation
- SSH connects your terminal to Claude Code running inside the VM
A base image is roughly 1–1.5GB depending on variant (each flavor keeps its own base-<flavor>.qcow2). Each project snapshot starts at ~200KB and grows only as the VM writes to its own disk (package installs, caches, etc.). QEMU is configured with discard=unmap so that deleted files are reclaimed from the overlay via fstrim, keeping snapshots compact over time. Background services that would silently grow snapshots (unattended-upgrades, apt timers, man-db rebuilds) are disabled during provisioning.
See docs/architecture.md for the full design.
All packages come from the distro's own repositories and install in a single cloud-init transaction — no third-party apt repos.
Slim (every flavor): git, ripgrep, jq, less, gh (GitHub CLI), curl, zip/unzip, rsync, Node.js + npm, Python 3 (with pip and venv), Claude Code.
Full adds: build tools (build-essential/base-devel/gcc + cmake), uv (Python package manager), glab (GitLab CLI), tmux, vim, tree, xxd, file, sqlite3, bc, ping, lsof, socat, netcat, dig, strace, patch, wget, gnupg.
Node.js comes from the distro repos: 20.x on Debian 13, 18.x on Ubuntu 24.04, current releases on Arch and Fedora. Need something newer? Claude Code has full sudo access — install it at runtime via NodeSource or nvm, like any other missing tool.
Open multiple terminals in the same project directory and run claude-vm in each. Each gets its own Claude Code session sharing the same VM and /workspace mount.
See full launch output:
CLAUDE_VM_VERBOSE=true claude-vmCheck logs:
cat ~/.claude-vm/run/$(echo -n "$PWD" | sha256sum | cut -c1-12)/launch.logKVM not available:
claude-vm falls back to TCG (software emulation) but it will be significantly slower. Ensure your user has access to /dev/kvm:
sudo usermod -aG kvm $USERFresh start for a project:
claude-vm reset # Deletes snapshot, next launch creates a fresh oneFresh start for everything:
claude-vm destroy --all # Removes base image + all snapshotsRebase onto a fresh base image (keeps VM state):
claude-vm rebase # Extracts state, rebuilds base, restores on next launchRebase preserves ~/.claude/ (minus runtime state such as daemon/, jobs/, sessions/ and caches), ~/.claude.json, ~/.gitconfig, ~/.config/gh/, ~/.config/glab-cli/ by default. Add arbitrary guest paths (synced as root with permissions preserved) via REBASE_BACKUP_PATHS — see docs/usage.md.
See docs/contributing.md for conventions, project structure, and how to add new commands or flavors.
MIT
