Install ztd

ztd is a single static binary. It carries its own runtime assets — the Terraform root, the lima template, cloud-init, the toolbox compose file — embedded inside it, so there is no ZTD source checkout to clone and nothing to keep in sync with the binary.

What it still needs from the host is the thing that can’t be shipped in a binary:

BackendHost needs
vz (local macOS)Docker + lima
kvm (local Linux)Docker + libvirt/qemu/dnsmasq + virtiofsd
proxmox / ec2 (remote)Docker only

Run ztd check after installing — it verifies every one of those and tells you the exact command to fix what’s missing.

macOS — Homebrew

The tap lives on GitLab, so it is added by URL:

brew tap frob/ztd https://gitlab.com/frob/homebrew-ztd.git
brew install --cask ztd

--cask, not a formula: Homebrew formulae are for building from source, and shipping a pre-built binary through one is deprecated upstream. The cask pulls in lima as a dependency (it is the hypervisor for the vz backend) and strips the Gatekeeper quarantine attribute at install time, so the first run doesn’t die with “cannot be opened because the developer cannot be verified”.

Docker is the other host requirement and is deliberately not a cask dependency — Docker Desktop, Colima or another runtime is your call. Install one before ztd up.

Upgrade and remove the usual way:

brew upgrade --cask ztd
brew uninstall --cask ztd

Linux — download the binary

Grab the archive for your architecture from the releases page, verify it, and drop the binary on your PATH:

VERSION=0.4.3                      # the release you want
ARCH=amd64                         # or arm64

base="https://gitlab.com/frob/ztd/-/releases/$VERSION/downloads"
curl -fLO "$base/ztd_${VERSION}_linux_${ARCH}.tar.gz"
curl -fLO "$base/checksums.txt"
sha256sum --check --ignore-missing checksums.txt

tar -xzf "ztd_${VERSION}_linux_${ARCH}.tar.gz" ztd
install -Dm755 ztd ~/.local/bin/ztd

Make sure ~/.local/bin is on your PATH. To upgrade, repeat with a newer VERSION; to uninstall, rm ~/.local/bin/ztd (and see Where ztd puts things below).

From source

You need Go and Docker:

git clone https://gitlab.com/frob/ztd.git && cd ztd
task go:build          # -> bin/ztd
task install:ztd       # symlinks bin/ztd onto $PATH (PREFIX=~/.local/bin)

Note the difference between the two entrypoints in a checkout: ./ztd is the dev wrapper, which points the binary back at the live source tree so script edits take effect immediately. The installed binary uses its embedded assets. When you want to test what a user gets, use the installed binary from a directory that is not the checkout — see CONTRIBUTING.

First run

From whatever directory holds the work you want an agent to touch:

ztd check      # host preflight — fix anything it flags
ztd setup      # local kvm only: applies the two host-side fixes
ztd init       # writes .ztd/ztd.toml (all keys commented; defaults boot)
ztd up         # boot a VM
ztd ssh
ztd down

ztd init also writes a .ztd/.gitignore so the ephemeral key, any API tokens, Terraform state and agent transcripts can’t be committed. ztd.toml itself is meant to be committed — it holds no secrets.

The backend defaults to local, which resolves per-platform: vz on macOS, kvm on Linux. Set backend in .ztd/ztd.toml (or TARGET= in the environment) for proxmox/ec2.

Where ztd puts things

PathWhatSafe to delete
<project>/.ztd/your config, ephemeral key, Terraform state, run recordsonly after ztd down
~/.cache/ztd/<version>/ (macOS: ~/Library/Caches/ztd)the extracted embedded assets for that versionyes — re-extracted on next run

The cache is version-scoped and re-created on demand, so an upgrade never leaves a stale asset tree behind and nothing you care about lives there.

Verifying what you installed

ztd version
ztd config      # includes the toolbox image this binary will pull

A released binary pins the toolbox container image to its own version — the ztd config output should read registry.gitlab.com/frob/ztd/ztd-toolbox:<that version>. A dev/snapshot build says ztd-toolbox:local and builds the image locally instead. See Pin or override the toolbox image.