Workflows
Common deploy and update flows for yeet.
These are the core workflows used day-to-day. All examples use placeholders.
yeet run <svc> ./compose.yml --net=lan
Get the LAN IP:
yeet info <svc>
yeet ip <svc>
After your first run, yeet writes a yeet.toml in the project directory. You
can then re-run with just the service:
yeet run <svc>
For a guided new-service deploy, run yeet run --web from the project
directory. The web flow keeps the browser form alive until a deploy succeeds.
Runtime errors appear in the browser terminal and the local terminal, and you
can edit the form and retry without restarting yeet run --web.
Update later (compose services; update pulls images and recreates
containers):
yeet run <svc> ./compose.yml # redeploy config, reuse existing images
yeet run --pull <svc> ./compose.yml # pull latest + redeploy
yeet run --force <svc> ./compose.yml # redeploy even if no changes are detected
yeet docker outdated # check for image updates without changing containers
yeet docker pull <svc> # prefetch images without restarting
yeet docker update <svc...> # pull + recreate containers (restart)
yeet docker update --outdated # update compose services that have image updates
Use --service-root to choose where a new service lives on the catch host:
yeet run vaultwarden ./compose.yml --service-root=/srv/apps/vaultwarden
yeet run vaultwarden ./compose.yml --service-root=tank/apps/vaultwarden --zfs
The path is absolute on the catch host. The parent directory (/srv/apps in
this example) must already exist; yeet can create the final service directory.
Each service root contains bin, run, env, and data.
For ZFS-backed service roots, pass --zfs and use the dataset name as
--service-root; catch resolves the dataset mountpoint and stores both the
dataset identity and the resolved filesystem path.
If the dataset does not exist, catch runs plain zfs create <dataset>. Parent
datasets must already exist. If the dataset already exists or its mountpoint
already contains files, catch prints a warning and deploys into it.
yeet run can set the initial root, but it cannot move an existing service. To
move a service, stop it first, then use yeet service set:
yeet stop vaultwarden
yeet service set vaultwarden --service-root=/mnt/fast/vaultwarden --copy
yeet service set vaultwarden --service-root=tank/apps/vaultwarden --zfs --copy
Use --copy to copy the old root into the new root, or --empty to create a
new empty root:
yeet service set vaultwarden --service-root=/mnt/fast/vaultwarden --empty
yeet service set vaultwarden --service-root=tank/apps/vaultwarden --zfs --empty
yeet service set leaves the old root in place. Non-interactive migrations
must pass either --copy or --empty. For the migration examples above,
/mnt/fast must already exist.
If the migration command was run outside the directory that contains the
service's yeet.toml, update the local replay config afterward:
yeet service sync vaultwarden --config ~/yeet-services/yeet.toml
For a config file with several services on the selected host:
yeet service sync --all --config ~/yeet-services/yeet.toml
ZFS-backed service roots get yeet-managed snapshots before redeploys, Docker image updates, and ZFS-backed service-root migrations. First deploys are skipped. The built-in default is enabled and required, keeps 5 yeet-created snapshots, and prunes yeet-created snapshots older than 7 days.
Show or change catch-wide defaults:
yeet snapshots defaults show
yeet snapshots defaults set --enabled=false
yeet snapshots defaults set --enabled=true --keep-last=5 --max-age=7d
yeet snapshots defaults set --events=run,docker-update --required=false
Override one service:
yeet service set vaultwarden --snapshots=off
yeet service set vaultwarden --snapshots=on --snapshot-keep-last=3 --snapshot-max-age=72h
yeet service set vaultwarden --snapshot-events=run,docker-update
yeet service set vaultwarden --snapshots=inherit
Snapshot-only yeet service set commands do not require the service to be
stopped. Service-root moves still require the service to be stopped. The catch
DB is the live source of truth; run yeet service sync <svc> to mirror
per-service snapshot overrides back into yeet.toml.
yeet run <svc> ./Dockerfile
GOOS=linux GOARCH=amd64 go build -o ./bin/<svc> ./cmd/<svc>
yeet run <svc> ./bin/<svc>
Pull a public image on the catch host:
yeet run <svc> nginx:latest
Push a local image instead (for custom builds):
yeet docker push <svc> <local-image>:<tag> --run
For binaries or compose files, just re-run yeet run with the new payload. For
compose images, add --pull (or use yeet docker update <svc...>) when you
want to refresh selected services. Use svc@host for individual targets that
should run on a specific host, such as yeet docker update web api@catch-b worker. Use yeet docker update --outdated to batch-refresh only compose
services reported by yeet docker outdated; scan errors are printed as skipped
rows so they are not mistaken for clean no-update results.
When a service already has a yeet.toml entry, a payload-only redeploy reuses
the saved run options and changes only the payload. You do not need to restate
the original network, tags, service root, snapshot, or payload args.
yeet run <svc> ./bin/<svc>
yeet stage <svc> ./bin/<svc>
yeet stage <svc> show
yeet stage <svc> commit
yeet edit <svc> # compose or systemd units
yeet env edit <svc> # env file
yeet env copy|cp <svc> ./app.env
yeet env set <svc> PORT=8080 LOG_LEVEL=debug
yeet env set <svc> LOG_LEVEL= # unset
yeet copy ./app.env <svc>:
yeet copy ./config.yml <svc>:config/config.yml
yeet copy ./configs/ <svc>:config/
yeet cron <svc> ./job.sh "0 9 * * *" -- --job-arg foo
yeet logs -f <svc>
Here, <host> refers to the catch host (Tailscale/tsnet hostname), not the
SSH machine host. See Tailscale.
Set the host per command:
CATCH_HOST=<host> yeet status
Or use @host:
yeet status@<host>
yeet run <svc>@<host> ./compose.yml
Or save it:
yeet prefs --host=<host> --save
Deploy a compose stack (most common)
Set or move a service root
Configure ZFS snapshots
Build from a Dockerfile and run
Deploy a binary
Run a registry image or push a local image (less common)
Update a service
Stage then commit
Edit config or env
Copy files into a service
Run a cron job
Tail logs
Multi-host usage