Three guides that existed only as one host's working copy, promoted to framework templates so every estate gets them. A working copy under ~/.mosaic binds one host; only a template here binds all of them. SEAT-IDENTITY.md (new) documents how a seat's git credential is actually resolved after #1311: identity from MOSAIC_GIT_IDENTITY, then mosaic.gitIdentity, then the stdin username; host mapped to a store prefix; then ONE of two stores chosen by whether the seat directory exists, with no precedence and no fallback between them. A seat with a directory and an empty slot fails closed rather than reaching the service store, and that is the point. It also corrects how to find the helper. credential.helper commonly names an absolute path, so `command -v git-credential-mosaic` answers a different question than the one git asks, and the two stop agreeing the moment the PATH copy is removed. Git also tries EVERY configured helper in order, so a fail-closed helper in front silently hands the request to whatever is configured behind it. The guide says to read the whole list. FLEET-COMMS.md (new) documents agent-send.sh: the class table, the addressing preamble, and the exit codes — including that rc=2 means the text reached the pane as an unsubmitted draft, so retrying double-sends it. Confirm with capture-pane instead. It also says to measure the fleet rather than trust roster.yaml, which on a live host was simultaneously naming a socket that did not exist, listing seats that were not running, and omitting seats that were. CODE-REVIEW.md gains an Evidence Discipline section: a green is not a result until you have shown it could go red, measurement and explanation are separate sentences, verify by content on the ref that ships rather than by ancestry of a local sha, and confidence is part of a finding. Plus four shell-measurement rules earned on #1311, each of which produced a wrong conclusion first — `cmd | tail; echo rc=$?` reports tail's status, a missed glob under pipefail exits 2 and kills the run under set -e, nonzero-with-no-output is an environment question before it is a code question, and `git -C` in a non-repo directory answers from the enclosing repo. The estate-specific repository exception that lived in the working copy is not carried here. The template says an estate may document one, scoped to a named repository and never precedent for a second. Both new guides are added to the two routing tables that agents read.
3.1 KiB
Fleet Comms Guide
How one seat reaches another on a host. The mechanism is the framework's; the sessions and sockets are per-host, so measure yours rather than trusting an example.
mosaic <runtime> would normally inject the addressing block from the roster. Where the composer
is unavailable, or where the roster is stale, this guide is the substitute.
Measure the fleet; do not trust the roster
fleet/roster.yaml is a declaration of intent, not an observation. It routinely names a socket
that was never created, lists seats that are not running, and omits seats that are — this was
measured on a live host on 2026-08-18 and all three were true at once. Find out what is actually
up before addressing anyone:
tmux list-sessions
tmux list-panes -a -F '#{session_name} #{pane_current_command} #{pane_current_path}'
The pane command tells you the runtime. A pane showing bash is an idle shell with no agent
attached — a send there lands in a shell prompt and is not read by anyone.
Use the default socket. Do not pass -L mosaic-fleet on the strength of the roster.
Sending
~/.config/mosaic/tools/tmux/agent-send.sh -s <dst_session> -C <class> -m "<message>"
-s also accepts session:window.pane. -f <file> sends a file body; stdin works too.
Classes
-C takes exactly one of these. Anything else exits 3.
| Class | Use for |
|---|---|
terminal-log |
log only; never needs the agent's attention |
actionable |
a decision, blocker, gate, or question needing an answer |
human |
relayed from a human operator |
reaction |
an ack or acknowledgement token |
digest |
machine wake, coalescible |
An absent class is treated as actionable by consumers, which is the fail-safe direction. Prefer
naming it anyway.
Addressing preamble
The wire format is [<src> -> <dst> class=<class>] <body>. Flip it when you reply — the tool
sends, it does not auto-reply.
Exit codes
| rc | Meaning |
|---|---|
| 0 | delivered or queued |
| 1 | target session not found |
| 2 | text reached the pane but is still a draft |
| 3 | usage error (bad class, missing -s) |
Never retry on rc=2. The message is in the target pane; retrying double-sends it. Confirm instead:
tmux capture-pane -p -t <session>:0.0 | tail -20
rc=2 is the normal result when the target is an idle pi seat.
Durable comms
tmux delivery is host-local and does not survive a pane. Anything that must outlive the session
goes through the estate's durable comms protocol — a committed comms/ tree in an estate repo,
with its own README. Use it for cross-host messages, verdicts, and anything a later session needs
to find.
Handing work across seats
- A verdict handed to the requesting seat is a legitimate delivery path, and the required one
for anything
pr-review.shwould otherwise post (seeguides/CODE-REVIEW.md). - Address the seat, not the runtime. A seat name is a session name; whether it runs claude, pi or codex is not the sender's business.
- Say what you measured, not just what you concluded — the receiving seat cannot see your terminal.