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.
Yeet uses "host" in two different ways:
- catch host (Tailscale/tsnet): the hostname that
yeettargets for RPC. This is whatCATCH_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.
--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.
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 installedvm://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.
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,runreuses 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.runcannot move an existing service to a different root; useyeet service setfor that.--zfs: treat--service-rootas a ZFS dataset name. Catch accepts an existing dataset or runs plainzfs 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 andyeet.toml.inheritclears 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 as72h, plus day values such as7d.--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 arerun,docker-update, andservice-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 forlan.--macvlan-vlan=<vlan>: VLAN id forlan.--macvlan-mac=<mac>: MAC address forlan.--cpus=<n>: override the default VM vCPU count forvm://payloads.--memory=<size>: override the default VM memory size forvm://payloads. Sizes accept suffixes such asmandg.--disk=<size>: override the default VM disk size forvm://payloads.--image-policy=prompt|update|cached: choose stale VM image cache behavior forvm://payloads. Interactive runs prompt by default. Non-interactive runs fail on stale cache unless you setupdateorcached.--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 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 showprints the staged config.stage clearremoves staged changes without applying them.stage commitapplies the staged version.
Stage flags match run flags (see above).
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.
Show service status.
yeet status
yeet status <svc> --format=json
Notes:
- With no
<svc>, yeet usesyeet.tomlhost list (if present) and queries each host. - Use
<svc>@<host>to disambiguate services that exist on multiple hosts. - Table output always includes the
HOSTcolumn, even for single-host queries. - Cron services (installed via
yeet cron) showTYPEascron. - Services show
TYPEasbinary,typescript, orpythonwhen detected; otherwiseserviceordockerbased on the underlying service type. - For docker compose services in the no-
<svc>view, containers are summarized into a singleCONTAINERScolumn and the status shows running/stopped/partial counts.
Tail service logs.
-f/--follow: follow logs.-n/--lines: number of lines (default-1).
Start a service.
Stop a service.
Restart a service.
Enable autostart for a service (systemd-backed services only).
Disable autostart for a service (systemd-backed services only).
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.
Roll back to the previous generation if available.
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 theyeet.tomlentry 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 preservesdata/.
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.
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.
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.
Print the current env file for a service. Use --staged to inspect the staged
env file.
Edit the env file for a service.
Upload a local env file. Alias: env cp.
Also stores the env file path in yeet.toml for future runs.
Set one or more env keys (creates the env file if missing). Use KEY= (or
KEY="") to unset a key.
Open the current config for editing in $EDITOR (defaults to vim).
--configedits the service JSON (limited; not implemented for docker/systemd content).--tsis reserved.--restartis currently unused.
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:
-ais archive mode (includes recursion and metadata preservation).-zcompresses 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.
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 sshtargets the catch host, not the machine host you used foryeet init.yeet ssh <svc>resolves the host from<svc>@<host>,--host,CATCH_HOST, oryeet.tomlservice 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
ubuntuunless 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_hostsentries.
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.
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.
Subscribe to events. Use --all for global events.
yeet events@<host> is shorthand for subscribing to all events on that host.
Show the service IP (only meaningful when --net=svc was used).
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.
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> updateuses a yeet-managed updater (not the officialtailscale updateself-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.
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.
Prefetch images for a compose service without restarting.
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.
Push a local image into the internal registry.
--run: tag image asrun.--all-local: push all local images for the service matching remote OS/arch.
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 tailnet hosts matching tags (default tag:catch).
Show or save client preferences.
Show the catch server version for the current host.
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
Unmount a mount by name.
yeet umount data-share
Hidden easter egg.
Host terminology
Global flags
Deploy and update services
run
Web deploy
stage
cron
Service control and status
status
logs
start
stop
restart
enable
disable
info
rollback
remove
service set
service sync
snapshots defaults
Config, env, and files
env show
env edit
env copy
env set
edit
copy
Connect and debug
ssh
vm images
vm console
events
Networking and Tailscale
ip
tailscale setup
tailscale (service netns)
Images and compose maintenance
docker outdated
docker pull
docker update
docker push
Host setup and discovery
init
list-hosts
prefs
version
mount
umount
Misc
skirt