vmsilo/CLAUDE.md
Davíð Steinn Geirsson e058e701d2 feat: use cloud-hypervisor custom flake input instead of nixpkgs
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>
2026-03-18 17:21:43 +00:00

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 build uses the git index for source filtering. New untracked files must be git add'd before nix build will 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:

  1. vm-run banking firefox connects to /run/vmsilo/banking/command.socket
  2. Socket activation triggers vmsilo-banking@.service (proxy template)
  3. Proxy requires vmsilo-banking-vm.service, which starts crosvm
  4. 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; includes vm.<name>.hypervisor for VMM selection: crosvm or cloud-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 copying
  • networking.nix — TAP interfaces, host nftables for netvm = "host", guest network config
  • netvm.nix — auto VM-to-VM and VM-to-host network links
  • pci.nix — VFIO PCI passthrough setup
  • overlay.nix — root overlay (raw/tmpfs) setup
  • assertions.nix — validation checks
  • package.nix — final package derivation
  • lib/helpers.nix — crosvm argument building helpers
  • css-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 root
  • guest/users.nix — user accounts, sudo, SSH
  • guest/networking.nix — network config from kernel params
  • guest/wayland.nix — wayland proxy and session setup
  • guest/command.nix — vsock command listener, tray, idle watchdog
  • guest/system.nix — packages, graphics, fonts, misc
  • guest/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 --help for 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 isolation
  • flake.nix — exposes nixosModules.default and lib.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 --ssh
  • vmsilo-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.interfaces or network.netvm is 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. For autoStart GPU VMs, the session-bind service also starts the VM on login. Non-GPU autoStart VMs start at multi-user.target (boot).
  • GPU device backend: vmsilo-<name>-gpu service runs crosvm device gpu sandboxed; both crosvm and cloud-hypervisor attach via vhost-user. vmsilo-<name>-wayland-seccontext must start first.
  • Per-VM runtime dirs: all sockets under /run/vmsilo/<vmname>/ subdirectories (not flat).

Gotchas

  • nix build git index filtering: new files must be git add'd before nix build sees them (applies to all src = ./<path> references in flake.nix).
  • Explicit UID required: the configured user must have users.users.<name>.uid set 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 across scripts.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.