yeet CLI

Client-side command reference for yeet.

This is the client-side command reference. Most commands are forwarded to catch. Use the sections below to find commands by task rather than by a raw alphabetical list.

Host terminology

Yeet uses "host" in two different ways:

  • catch host (Tailscale/tsnet): the hostname that yeet targets for RPC. This is what CATCH_HOST, --host, and @<host> refer to.
  • machine host (SSH): the SSH target you use with yeet init (for installing catch). Example: yeet init root@<host>.

After yeet init, catch will advertise a tsnet hostname (default catch or --tsnet-host). That tsnet name is the catch host you use for yeet run, yeet status, etc.

See Tailscale for how RPC and tailnet addressing work.

Global flags

  • --host=<host>: target host (overrides prefs).
  • --service=<svc>: force the service name.
  • --tty: force TTY mode for remote commands.
  • --no-tty: disable TTY mode for remote commands.
  • --progress=<mode>: progress output mode (auto, tty, plain, quiet).

Host scoping shortcuts:

  • yeet <command>@<host> for host-only commands (e.g. events@host).
  • yeet <command> <svc>@<host> to target a service on a specific host.

Note: Binary payloads uploaded by run, stage, and cron are zstd-compressed; catch auto-decompresses on receipt.

Deploy and update services

run

Install or update a service based on the payload:

  • Binary or script -> systemd service
  • Docker Compose file -> docker compose service
  • TypeScript file -> docker compose service using a container runtime
  • Python file -> docker compose service using a container runtime
  • Docker image ref (nginx:latest, ghcr.io/org/app:latest) -> pulled on the catch host and installed
  • Dockerfile -> built locally for the remote platform, pushed to the internal registry, then installed
  • vm://ubuntu/26.04 -> experimental Ubuntu VM service on KVM-capable hosts

Examples:

yeet run --web
yeet run --web <svc>
yeet run --web <svc> ./compose.yml
yeet run <svc>@<host> ./compose.yml
yeet run <svc> ./compose.yml --net=lan
yeet run --pull <svc> ./compose.yml
yeet run --force <svc> ./compose.yml
yeet run --env-file=prod.env <svc> ./compose.yml
yeet run vaultwarden ./compose.yml --service-root=/srv/apps/vaultwarden
yeet run vaultwarden ./compose.yml --service-root=tank/apps/vaultwarden --zfs
yeet run vaultwarden ./compose.yml --snapshots=off
yeet run <svc> vm://ubuntu/26.04 --net=svc
yeet run <svc> ./Dockerfile
yeet run <svc> ./bin/<svc> -- --app-flag value
yeet run <svc> ghcr.io/org/app:latest
yeet run -p 8000:8000 <svc> ./server.py

-p/--publish publishes host ports for python/TypeScript/Dockerfile payloads and registry image refs (e.g. -p 8000:8000). Yeet stores those mappings in yeet.toml and replays them on future runs. If you provide a new publish list on a later run, include every existing mapping you want to keep or pass --publish-reset to acknowledge replacement. For docker compose payloads, define ports in the compose file, then use yeet service set -p for follow-up changes.

When stdout is a terminal, run uses the full TTY progress UI (spinners, live updates). Pipe output for plain text. Use --progress=plain (or --progress=quiet) for POSIX-friendly scripted output.

Web deploy

For a guided first-time deployment, run:

yeet run --web
yeet run --web <svc>
yeet run --web <svc> ./compose.yml

Yeet opens a localhost browser form, validates the selected catch host and payload, and deploys the new service through the same path as the CLI. After you click Deploy, yeet opens a compact read-only terminal in the browser that mirrors the local terminal output. Successful deploys tell you to close the tab and return to the terminal. Failed deploys keep the form open so you can adjust fields and try again.

The web flow is for new services in this release. Redeploy existing services with the CLI form of yeet run.

If a yeet.toml exists (or after your first run), you can omit the payload:

yeet run <svc>
yeet run <svc> --force

Yeet will expand the stored payload + args for that service.

For an existing service, you can also provide only a new payload:

yeet run <svc> ./compose.yml

