Now that git.dsg.is/dsg/cloud-hypervisor.git has a flake.nix, use it as a proper flake input with inputs.nixpkgs.follows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
vmsilo is a lightweight virtualization system inspired by Qubes OS. It runs isolated VMs using crosvm (Chrome OS VMM) with different security domains (banking, shopping, untrusted, etc.). VMs are configured declaratively via a NixOS module.
Environment
You are running under NixOS. If you need any tools not in the environment, use nix-shell.
Development Rules
- Update CLAUDE.md along with code. Keep this concise. Only add information that is not obvious and can not be easily looked up in code.
- Always update README.md for any user-visible changes (NixOS options, CLI flags, etc).
- There are no tests for the Nix modules.
nix builduses the git index for source filtering. New untracked files must begit add'd beforenix buildwill see them.
Build Commands
# Build the default rootfs image
nix build .#
Code Style
This project uses treefmt-nix with nixfmt for formatting. Run before committing:
nix fmt
Architecture
VM Launch Flow (NixOS module)
VMs run as system services (root) for PCI passthrough and sandboxing support. crosvm drops privileges before starting the guest.
VMs start automatically when first accessed via socket activation:
vm-run banking firefoxconnects to/run/vmsilo/banking/command.socket- Socket activation triggers
vmsilo-banking@.service(proxy template) - Proxy requires
vmsilo-banking-vm.service, which starts crosvm - Proxy waits for guest vsock:5000, then forwards command
The configured user can manage VM services via polkit (no sudo required for vm-start/vm-stop).
Key Files
NixOS module (modules/): Split across many files — there is no single config.nix.
default.nix— entry point (imports all submodules)options.nix— option declarations (programs.vmsilo; includesvm.<name>.hypervisorfor VMM selection:crosvmorcloud-hypervisor)scripts.nix— generated CLI scripts (vm-run,vm-start, etc.)services.nix— systemd units (VM service, proxy, console relay, session bind, GPU device backend, wayland-seccontext)desktop.nix— .desktop file generation and icon copyingnetworking.nix— TAP interfaces, host nftables fornetvm = "host", guest network confignetvm.nix— auto VM-to-VM and VM-to-host network linkspci.nix— VFIO PCI passthrough setupoverlay.nix— root overlay (raw/tmpfs) setupassertions.nix— validation checkspackage.nix— final package derivationlib/helpers.nix— crosvm argument building helperscss-colors.nix— CSS named color lookup table
Guest rootfs (rootfs-nixos/):
default.nix— NixOS-based rootfs builder (outputs{ erofs, kernel, initrd })configuration.nix— entry point (imports all guest submodules)guest/boot.nix— boot config, initrd, overlayfs rootguest/users.nix— user accounts, sudo, SSHguest/networking.nix— network config from kernel paramsguest/wayland.nix— wayland proxy and session setupguest/command.nix— vsock command listener, tray, idle watchdogguest/system.nix— packages, graphics, fonts, miscguest/kernel-param-helper.nix— shared shell helper for parsing kernel cmdline- Self-contained erofs image with overlayfs root; no host /nix sharing
Rust crates:
vmsilo-balloond/— dynamic balloon memory management daemon (equalizes host/guest free memory via virtio-balloon; run--helpfor CLI options)vmsilo-tray/— tray proxy (guest SNI items proxied to host system tray over vsock:5001)vmsilo-wayland-seccontext/— creates Wayland security context socket (wp_security_context_v1); run by per-VM systemd service before the GPU device service
Other:
patches/— KWin/Plasma patches for VM window decoration colors and clipboard isolationflake.nix— exposesnixosModules.defaultandlib.makeRootfsNixos
Generated Scripts
vm-run <name> <cmd>— run command in VM (starts VM on-demand via socket activation)vm-start <name>— start VM via systemd (polkit, no sudo)vm-stop <name>— stop VM via systemd (polkit, no sudo)vm-shell <name>— connect to VM serial console (default) or SSH with--sshvmsilo-usb [attach|detach] [<name> <vid:pid|devpath>]— list USB devices, attach/detach USB devices to VMs
See README.md for full usage details and options.
Dependencies
- Custom crosvm fork:
git.dsg.is/dsg/crosvm.git - wayland-proxy-virtwl: Wayland/X11 proxying between host and guests
- NixOS 25.11 base
Key Patterns
- Socket activation chain: command socket → proxy template service → VM service → crosvm
- Offline-by-default networking: VMs have no network unless
network.interfacesornetwork.netvmis configured. - Host netvm:
network.netvm = "host"routes VM traffic through the host directly (TAP with hostAddress, host nftables NAT). No bridge or netvm VM needed. - Root overlay: raw disk-backed (default) or tmpfs-backed overlayfs upper layer. Ephemeral — created at VM start, deleted at stop.
- Session bind: GPU-enabled VMs (default) are tied to the desktop session via per-VM systemd user services bound to
graphical-session.target. ForautoStartGPU VMs, the session-bind service also starts the VM on login. Non-GPUautoStartVMs start atmulti-user.target(boot). - GPU device backend:
vmsilo-<name>-gpuservice runscrosvm device gpusandboxed; both crosvm and cloud-hypervisor attach via vhost-user.vmsilo-<name>-wayland-seccontextmust start first. - Per-VM runtime dirs: all sockets under
/run/vmsilo/<vmname>/subdirectories (not flat).
Gotchas
nix buildgit index filtering: new files must begit add'd beforenix buildsees them (applies to allsrc = ./<path>references in flake.nix).- Explicit UID required: the configured user must have
users.users.<name>.uidset explicitly. - O_DIRECT on root disk: intentional — bypasses host page cache to avoid double-caching (erofs is read-only, guest caches internally).
- Module split: there is no
modules/config.nix. Implementation is split acrossscripts.nix,services.nix,desktop.nix,networking.nix,pci.nix,overlay.nix,assertions.nix,package.nix. - cloud-hypervisor package: sourced from a custom flake input (
git.dsg.is/dsg/cloud-hypervisor.git), not nixpkgs.
NixOS Module Usage
The configured user must have an explicit UID set (users.users.<name>.uid = <number>).
See README.md for the full configuration reference and examples.