CLI Guide

Ad Hoc VMs

holos run launches a one-off VM without a compose file:

holos run ubuntu:noble
holos run --vcpu 4 --memory 4G ubuntu:noble
holos run -p 8080:80 --pkg nginx \
  --runcmd 'systemctl enable --now nginx' alpine
holos run -v ./code:/srv:ro ubuntu:noble
holos run --device 0000:01:00.0 ubuntu:noble
holos run --image-os openrc ./custom-alpine.qcow2
holos run alpine -- echo hello world

The synthesized compose file is stored at state_dir/runs/<name>/holos.yaml. The project name is derived from the image unless you pass --name.

Follow-up commands use the project name printed by holos run:

holos exec <name>
holos console <name>
holos logs <name>
holos down <name>

holos run exits once the VM is started. VMs are always detached. Use holos exec for an interactive shell and holos console for serial boot logs.

SSH With holos exec

Every holos up creates a project SSH key under state_dir/ssh/<project>/ and injects the public key with cloud-init. Each instance gets a host port forwarded to guest port 22.

holos exec web-0
holos exec db-0 -- pg_isready
holos exec my-project -- uname -a

-u <user> overrides the login user. Otherwise holos uses the service’s resolved cloud_init.user, then the image convention (alpine, arch, debian, fedora, ubuntu, almalinux, rocky, cloud-user), then ubuntu.

On a fresh VM, holos exec waits up to 60s for sshd to be ready. Use -w 0 to disable that wait or -w 5m for slow first boots.

Project Locks

Lifecycle commands take a per-project lock before reading or writing runtime state. holos up, run, down, start, stop, and ps -f wait up to --lock-timeout (default 5m) when another holos process is already operating on the same project. Use --no-wait when automation should fail fast instead of waiting:

holos up --lock-timeout 30s
holos down --no-wait demo

Lock errors include the lock path and last recorded holder metadata when available.

Image Verification

Built-in images carry checksum metadata. holos pull, holos up, and holos run verify downloads before promoting them into the cache and re-check a cached file before reuse. To audit the cache explicitly:

holos verify alpine
holos verify --all

holos images shows the guest OS metadata and hash algorithm used for each built-in entry. Local image paths are not trusted by name; set image_format and image_os in compose, or --image-os with holos run, when a custom image does not match the defaults. For private qcow2 images, keep a project checksum manifest such as images/SHA256SUMS or holos.images.lock and verify it before launching; the threat model has a fuller checklist.

Reboot Survival

Install a systemd unit so a project comes back after host reboot:

holos install --enable
holos install --system --enable
holos install --dry-run
holos uninstall

User units go under ~/.config/systemd/user/holos-<project>.service; system units go under /etc/systemd/system/.

If you use holos install --system --user <name>, also pass an explicit --state-dir that the target user owns. holos keeps state directories owner-only.

Import From virsh

holos import reads libvirt domain XML and emits a starting holos.yaml:

holos import web-prod db-prod
holos import --all -o holos.yaml
holos import --xml ./web.xml
holos import --connect qemu:///system api

It maps vCPU, memory, machine type, host CPU mode, UEFI loader, the first file disk, and PCI host devices. Extra disks, bridged NICs, USB passthrough, and custom emulators are reported as warnings so you can edit the generated compose file before holos up.

Doctor

holos doctor checks the host without launching a VM:

holos doctor
holos doctor --json

It verifies Linux/KVM availability, QEMU tools, a cloud-init seed builder, SSH, optional OVMF firmware for UEFI and PCI passthrough, and state-dir writability.