Yeet reuses the saved run options from yeet.toml and updates just the payload. If you pass new run args, saved --net and --ts-tags are still carried forward unless you explicitly provide different values, which is rejected after the initial deploy.

If you want to run a local image instead of pulling from a registry, use yeet docker push --run:

yeet docker push <svc> <local-image>:<tag> --run

Run flags:

  • --web: open a local browser form for a guided first-time deployment.
  • --pull: for docker compose/image payloads, pull latest images on deploy. Without this, run reuses existing images.
  • --force: redeploy even when yeet detects no payload/env/arg changes.
  • --service-root=/abs/path: choose the initial service root on the catch host. The path must be absolute and the parent directory must already exist. run cannot move an existing service to a different root; use yeet service set for that.
  • --zfs: treat --service-root as a ZFS dataset name. Catch accepts an existing dataset or runs plain zfs create <dataset>, resolves its mountpoint, and uses that path as the service root. Parent datasets must already exist. If the dataset already exists or its mountpoint already contains files, catch prints a warning and deploys into it.

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.

  • --snapshots=on|off|inherit: override the service snapshot policy saved in catch and yeet.toml. inherit clears the service override and uses the catch default.
  • --snapshot-keep-last=<n|inherit>: keep at most this many yeet-created snapshots for the service.
  • --snapshot-max-age=<duration|inherit>: prune yeet-created snapshots older than this age. Durations accept Go-style values such as 72h, plus day values such as 7d.
  • --snapshot-required=<bool|inherit>: decide whether a failed pre-change snapshot aborts the operation.
  • --snapshot-events=<list|inherit>: comma-separated events that should create snapshots. Supported events are run, docker-update, and service-root-migration.
  • --net=<list>: network modes (ts, svc, lan). Comma-separated.
  • --ts-ver=<ver>: tailscale version for service netns.
  • --ts-exit=<node>: tailscale exit node.
  • --ts-tags=<tag>: tailscale tags (repeatable or comma-separated).
  • --ts-auth-key=<key>: tailscale auth key for service netns.
  • --macvlan-parent=<iface>: parent interface for lan.
  • --macvlan-vlan=<vlan>: VLAN id for lan.
  • --macvlan-mac=<mac>: MAC address for lan.
  • --cpus=<n>: override the default VM vCPU count for vm:// payloads.
  • --memory=<size>: override the default VM memory size for vm:// payloads. Sizes accept suffixes such as m and g.
  • --disk=<size>: override the default VM disk size for vm:// payloads.
  • --image-policy=prompt|update|cached: choose stale VM image cache behavior for vm:// payloads. Interactive runs prompt by default. Non-interactive runs fail on stale cache unless you set update or cached.
  • --restart=<bool>: currently unused.
  • --env-file=<path>: upload an env file before deploying the payload.

When --env-file is provided (or yeet env copy is used), yeet stores the env file path in yeet.toml and re-uploads it on future runs.

See Tailscale for setup, netns behavior, and Serve examples.

For compose services, yeet docker update <svc...> also pulls and recreates containers.

stage

Stage a change without installing it yet.

Examples:

yeet stage <svc> ./bin/<svc>
yeet stage <svc> --net=ts --ts-tags=tag:app
yeet stage <svc> show
yeet stage <svc> commit

Notes:

  • stage show prints the staged config.
  • stage clear removes staged changes without applying them.
  • stage commit applies the staged version.

Stage flags match run flags (see above).

cron

Install a cron job from a file. The cron expression must have 5 fields.

yeet cron <svc> ./job.sh "0 9 * * *" -- --job-arg foo

If a yeet.toml exists (or after your first cron), you can omit the payload and cron expression:

yeet cron <svc>

When stdout is a terminal, cron uses the full TTY progress UI (spinners, live updates). Use --progress=plain (or --progress=quiet) for POSIX-friendly scripted output.

Service control and status

status

Show service status.

yeet status
yeet status <svc> --format=json

