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.

BackendStatusNotes
kvm (libvirt)availableLocal Linux host. dmacvicar/libvirt 0.9.x; repo live-mounted over virtiofs.
proxmox (bpg)validatedRemote node; cloud-init uploaded as a snippet.
ec2 (aws)validatedAWS instance; Debian AMI auto-looked-up; public IP is a real Terraform output. See the EC2 how-to.
vz (Apple Virtualization)availablemacOS local via lima — host-side (not Terraform); reached over lima’s forwarded SSH port. See the vz how-to.
hetzner / digitalocean / vultrplannedSame contract.
verdaplannedGPU 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:

ModeBackendsMechanism
live-mountlocal (kvm, vz)virtiofs — edit on host, guest sees it; files created in the guest stay owned by you on the host
sync-upremote (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.