Backends
A backend is a stable contract — inputs (name, size, image, cloud-init, repo-sync
mode, ports) and outputs (a reachable SSH endpoint, instance id). Most backends
implement it as a Terraform module; the macOS vz backend implements it host-side
with lima instead (no usable Terraform provider, and it drives
Virtualization.framework on the host). The same interface drives every backend;
only TARGET changes.
| Backend | Status | Notes |
|---|---|---|
kvm (libvirt) | available | Local Linux host. dmacvicar/libvirt 0.9.x; repo live-mounted over virtiofs. |
proxmox (bpg) | validated | Remote node; cloud-init uploaded as a snippet. |
ec2 (aws) | validated | AWS instance; Debian AMI auto-looked-up; public IP is a real Terraform output. See the EC2 how-to. |
vz (Apple Virtualization) | available | macOS local via lima — host-side (not Terraform); reached over lima’s forwarded SSH port. See the vz how-to. |
hetzner / digitalocean / vultr | planned | Same contract. |
verda | planned | GPU cloud, for GPU agent workloads. |
libvirt version pin
The kvm backend pins dmacvicar/libvirt to ~> 0.9.8 — the raw-XML schema
(devices, os, memory_backing as attributes), which the module needs for
native virtiofs. Note 0.9.x exposes no computed guest IP, so ztd reads it from the
libvirt DHCP lease via virsh rather than a Terraform output.
Repo sync
The guest work dir is /home/<user>/<dirname>, where <dirname> is the name of
the directory you ran ./ztd from — so the guest mirrors your directory rather
than a generic repo. How your code gets there depends on the backend:
| Mode | Backends | Mechanism |
|---|---|---|
| live-mount | local (kvm, vz) | virtiofs — edit on host, guest sees it; files created in the guest stay owned by you on the host |
| sync-up | remote (proxmox, ec2, …) | cloud-init creates the (empty) dir; ./ztd mount sshfs-syncs your working tree (incl. .git) up on first mount (skips gitignored files), ./ztd fetch pulls the agent’s commits back — both operator-initiated over the ephemeral key |
The guest never contacts a forge — no clone-from, no push-to, no forge
credentials in the VM. All forge git is a host operation: code goes in via the
sync above, and the host pushes results after ./ztd fetch. See
The zero-trust model.
Rejected mechanisms: NFS (fine on a LAN, poor over a WAN — latency, VPN, host reachability); guest-mounts-host live mounts (a foothold into your machine — wrong trust direction); and the guest cloning/pushing to a forge (forge credentials in an untrusted VM).
macOS
A local VM on macOS uses Apple’s Virtualization.framework (vz backend via
lima), not KVM — so local is platform-native: on macOS the default local
target resolves to vz, exactly as it resolves to libvirt on Linux. The same
cross-platform binary does the right local thing on either OS; a bare ./ztd up
needs no TARGET, and TARGET=vz is just the explicit form. Unlike the Terraform
backends, vz runs host-side (lima drives the hypervisor directly), so its
lifecycle verbs (up/down/ssh/status/…) dispatch to a host script rather
than the toolbox container. The guest is reached
over lima’s forwarded SSH port on the ephemeral key; the working tree live-shares
with operator-owned files (lima’s vz virtiofs). Host needs only Docker +
lima — no privileged setup. See the vz how-to.