Notes:

  • With no <svc>, yeet uses yeet.toml host list (if present) and queries each host.
  • Use <svc>@<host> to disambiguate services that exist on multiple hosts.
  • Table output always includes the HOST column, even for single-host queries.
  • Cron services (installed via yeet cron) show TYPE as cron.
  • Services show TYPE as binary, typescript, or python when detected; otherwise service or docker based on the underlying service type.
  • For docker compose services in the no-<svc> view, containers are summarized into a single CONTAINERS column and the status shows running/stopped/partial counts.

logs

Tail service logs.

  • -f/--follow: follow logs.
  • -n/--lines: number of lines (default -1).

start

Start a service.

stop

Stop a service.

restart

Restart a service.

enable

Enable autostart for a service (systemd-backed services only).

disable

Disable autostart for a service (systemd-backed services only).

info

Show detailed service information collected from both the local yeet.toml and the remote catch host.

yeet info <svc>
yeet info <svc>@<host>
yeet info <svc> --format=json

Plain output is grouped by section (host, service, VM details when present, client config, server config, network, runtime, images) and the Network section includes published ports when catch reports them. Use --format=json or --format=json-pretty for machine-readable output with structured port mappings.

rollback

Roll back to the previous generation if available.

remove

Remove a service. yeet attempts to stop the service and clean up files, but will still remove the service from the database even if cleanup fails. Any stop/cleanup failures are printed as warnings.

Alias: rm.

Flags:

  • -y/--yes: skip the removal prompt.
  • --clean-config: delete the yeet.toml entry for the service. Without this flag, yeet prompts to keep or remove the local config after the service is removed.
  • --clean-data: delete service data, including VM guest disks. Without this flag, yeet preserves data/.

service set

Change service settings that require an explicit migration.

yeet service set vaultwarden --service-root=/mnt/fast/vaultwarden --copy
yeet service set vaultwarden --service-root=tank/apps/vaultwarden --zfs --copy
yeet service set vaultwarden --service-root=/mnt/fast/vaultwarden --empty
yeet service set vaultwarden --service-root=tank/apps/vaultwarden --zfs --empty
yeet service set vaultwarden -p 80:80 -p 443:443
yeet service set vaultwarden --publish-reset -p 443:443
yeet service set vaultwarden --publish-reset
yeet service set vaultwarden --snapshots=off
yeet service set vaultwarden --snapshots=on --snapshot-keep-last=3 --snapshot-max-age=72h
yeet service set vaultwarden --snapshots=inherit

Without --zfs, --service-root is an absolute filesystem path on the catch host. The parent directory (/mnt/fast in these examples) must already exist; yeet can create the final service directory.

With --zfs, --service-root is a ZFS dataset name. Catch accepts an existing dataset or runs plain zfs create <dataset>, resolves its mountpoint, and uses that path as the service root. Parent datasets must already exist. If the dataset already exists or its mountpoint already contains files, catch prints a warning and deploys into it.

The root contains bin, run, env, and data.

Use yeet service set to move an existing service root. The service must be stopped first, and the old root is left in place. Non-interactive migrations must choose one mode:

  • --copy: copy the old root into the new root.
  • --empty: create a new empty root.

yeet service set also changes per-service snapshot overrides. Snapshot-only changes do not require the service to be stopped; service-root moves still do. Use --snapshots=inherit to clear the whole service snapshot override, or set individual fields to inherit with flags such as --snapshot-keep-last=inherit.

-p/--publish changes the complete desired published-port list for a compose service. If the current list contains 80:80, then yeet service set vaultwarden -p 443:443 fails because it would remove 80:80. Keep existing mappings by including them in the command, or pass --publish-reset to replace or clear the list intentionally.

service sync

Pull catch-owned service settings into an existing local yeet.toml entry. Syncable settings include service_root, service_root_zfs, ports, and snapshot override fields such as snapshots, snapshot_keep_last, snapshot_max_age, snapshot_required, and snapshot_events.

yeet service sync vaultwarden
yeet service sync vaultwarden --config ~/yeet-services/yeet.toml
yeet service sync --all --config ~/yeet-services/yeet.toml

Use this after a live service is changed from another directory or another machine. The catch DB is the source of truth for live state; yeet.toml is the TOML replay recipe. Sync updates matching existing entries only and does not import every service from catch.

