Architecture

How yeet and catch work together over Tailscale RPC.

Yeet is the client. Catch is the server. Both live in this repo, and catch runs on your homelab hosts.

Components

  • yeet: CLI that packages payloads and issues RPC calls.
  • catch: daemon that installs, runs, and monitors services.
  • catchrpc: JSON-RPC + WebSocket layer for exec/events.
  • internal registry: Docker registry served by catch for image pushes.

How a deploy works

  1. Yeet detects the payload type.
  2. Yeet streams the payload over RPC.
  3. Catch writes artifacts under the service directory.
  4. Catch installs or updates the service (systemd or docker compose).
  5. Catch publishes events for status/config changes.

Generations and staging

  • Each service has versions (generations).
  • stage uploads artifacts without applying them.
  • stage commit installs the staged generation.
  • rollback moves back one generation (if available).

Networking

Services can run in host, ts, svc, or lan network modes. See Networking for details and Tailscale for how RPC and service netns are wired.

Authorization

RPC access is gated by Tailscale identity:

  • Tagged nodes must share tags to connect.
  • Untagged nodes must match the owner of the catch node (unless the catch node is tagged).

See Tailscale for setup and tailnet behaviors.

Registry

The internal registry is served in two places:

  • HTTPS /v2/ on port 443 (for client pushes).
  • Loopback /v2/ on a local port (for docker pulls on the host).