| D1 |
Session owner. What do Orca and Hermes connect to? |
Decided: herdr. herdr owns the session per container, and there is no custom listener to build. Orca and Hermes are optional front-ends. Orca runs orca serve --port 67xx --pairing-address <mini> per container or per Mini. The laptop pairs with an access link, and the phone pairs with a QR code. The Orca docs bless SSH forwarding as the transport, and the tailnet carries that path. Orca adds server-side accounts with orca account add --agent claude, which fits the per-container identity model. Hermes is a CLI and TUI with local, docker, and ssh terminal backends. It also reaches Telegram, Discord, Slack, and WhatsApp. Run it inside each container. Drive it from the phone over chat, or over the SSH TUI from the laptop. herdr stays the session keeper underneath both. One trial remains: run orca serve end to end over the tailnet in one container. |
T7 |
| D2 |
Access path |
Decided and locked: Tailscale. One tailnet holds the client devices and both Minis. WireGuard connects peers directly, and DERP is only a fallback. Tailnet identity and ACLs control access. There is no public endpoint. The EC2 host, autossh, and launchd tunnels are removed. Headscale is optional later, if you want to self-host the coordination server. |
T6, T7 |
| D3 |
Shared skills sync between the Minis |
Use a private git repo. It gives you versioning and an audit trail. |
T5 |
| D4 |
Container image base |
Decided: node:24-bookworm-slim, which is the current Active LTS. Rebuild and re-verify herdr on 24 in T2. |
T2 |
| D5 |
Session runtime that keeps agents alive across disconnects |
Resolved: herdr, as D11 describes. tmux stays installed as an emergency fallback, and it no longer starts. herdr also restores the layout and resumes conversations after a restart. tmux never did that. |
T5b, T8, T10 |
| D6 |
More than one agent instance. One container, or one container per instance? |
Run more than one herdr agent or pane in one container, so they share one identity. Cap them with the compose CPU and RAM limits. herdr makes this a pane count, not a port count. |
T9 |
| D7 |
Shared memory. Read-only, or writable? |
Decided: skills and tools stay read-only. Each client gets a writable /memory bind mount, at state/<client>/memory, which fleet.sh new creates. Shared team memory is append-only by convention only. |
T5, T5b, T9 |
| D8 |
Endpoint scheme past three clients |
Superseded. Names replaced ports. The registry at fleet/clients.md holds the mapping. One SSH path reaches each Mini, and you attach by container and agent name. Keep a port only for a tool that cannot speak SSH. |
T9, T6, T7 |
| D9 |
Host source mounts. Scope and performance |
Mount ~/Code/<client> only, never the whole home directory. Keep the hot paths in named volumes. |
T9 |
| D10 |
Where herdr state lives |
Decided: a Docker named volume at /home/node/.config/herdr. A macOS bind mount makes the server exit with EINVAL, because virtiofs lacks setxattr and O_TMPFILE. The image pre-creates the directory and owns it with the node user. The source folder, ~/.claude, and ~/.config/gh stay bind mounts. |
T10 |
| D11 |
Container runtime. Which process owns the panes? |
Decided: tini is PID 1 because of init: true. The herdr server is its main child, entered through fleet/entrypoint.sh and pinned to v0.9.5 with a sha256 check. The setting HERDR_CONFIG_PATH=/etc/herdr/config.toml keeps the state volume from shadowing the config. tmux stays installed but does not start. |
T5b, T10 |
| D12 |
Where herdr runs, and what a down -v costs |
Decided: herdr runs per container, never per Mini, and never off the box. The Claude integration hook reports the session id over the herdr local socket, and that is what makes the resume exact. The corollary matters: docker compose down -v deletes the herdr volume and loses the session ids. The transcript still survives in the ~/.claude bind mount, so a manual resume still works. |
T10 |
| D13 |
Which container runtime runs on a Mini |
Decided: Colima, not Docker Desktop. The fleet must return after a reboot with nobody at the machine. Docker Desktop runs its engine inside the GUI login session, so a LaunchDaemon cannot start it. Colima is a userland process. A LaunchDaemon runs fleet/colima-daemon.sh at boot as the operator, with launchd's UserName key. That wrapper holds the VM open and restarts it if it stops. The laptop keeps Docker Desktop until T8, then both sides align. Verified on the laptop with a user LaunchAgent. The system LaunchDaemon is not yet installed on a Mini. |
T6, T8 |
| D14 |
How the image reaches each Mini |
Decided: build once, then docker save | ssh <mini> docker load. One Dockerfile, one tag, identical bits. A local build stays in the local daemon. Build on a Mini only if that Mini is a different architecture. |
T2, T6 |
| D15 |
How a non-technical operator runs the runbook |
Decided: OliveTin as a thin button layer over the same scripts. It is optional, binds to 127.0.0.1, and is reached through an SSH tunnel. The scripts remain the source of truth. Two credential actions accept a secret: they use exec:, so no shell parses it, and the log records it as <redacted>. Every other action takes no secret. |
T8 |
| D16 |
Where Nix fits |
Decided: dev shell and operator shell only. The flake pins the tools a person types into a terminal. It does not manage the container runtime or the tailscaled daemon, because a store path inside a launchd plist breaks on the next garbage collection. |
T6 |