ADR 0005: Clanky Ships Its Stage — the clanky-herdr Binary
- Status: Proposed
- Date: 2026-07-05
Context
Clanky's terminal stage runs on clanky-herdr. The fork sources live in the
monorepo (ADR 0003) as a patch stack on upstream (clanky-agent ADR-0017),
but the running stage is still an environment assumption: Clanky attaches to
whatever herdr binary the user has installed and to a named session inside
it. That assumption costs real things:
- Version drift. The running stage server can lag the installed binary, and both can lag the fork sources the agent was developed against. Behavior that depends on fork-carried capabilities becomes probabilistic.
- Capability uncertainty. Fork capabilities (pane/session metadata, multi-client retained-render gating, watch/presence eventing) cannot be assumed present, so every consumer carries compatibility checks that exist only to tolerate a vanilla binary Clanky never actually targets.
- Incomplete containment. As a guest in the user's mux, Clanky must discover which panes are his. The roster, presence mirroring, and orchestration graph are best-effort reconstructions rather than facts.
- Wording tax. Docs and skills speak in "the active mux adapter" circumlocutions to preserve a tmux/Zellij adapter option no one is building.
The iOS window makes the assumption untenable: native attach, mirror mode, and relay pane read/steer all depend on fork behavior, so the app already hard-requires a binary the product does not control.
Decision
Clanky ships its stage. The herdr/ package builds a Clanky-branded stage
binary, clanky-herdr, installed and version-locked by Clanky's setup
wizard and supervised like any other Clanky component. It coexists with — and
never replaces or attaches to — a user-installed herdr.
The same pattern already governs ClankVox: a Rust plane the Node brain drives
over IPC, built idempotently at setup, resolved by explicit location, faulting
legibly when missing. clanky-herdr follows it:
- Full runtime isolation.
clanky-herdruses its own socket paths and state directory under Clanky's resolved data root ($CLANKY_HOME/stage/), never Herdr's defaults. A user's ownherdrCLI cannot reach Clanky's stage and Clanky's tools cannot reach the user's sessions. Binary and source locations are overridable (CLANKY_STAGE_BIN/CLANKY_STAGE_DIR, mirroringCLANKY_CLANKVOX_BIN/CLANKY_CLANKVOX_DIR). - One default session, supervisor-owned. The supervisor starts
clanky-herdrwith the brain on cold start and owns the default session. Single-session is Clanky's usage default, not a capability removed from the binary. - Complete containment by construction. Everything on the stage is in Clanky's domain: his workers, and anything the user opens there. Clanky is the lead agent over the whole stage; the roster, presence mirror, and orchestration graph are complete because the stage boundary is the ownership boundary.
- Stage marker. Panes inside Clanky's stage carry
CLANKY_STAGE=1in addition to the standard Herdr environment. Clanky surfaces (worker skill, spawn seam, coordination protocol) key on the Clanky marker, so they never misfire inside a user's personal Herdr session. - Fork capabilities are baseline. With the installed binary always
Clanky's own, fork-carried capabilities are assumed present and may be
hard-required — including relay-facing event subscriptions and pane/session
metadata shaped for the mobile mirror. The
StageProvidercapability checks remain as a testing seam, not a user-facing compatibility mechanism. - iOS glue. The relay attaches to the known stage socket; the app pairs to a stage whose version ships with the brain it talks to.
Mux-agnosticism as a shipping feature is dropped. The StageProvider seam
survives as design discipline with an honest justification: it keeps the AGPL
patch stack thin and rebasable against upstream, and keeps the agent testable
without a live stage. Product semantics stay in clanky-agent, per ADR-0017's
boundary — that part is unchanged.
flowchart TB
subgraph mac["Always-on Mac"]
sup["supervisor (launchd)"]
brain["clanky-agent brain"]
subgraph stage["clanky-herdr — default session ($CLANKY_HOME/stage/)"]
lead["Clanky face pane"]
w1["worker panes<br/>clanky:<slug>"]
up["user-opened panes"]
end
userherdr["user's own herdr<br/>(untouched, separate sockets)"]
end
ios["clanky-ios window"]
sup --> brain
sup --> stage
brain <-->|stage sockets| stage
ios <-->|relay WS| brain
ios -.->|attach / mirror| stage
Distribution
Shipping the binary is AGPL distribution of the clanky-herdr fork. That is
compatible with the existing posture — the clanky-herdr fork source remains
public and is vendored here — but it becomes a release checklist, not a
background fact:
- License text ships with the binary; the published fork stays in sync with every shipped build.
- The brain remains a separate process speaking to
clanky-herdrover sockets;clanky-agent's own licensing is unaffected. - Distributed macOS builds are signed and notarized.
- Keeping "herdr" in the binary name is deliberate: it carries attribution and provenance rather than hiding them.
Consequences
-
- Brain and stage version-lock on the same monorepo commit; the installed-binary drift class of bugs disappears.
-
- Fork capabilities are assumable, so relay/iOS features build against real eventing instead of polling-shaped workarounds.
-
- Setup is one wizard flow: build/verify
clanky-herdr, start the supervisor, pair the app.
- Setup is one wizard flow: build/verify
-
- Docs and skills name Herdr plainly; the adapter circumlocutions go away.
-
clanky-herdrjoins ClankVox in the compatibility surface: CI builds it, releases version it, and stage bugs are Clanky's to fix or carry as patches.
-
- The patch-stack discipline (
herdr-fork-rebase) stays mandatory. Owning the binary must not become an excuse to diverge from upstream and lose its terminal-emulation and performance stream.
- The patch-stack discipline (
-
- AGPL source-sync and notarization join the release checklist.
SPEC.md §2/§4.1 (clanky-agent) and the root package map drop the
mux-agnostic framing in the implementing change; clanky-agent ADR-0017's
capability-check boundary is reinterpreted as a testing seam by this decision.
The skill-layer consequences (naming, consolidation, config-rendered skills)
are clanky-agent ADR-0020.
