docs/adr/0164-the-fleet-is-its-own-session.md

ADR 0164: The fleet is its own session

Status: proposed (2026-09-06). Its auto rule was overtaken before acceptance by ADR 0170: the session the service was launched inside is a signal again, and no binding is written back to settings. The rest of this record is in force — the fleet is still its own session, and it still outlives the service. Amends ADR 0157 (retires its adopt-the-surrounding-session rule) and ADR 0139 (retires the fork's scheduled death). Stands on ADR 0149: his session is chosen, and this decision says what the default choice is.

Context

The service's auto binding adopted whatever Herdr session it was launched inside. On the owner's machine that made every pane they ever opened a Clankie contact: their own agents showed on the roster, Clankie's hires landed in their workspaces, and a service restart shared a server with panes it had no business near. For an everyday user that is the wrong default. Someone who runs Herdr for their own work has not agreed to have every session read by Clankie, and the app's roster should not be a list of strangers who happen to share a terminal.

The fork question was decided at the same time. Prompt and spawn edges (ADR 0163) need herdr internals no plugin hook or CLI exposes, the fork carries a performance overlay the owner's GUI depends on under Clankie's polling, and nothing will be sent upstream. A fork with no scheduled death is a runtime Clankie owns, so the binary the owner runs must be the one Clankie ships or the fork's features are invisible to the one person using the product daily.

Decision

Clankie's fleet is its own Herdr session. A pane is Clankie's only if it lives in that session, and the way to opt a pane in is to create it there: through Clankie's own Herdr UI, or through his CLI, or through a hire from the app. No pane is ever adopted from the session the service was launched in.

  • auto binds bundled on first start, always. Only a session or socket the owner named (clankie herdr set --session NAME) makes the binding external, and then that named session is the fleet. (ADR 0170 amends this: the session the service was launched inside is preferred over bundled.)
  • Launching clankie inside some Herdr session is not a signal. HERDR_ENV, HERDR_SESSION, and HERDR_SOCKET_PATH play no part in the choice. (Amended by ADR 0170: HERDR_SOCKET_PATH names the session he leads when the owner has named none.)
  • The owner sees the bundled fleet through clankie-herdr, the viewer; a developer who wants a windowed session runs the fork binary and names a session of their own for the fleet, side by side with their personal one.
  • Clankie runs its own herdr. The bundled binary is built from the pinned fork commit, the owner's machine runs the same binary, and features the fleet needs may live in the fork. The upstream CLI and socket API remain the rule for anything that can be built without a patch, and every fork-only feature degrades to nothing on a binary that lacks it rather than breaking.

Consequences

  • The roster is Clankie's fleet and nothing else. "What is everything doing" means what his agents are doing.
  • A service restart or crash cannot touch a pane the owner opened for themselves.
  • The fork carries a rebase tax: every patch it holds is re-applied on each upstream pull. The cost is paid for in fleet features the plugin API cannot provide, and it is why a herdr change is the last resort after a service-side one.
  • The console and clankie seat claim a pane as his only when the terminal they sit in is the fleet's session, checked by socket. Opened inside any other Herdr they run as ordinary consoles: no pane is him, no pane is renamed there, and the turn leads the fleet from the service body.
  • The fleet outlives the service. Restarting Clankie must not close the panes its agents are working in, and a restart is the documented answer to every settings change. So the server runs in its own process group, where the launcher's group-wide stop of Clankie cannot reap it; losing the supervisor's channel, including to the SIGKILL the launcher escalates to, detaches instead of stopping; and a start that finds a live server still answering adopts it rather than refusing the socket. Stopping the fleet is explicit, through clankie-herdr server stop. This reverses ADR 0157's close-on-disconnect: an orphaned server is a fleet still working, and the socket is the lock that keeps there being exactly one.
  • The bundled runtime's private XDG_CONFIG_HOME, XDG_STATE_HOME and XDG_RUNTIME_DIR isolate that Herdr's own config, logs, and sessions, and Herdr hands its environment to every pane it opens. That isolation is the server's, not the owner's: a pane is the owner's shell, so the runtime names a pane shell (<state>/herdr/pane-shell, rewritten at every service start) that restores the owner's values of those three variables and then starts the owner's login shell. Without it gh is logged out, git and mise lose their config, and an agent hired inside the fleet cannot run the machine. CLANKIE_STATE_HOME is set alongside and points at the owner's real state home, so a console, seat, or launcher running inside the fleet resolves Clankie's own records rather than a directory that holds none. Without it the launcher reads its own healthy services as foreign.
  • Presence is reported against the binding's own herdr rather than whichever herdr sits on the caller's PATH, which for a bundled fleet is a different build that refuses the protocol. A report that fails is dropped: presence is a status line, and it may never take the console down with it.
  • An owner already bound to an external session keeps that binding; the service saves it once and auto only runs again after clankie herdr set --runtime auto. (ADR 0170 retires the save: the binding is resolved fresh at every start and settings hold only what the owner wrote.)