snapshots defaults

Show or change catch-wide snapshot 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

Snapshot defaults apply to ZFS-backed service roots. The built-in default is enabled and required, keeps 5 yeet-created snapshots, prunes yeet-created snapshots older than 7 days, and snapshots before run, docker-update, and service-root-migration events. Per-service overrides are managed with yeet service set.

Config, env, and files

env show

Print the current env file for a service. Use --staged to inspect the staged env file.

env edit

Edit the env file for a service.

env copy

Upload a local env file. Alias: env cp.

Also stores the env file path in yeet.toml for future runs.

env set

Set one or more env keys (creates the env file if missing). Use KEY= (or KEY="") to unset a key.

edit

Open the current config for editing in $EDITOR (defaults to vim).

  • --config edits the service JSON (limited; not implemented for docker/systemd content).
  • --ts is reserved.
  • --restart is currently unused.

copy

Copy files between local paths and a service data dir (rsync-like). Exactly one side must be remote using svc: or svc:path (paths are relative to the service data/ directory). By default, yeet copy behaves like rsync -avz (archive + verbose + compress). Alias: cp.

Examples:

# Local -> remote (data dir root)
yeet copy ./app.env svc:

# Local -> remote (explicit destination file)
yeet copy ./config.yml svc:config/config.yml

# Local dir contents -> remote dir (rsync-style)
yeet copy ./configs/ svc:config/

# Remote -> local
yeet copy svc:config ./config

Notes:

  • -a is archive mode (includes recursion and metadata preservation).
  • -z compresses the transfer stream.
  • Output mirrors rsync's file list and summary format.
  • File ownership (uid/gid) is not preserved.
  • A trailing slash on the source copies directory contents (rsync-style).
  • A trailing slash on the destination forces directory semantics.
  • Transfers are staged and moved into place only after completion.

Connect and debug

ssh

Open an SSH session to the catch host over the tailnet/tsnet address. If you pass a regular service name, the session starts in that service's data directory (<data-dir>/services/<svc>/data). If the service is an experimental VM, yeet ssh <svc> connects to the VM guest instead.

yeet ssh
yeet ssh <svc>
yeet ssh -- uname -a
yeet ssh <svc> -- ls -la

Notes:

  • yeet ssh targets the catch host, not the machine host you used for yeet init.
  • yeet ssh <svc> resolves the host from <svc>@<host>, --host, CATCH_HOST, or yeet.toml service entries. For regular services, it drops into the service data dir. For VM services, it connects to the guest.
  • Because it connects over Tailscale/tsnet, you can firewall port 22 on public/LAN interfaces and still reach the host via your tailnet.
  • For catch-host SSH and regular services, if catch reports an install user, that user is used for SSH; otherwise your SSH defaults apply. For VM services, yeet uses the VM-reported user or defaults to ubuntu unless you pass an SSH user option.
  • SSH options can be passed before the service name (e.g., yeet ssh -i ~/.ssh/id_ed25519 <svc>).
  • Use -- to pass a remote command. For regular services, the command runs from the service directory. For VM services, the command runs in the guest's default SSH session context.
  • For VM services on --net=svc, yeet proxies the SSH connection through the yeet host to reach the guest's private service-network IP.
  • For yeet-managed VM aliases in ~/.yeet/known_hosts, yeet ssh <vm> repairs a stale VM host key and retries once after a VM is recreated. Yeet does not edit normal ~/.ssh/known_hosts entries.

vm images

Show or refresh the experimental VM image cache on the selected catch host:

yeet vm images
yeet vm images --format=json
yeet vm images update

yeet vm images shows the host file-cache state for vm://ubuntu/26.04. yeet vm images update downloads and verifies the latest image bundle used for future VM creates. A missing image is downloaded automatically on the first VM create. Existing VMs are not rebuilt or modified.

For ZFS-backed VMs, the first create on a pool and image version prepares a shared ZFS image base. Later VMs on the same pool clone that base, so normal creates skip the base-image write.

vm console

Stream the serial console output for an experimental VM service:

yeet vm console <svc>

