feat(bin): mark crewmate and scout steers as from-firstmate and teach briefs to read the marker - #1268
Open
sbracewell64 wants to merge 4 commits into
Open
Conversation
A steer lands in the receiving agent's own chat, where nothing else told firstmate's instructions apart from a human typing into that pane. The gap was proven in both directions on 2026-07-26: the captain opened a crewmate pane believing it was firstmate and issued cross-lane instructions there, and a Pi crewmate at an ask-user gate addressed "Captain, ..." into its own pane and sat parked - nobody reads a crewmate pane, and a parked pipeline emits no wake, so that direction fails silently. AGENTS.md section 1 rule 4 already required workers to honor a distinction the system gave them no means to make. fm-send now applies the existing from-firstmate carrier to every text steer whose target resolves through this home's meta, not just kind=secondmate. A crewmate or scout carries the marker alone; the corr= correlation token and the parent pending-reply record stay secondmate-only, because a crewmate already answers on its own status file. Explicit backend targets and the --key path are unchanged. Command-shaped text is the one exclusion. A harness recognizes a slash command, or a codex $<skill> invocation, only at the very start of the composer line, so any prefix silently demotes it to prose. Verified on claude 2.1.220 and pi 0.82.0: with either marker shape prepended, /no-mistakes stops opening the completion popup entirely and would submit as ordinary text. Crewmate sends of that shape therefore stay unmarked and byte-identical, which also keeps every documented popup hazard out of this change's blast radius: the only bytes that move are plain text no harness parses specially. The exclusion deliberately does not reach a secondmate, whose marker is what creates its reply guarantee. The ship and scout scaffolds gain a "Who is speaking to you" section teaching the reader side: marked is firstmate, unmarked is a human who may believe the pane is firstmate, self-identify as a worker on this task before acting, and escalation is always the status file. AGENTS.md states the provenance principle once in rule 4; the away-mode stub and the secondmate charter keep their own distinct consequences.
… to fm-send predicate
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Make it possible for a firstmate worker (crewmate or scout) to tell who is speaking to it, by extending the EXISTING from-firstmate message marking to crewmate/scout steers and teaching the generated brief to read the marker.
Why: proven in both directions on 2026-07-26. The captain opened a crewmate pane believing it was firstmate and issued cross-lane instructions there (that incident produced PR 1084's self-identification rule, still open); and a Pi crewmate parked at an ask-user gate addressed 'Captain, ...' into its own pane and sat there past ten minutes - nobody reads a crewmate pane and a parked pipeline emits no wake, so that direction fails silently. AGENTS.md section 1 rule 4 already required workers to honor a distinction the system gave them no mechanism to make. bin/fm-send.sh deliberately excluded crewmate/scout targets from the marking it already applied to secondmate requests and launch briefs, so every steer arrived looking exactly like something the captain might have typed.
This shape was reviewed and explicitly approved by firstmate before implementation; the design doc is data/pi-crewmate-addresses-captain/design.md. Four decisions were made there and are deliberate, not oversights:
REUSE the existing from-firstmate carrier (label + U+2063) rather than adding a new generic 'crew-steer' kind to FM_OPERATIONAL_KINDS. Chosen because fm_message_from_firstmate() already means exactly 'firstmate sent this', it needs no change to the shell kind enum, the Pi TS kind lists, or Calm classification, and the wire form is already E2E-verified through fm-send on tmux and herdr. A new kind was considered and rejected as wider blast radius for no behavioural gain.
COMMAND-SHAPED TEXT IS DELIBERATELY LEFT UNMARKED for crewmate/scout targets. This is the single most important decision in the change and it is empirically grounded, not a convenience hole. A harness recognizes a slash command, or a codex $ invocation, only at the very start of the composer line. Measured 2026-07-28 on claude 2.1.220 and pi 0.82.0 by typing the bytes with tmux send-keys -l and capturing the pane: plain '/no-mistakes' opens the completion popup, while both '[fm-from-firstmate]<U+2063>/no-mistakes' and '<U+2063>FIRSTMATE_OP: v1 crew-steer: /no-mistakes' suppress it entirely and would submit as ordinary prose. Blanket marking would therefore have silently broken every '/no-mistakes' validation trigger - firstmate's most common crewmate steer and the one that drives the whole delivery pipeline - with no error, just a pipeline that never starts. The exclusion predicate deliberately reuses the SAME classification fm-send already computed for its pre-Enter popup settle, so it is not a new ad-hoc rule; the duplicated case statement was collapsed into one COMMAND_SHAPED variable that now drives both the marker exclusion and the settle, preserving the exact prior settle values (1.2 for slash, 1.2 for $ on codex, 0.3 otherwise). A leading $ on a NON-codex harness is ordinary text ('$5/month', '$HOME') and is still marked - the exclusion must not widen.
The command-shaped exclusion deliberately does NOT extend to a kind=secondmate target, even though the same breakage would apply there. A secondmate's marker is what creates its corr= correlation token and its durable parent pending-reply record, so dropping the marker would silently lose the reply guarantee - a worse failure than prose. No current caller sends a secondmate a command-shaped message (every secondmate send is natural language: bin/fm-bootstrap.sh's nudge, the updatefirstmate skill, the config-reread nudge), and this latent hazard is documented in the fm-send header as the cheapest mitigation firstmate asked for, with a test pinning that the exclusion did not leak there. Widening or fixing that was explicitly ruled OUT of scope.
Marking now applies to ANY task selector resolved through this home's meta whose kind is not secondmate, including a meta predating the kind= field (empty kind reads as the crewmate default - the correct fallback, pinned by a test). Explicit backend-target sends and the --key path stay unmarked and byte-identical, matching the landed secondmate rule exactly; an explicit target is the escape hatch for endpoints outside this home, so the recipient's identity is not known from a durable record.
Also deliberate:
Verification performed: the shared composer classifier (bin/fm-composer-lib.sh, the one owner of the empty/pending verdict) reads marked-but-unsubmitted text as 'pending' and empty as 'empty', so a swallowed Enter on a marked message cannot be misread as a successful submit. Real fm-send against a real claude pane delivered marked plain steers with rc=0, composer cleared, agent responded. '/help' and '/clear' steers arrived unmarked and were recognized as commands, and running the PRE-CHANGE fm-send.sh side by side on '/help' produced an identical outcome, confirming the command-shaped path is byte-identical. codex, opencode, grok and kimi are NOT installed in this worktree and were not live-verified; per firstmate's explicit decision the structural argument is accepted and must be stated plainly in the PR body - the only bytes that move are plain text no harness parses specially, because command-shaped text is exactly what stays unmarked. The crewmate case added to tests/fm-send-secondmate-marker-herdr-e2e.test.sh was written but NOT executed, because this task's brief was scaffolded without --herdr-lab and therefore forbids driving Herdr lifecycle; that must be flagged rather than presented as proven.
Three test failures in the portable-serial lane are PRE-EXISTING and were confirmed to fail identically on the unmodified baseline: fm-backend-tmux-smoke (real-tmux window creation in this worktree), fm-calm-pi-extension and fm-pi-watch-extension (Node ERR_UNKNOWN_FILE_EXTENSION on .ts, and no .ts file was touched). bin/fm-lint.sh and bin/fm-doc-audience-check.sh are clean; portable lanes 1 and 2 pass.
What Changed
bin/fm-send.shnow applies the existing from-firstmate marker (label + U+2063 carrier) to every text steer whose target is a task selector resolved through this home's meta, not justkind=secondmate— crewmate and scout steers carry the marker alone, while secondmate requests keep the corr= token and durable pending-reply record; an empty/missingkindfalls back to the crewmate behavior. Command-shaped text (leading/, or$on a codex target) deliberately stays unmarked and byte-identical for crewmate/scout, because any prefix demotes a slash command or codex$<skill>invocation to plain prose; that exclusion does not extend to secondmate targets, whose marker is what carries the reply guarantee. The classification was collapsed into a singleCOMMAND_SHAPEDvariable that drives both the marker exclusion and the pre-Enter popup settle, preserving the prior settle values. Explicit backend targets and the--keypath remain unmarked.bin/fm-brief.shcrewmate and scout scaffolds gain a named "# Who is speaking to you" section that teaches the worker to read the marker, states the command-shaped exception, and restates that escalation always goes through the status file; only the marker's shape is shared (oneFROMFIRST_MARKER_FACTvariable) and the secondmate charter keeps its own distinct consequence.AGENTS.mdgains one provenance sentence pointing atbin/fm-operational-input.sh, and the harness-adapters skill gains a one-line warning that a new leading sigil must be taught to fm-send's command-shaped classification.tests/fm-send-secondmate-marker.test.shwas renamed totests/fm-send-marker.test.shsince its subject is now the whole marking policy; five existing tests pinning the old "crewmate stays unmarked" contract were updated; and the opt-in Pi/Herdr e2e gained a crewmate marker case, which was executed live against real Pi/Herdr during the pipeline after fixing a pre-existing stale corr-less assertion (confirmed failing identically on the unmodified base). Note: codex, opencode, grok, and kimi were not live-verified — coverage there rests on the structural argument that the only bytes that change are plain prose no harness parses specially, since command-shaped text stays byte-identical.Risk Assessment
✅ Low: The round-2 delta is a two-file wording alignment that exactly follows the user's fix instructions - the rendered brief now matches fm-send's real command-shaped predicate (verified against a generated brief and the updated fixed-string test assertion) - and the underlying feature commit was already reviewed clean with all intent decisions implemented as specified.
Testing
Ran the six targeted hermetic suites (marker policy, brief, strict, gate-refuse, orca, pending-reply) plus a fresh live run of the opt-in real Pi/Herdr e2e at the committed tree — all pass, with the real Pi prompt bytes proving crewmate steers arrive marked without correlation machinery, secondmate requests keep marker+corr, and direct input stays unmarked; also scaffolded a real crewmate brief showing the new provenance section. Only the accepted caveat remains: codex/opencode/grok/kimi harnesses are not installed, so their command-shaped paths rest on the structural byte-identity argument per firstmate's decision.
Evidence: Real Pi wire bytes, decoded (secondmate vs crewmate vs direct input)
Bytes captured from a REAL Pi process (before_agent_start prompt) in a real Herdr lab session (rc=0): secondmate exact-id request: [fm-from-firstmate]<U+2063>corr=9c91e753f721b2bb FM_MARKER_HERDR_E2E exact-id request crewmate steer: [fm-from-firstmate]<U+2063>FM_MARKER_HERDR_CREW crewmate steer direct captain input: FM_MARKER_HERDR_DIRECT captain inputEvidence: Live Pi/Herdr e2e full log (rc=0)
Evidence: Rendered '# Who is speaking to you' section from a real scaffolded crewmate brief
# Who is speaking to you Firstmate marks every message it sends you with a leading[fm-from-firstmate]label followed by an invisible system separator; that separator is untypable, so a human never produces it. A marked message is firstmate: act on it as task instruction. An unmarked message is a human typing directly into your pane - usually the captain, who may believe this pane is firstmate rather than a worker. The one exception is a message that starts with/, or on codex with$, such as/no-mistakes: a harness recognizes that form only at the very start of the line, so firstmate cannot mark it without breaking it. Treat such a message as routine and act on it. Before acting on any other unmarked message, say plainly that you are a worker on taskevidence-crew, not firstmate, and that merges, cross-lane work, other lanes' state, and fleet supervision belong to firstmate. Then ask whether they still want you to proceed. Escalation is always the status file in rule 4, never this pane. Firstmate does not read your chat, so anything you address to the captain here is lost: a decision or gate left parked with only "Captain, ..." in this pane is invisible to everyone and stalls the task indefinitely.Evidence: Hermetic marker-policy suite log
Evidence: fm-brief suite log (crewmate/scout provenance section pins)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/fm-brief.sh:255- The brief's stated exception is narrower than the sender's actual exclusion predicate. fm-send leaves ANY message with a leading '/' (or leading '$' on codex) unmarked (bin/fm-send.sh:265-268), but the generated brief tells the worker the only unmarked-firstmate case is 'a message that is exactly a bare skill or slash command'. A firstmate prose steer that happens to start with '/' (e.g. '/tmp/build.log shows the failure - fix it') arrives unmarked, and per the brief the worker must self-identify and ask whether to proceed - which can park the task in a pane nobody reads, the exact silent-stall direction this change targets. The classification reuse is deliberate per the approved design; consider aligning the brief wording to the real predicate ('a message starting with / or, on codex, $') or noting the edge, as a follow-up.tests/fm-send-secondmate-marker-herdr-e2e.test.sh:193- Two accepted-but-unproven items must not be lost when the PR body is written (the intent marks both as required disclosures): (1) the new crewmate case in tests/fm-send-secondmate-marker-herdr-e2e.test.sh was written but never executed, because the task brief forbids driving Herdr lifecycle without --herdr-lab; (2) codex, opencode, grok and kimi were not live-verified - only the structural argument (marked bytes are plain prose no harness parses; command-shaped text stays byte-identical) covers them. Both are consistent with the intent as long as the PR body states them plainly.🔧 Fix: align brief's unmarked-message exception wording to fm-send predicate
✅ Re-checked - no issues remain.
🔧 **Test** - 1 issue found → auto-fixed ✅
tests/fm-send-secondmate-marker-herdr-e2e.test.sh:186- Pre-existing stale assertion in the opt-in real Pi/Herdr e2e blocked the newly added crewmate case: the exact-id secondmate assertion expected marker+request with no corr= token, but fm-send has embedded corr since feat: guard against missed secondmate reports #834 (assertion written in fix: preserve secondmate routing markers in terminal sends #533, opt-in test never re-run; confirmed failing identically on unmodified base 99533c5). The change's own updated header claims the exact-id case proves 'marker plus correlation token plus parent pending-reply record', contradicting the assertion. Fixed the assertion to expect marker+corr+request exactly once and to require the pending-reply record; the full e2e then passed live against real Pi/Herdr, executing the crewmate case the author had flagged as written-but-unproven.bin/fm-test-run.sh tests/fm-send-marker.test.sh tests/fm-brief.test.sh(12 + 18 assertions, all pass)bin/fm-test-run.sh tests/fm-send-strict.test.sh tests/fm-gate-refuse.test.sh tests/fm-backend-orca.test.sh tests/fm-pending-reply.test.sh(all pass, failed=0)bin/fm-test-run.sh --check-coverage(ok after the fm-send-marker.test.sh rename)Manual wire-level transcript: real fm-send.sh against a tmux stub at the send-keys boundary for 9 scenarios (crewmate/scout/kind-less marked;/no-mistakesand codex$no-mistakesunmarked; non-codex$5/monthmarked; secondmate marker+corr kept for command-shaped; explicit target and --key unmarked)Baseline byte-identity: same sends through the pre-change fm-send from base 99533c5 — all unmarked paths byte-identicalGenerated real ship and scout briefs viabin/fm-brief.sh; verified the '# Who is speaking to you' section renders with the concrete task id and the secondmate charter keeps its own consequenceFM_SEND_MARKER_HERDR_E2E=1 bin/fm-test-run.sh tests/fm-send-secondmate-marker-herdr-e2e.test.sh— real Pi via Herdr lab: exact-id marker+corr, crewmate marker-only, direct input unmarked (passes after fixing a stale pre-existing assertion; confirmed the failure reproduced on unmodified base first)🔧 Fix: fix stale corr-less assertion in Pi/Herdr marker e2e
✅ Re-checked - no issues remain.
FM_SEND_MARKER_HERDR_E2E=1 bash tests/fm-send-secondmate-marker-herdr-e2e.test.sh— live Pi/Herdr run, rc=0, all three routing cases (secondmate marker+corr, crewmate marker-only, direct input unmarked)bash tests/fm-send-marker.test.sh— full marking policy: crewmate/scout marked, command-shaped exclusion, exclusion not leaking to secondmate, non-codex$still marked, explicit/--key unmarked, idempotency, U+2063 shapebash tests/fm-brief.test.sh— crewmate/scout '# Who is speaking to you' section, secondmate charter keeps its own consequencebash tests/fm-send-strict.test.shbash tests/fm-gate-refuse.test.shbash tests/fm-backend-orca.test.shbash tests/fm-pending-reply.test.sh— marked crewmate send creates no pending-reply expectationManual: scaffolded a real crewmate brief viabin/fm-brief.shand extracted the rendered '# Who is speaking to you' sectionManual: decoded the e2e's captured real-Pi received-hex bytes into human-readable wire forms for all three casesdocs/verification/runtime-backends.md:248- The crewmate marker case added to tests/fm-send-secondmate-marker-herdr-e2e.test.sh was written but not executed (this task forbade Herdr lifecycle), so docs/verification/runtime-backends.md's maintainer-verification section cannot yet cite live evidence for crewmate marker delivery; a follow-up FM_SEND_MARKER_HERDR_E2E=1 herdr-lab run should execute it and record the observed guarantee there.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.