Data Layout

On-host storage layout for catch.

Catch stores state on the host under a single data directory (--data-dir). The default is ./data.

Top-level

<data-dir>/
  db.json
  services/
  mounts/
  registry/
  tsnet/

Per-service layout

By default, services live under <data-dir>/services/<svc>/. A service can use a custom root selected with yeet run <svc> <payload> --service-root=/abs/path or moved later with yeet service set <svc> --service-root=/abs/path.

yeet run vaultwarden ./compose.yml --service-root=/srv/apps/vaultwarden
yeet run vaultwarden ./compose.yml --service-root=tank/apps/vaultwarden --zfs

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.

Catch stores the authoritative live root in its DB, including both the mounted filesystem path and the ZFS dataset name when --zfs is used. yeet.toml stores the user-facing replay intent. If those drift because the service was mutated from a different directory, run yeet service sync <svc> to pull the root identity back into the local config.

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.

ZFS snapshots

For ZFS-backed service roots, catch can create yeet-managed snapshots before risky changes. The built-in default is enabled and required: catch snapshots before redeploys, Docker image updates, and ZFS-backed service-root migrations. First deploys are skipped because there is no prior service state to recover.

Catch prunes only snapshots it created for that service. Yeet-created snapshots are named with a yeet- prefix and tagged with ZFS properties such as com.yeetrun:created-by=catch, com.yeetrun:service=<svc>, and com.yeetrun:event=<event>. The default retention keeps the newest 5 snapshots and prunes snapshots older than 7 days.

Snapshot defaults and per-service overrides live in the catch DB because they control live service behavior. yeet.toml stores per-service overrides only as the local replay recipe; use yeet service sync <svc> if another checkout or machine changed the live policy.

<service-root>/
  bin/   # binaries, compose files, units
  run/   # runtime files
  data/  # persistent app data
  env/   # env files

Notes:

  • A custom service root is an absolute path on the catch host. The parent must already exist; yeet can create the final service directory.
  • A ZFS service root is a dataset name. If it does not exist, catch runs plain zfs create <dataset>. Parent datasets must already exist.
  • yeet run can set the initial root for a new service, but cannot move an existing service to a different root.
  • Moving a root uses yeet service set, requires the service to be stopped, leaves the old root in place, and requires --copy or --empty when running non-interactively.
  • ZFS snapshot settings are inherited from catch defaults unless a service has a snapshot override set by yeet run or yeet service set.
  • Env files are versioned under env/ and surfaced via yeet env show or yeet env edit.
  • Compose network files and Tailscale artifacts live under bin/ and run/ (see Tailscale).
  • mounts/ is host-global and used by yeet mount / yeet umount.