Use this when the guest is booting, when SSH is not available yet, or when the VM has no reported SSH address. Use yeet ssh <svc> for an interactive guest shell.

events

Subscribe to events. Use --all for global events.

yeet events@<host> is shorthand for subscribing to all events on that host.

Networking and Tailscale

ip

Show the service IP (only meaningful when --net=svc was used).

tailscale setup

Interactive setup for the catch host's Tailscale OAuth client secret using yeet tailscale --setup (alias: yeet ts --setup). The CLI walks you through creating a tag and a trust credential, then stores the tskey-client-... secret on the target host. Use --client-secret to skip the prompt.

See Tailscale for the full setup flow and related flags.

tailscale (service netns)

Run tailscale commands inside the service netns.

yeet tailscale <svc> -- serve --bg 8080
yeet tailscale <svc> -- debug daemon-logs
yeet ts <svc> update
yeet ts <svc> update 1.95.112
yeet ts <svc> update --version=1.95.112

Alias: yeet ts <svc> -- ....

Notes:

  • yeet ts <svc> update uses a yeet-managed updater (not the official tailscale update self-update path).
  • It asks for confirmation before upgrading.
  • To force the official subcommand behavior, use: yeet ts <svc> -- update.

See Tailscale for Serve/TLS details.

Images and compose maintenance

docker outdated

Checks Docker compose services for upstream image updates without pulling images, recreating containers, or restarting services.

yeet docker outdated
yeet docker outdated <svc>
yeet docker outdated <svc>@<host>
yeet docker outdated --format=json
yeet docker outdated --format=json-pretty

Default output shows only update, unknown, and error rows. Up-to-date containers are omitted. The table output is compact and hides raw digests; use --format=json or --format=json-pretty when you need exact running and upstream image digests.

docker pull

Prefetch images for a compose service without restarting.

docker update

Pull images and recreate containers (restart) for compose services installed from compose files.

yeet docker update <svc>
yeet docker update <svc-a> <svc-b>
yeet docker update <svc-a> <svc-b>@<host>
yeet docker update --outdated
yeet --host=yeet-prod docker update --outdated

Explicit service arguments update each requested compose service. A target like svc@host pins that service to one host; unqualified services use --host, a single matching yeet.toml service host, or the default catch host. When more than one target is updated, each update prints a short host/service marker before streaming the normal compose update output.

--outdated is a host-wide batch mode: it checks compose services for update rows, deduplicates by service, and updates only services with available image updates. Unknown or error rows are reported as skipped scan issues after running any updateable services, and the batch exits nonzero when scan issues remain. It does not take service arguments; use explicit services for selected updates.

docker push

Push a local image into the internal registry.

  • --run: tag image as run.
  • --all-local: push all local images for the service matching remote OS/arch.

Host setup and discovery

init

Install or update catch on a remote host via SSH.

yeet init root@<host>

If omitted, init uses the current CATCH_HOST value.

Note: the root@<host> here is the machine host you can reach over SSH. It is not the catch/tsnet host you target for yeet run or yeet status.

Run init from the yeet source repo (it builds ./cmd/catch). If you are in a different repo, clone github.com/yeetrun/yeet and run it from there.

If you omit the SSH user, init will try to use the install user reported by catch (recorded during the last install). If unavailable, SSH defaults apply. If catch reports an install host, init will prefer that host for SSH.

In interactive terminals, init will prompt to accept the SSH host key if needed. For non-interactive runs, pre-populate ~/.ssh/known_hosts.

When stdout is a terminal, init uses the full TTY progress UI (spinners, live updates). Pipe output for plain text. Use --progress=plain (or --progress=quiet) for POSIX-friendly scripted output.

list-hosts

List tailnet hosts matching tags (default tag:catch).

prefs

Show or save client preferences.

version

Show the catch server version for the current host.

mount

Mount a network filesystem on the host (global, not per-service). If no args are given, it lists mounts.

yeet mount host:/export data-share --type=nfs --opts=defaults
yeet mount             # list mounts

umount

Unmount a mount by name.

yeet umount data-share

Misc

skirt

Hidden easter egg.