docs: relabel built-in defaults as the firstmate repo - #688
Merged
Merged
Conversation
Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged.
LoneExile
added a commit
to LoneExile/firstmate
that referenced
this pull request
Jul 19, 2026
kunchenguid#688) "template" is overloaded in this repo (launch templates, PR-poll templates, and the design-tenet shared template), so the absent-captain/absent-file defaults wording the captain reads in AGENTS.md section 3, the fm-session-start.sh digest comment, and secondmate-provisioning now names the firstmate repo's built-in defaults instead. Captain-read clarity only; no behavior change. Contract tests (fm-instruction-owners, fm-captain-translation-contract, fm-stow-contract, fm-supervision-instructions, fm-bootstrap, fm-ensure-agents-md) green.
kirubeltadesse
added a commit
to kirubeltadesse/firstmate
that referenced
this pull request
Jul 20, 2026
* fix: restore fleet snapshots on stock macOS Bash (kunchenguid#578) * fix: restore stock macOS snapshot parsing * no-mistakes(document): Clarify Linux gate and macOS CI coverage * fix(afk): make Pi escalation and return catch-up reliable (kunchenguid#587) * fix: close away-mode blocker supervision gap * no-mistakes(review): Gate teardown retries and verify U+2063 dedupe * no-mistakes(test): Fail closed on incomplete Pi composer separators * no-mistakes(document): Document Pi composer recognition and return gating * feat: support Pi max reasoning profiles (kunchenguid#537) * support Pi max thinking profiles * no-mistakes(review): Captain, allow Pi max dispatch profiles * chore: no-mistakes(document): Clarify yolo response ownership (kunchenguid#595) * Clarify validation response ownership * no-mistakes(document): Clarify yolo response ownership * feat: establish instruction ownership foundation (kunchenguid#619) * Add instruction owners foundation * no-mistakes(document): Refresh project-management owner pointers * fix: compress Firstmate contract and enforce delivery rigor ownership (kunchenguid#626) * docs: compress firstmate operating contract * docs: make delivery rigor single-owner PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion. * no-mistakes(review): Honor configured merge authority across faster delivery paths * no-mistakes(document): Align docs with compressed operating contract * feat: add durable captain decision holds (kunchenguid#593) * Add durable captain decision holds * no-mistakes(review): Validate decision hold retries and origin paths * no-mistakes(review): Enforce durable decision lifecycle boundaries * no-mistakes(review): Harden decision display and partial retry recovery * no-mistakes(test): Update scout teardown fixtures for decision inventory * no-mistakes(document): Align decision lifecycle and scout teardown documentation * no-mistakes: apply CI fixes * no-mistakes(review): Reconcile terminal decision holds * no-mistakes(document): Align captain decision-hold documentation * fix(bin): harden PR check artifacts (kunchenguid#556) * fix: harden PR check artifacts * fix: close PR check migration gaps * fix: close PR check retry gaps * fix: clarify migration outcomes and ESM boundary * fix: keep failed migrations authoritative * test: use inert PR validation fixtures * no-mistakes(review): Reserve noncanonical PR quarantine namespace * no-mistakes(review): Prevalidate final PR-check teardown artifacts * no-mistakes(review): Preserve X metadata and validate teardown IDs * no-mistakes(review): Initialize migration state before watcher exclusion * no-mistakes(review): Isolate failed poll migrations from bootstrap recovery * no-mistakes(review): Allow safe polling during incomplete private repairs * no-mistakes(review): Authenticate watcher checks at execution time * no-mistakes(review): Preserve custom checks with hash-bound registration * no-mistakes(review): Clean custom check snapshots on watcher signals * no-mistakes(review): Stop watcher checks promptly on signals * no-mistakes(review): Terminate watcher check groups before cleanup * no-mistakes(document): Correct stale X-mode watcher documentation * fix: drain returned watcher check groups * no-mistakes(review): Harden quarantine links and recover validated replacement polls * no-mistakes(review): Preserve X mode across shim version transitions * no-mistakes(review): Refresh legacy X shims before marker short-circuits * no-mistakes(document): Correct persisted PR-check artifact documentation * no-mistakes(document): Correct stale PR-check documentation * fix: bind PR poll repair provenance * no-mistakes(review): Enforce single-link ownership for custom check artifacts * no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs * no-mistakes(review): Separate task creation and legacy teardown validation * no-mistakes(review): Restore safe legacy operations and teardown validation * no-mistakes(review): Disambiguate migration obligations and preserve legacy retries * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits * no-mistakes(document): Document private poll artifact safety contracts * no-mistakes(lint): Suppress intentional literal-dollar lint finding * fix: migrate historical X poll identity * fix: harden PR check artifacts * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * fix: migrate historical X poll identity * no-mistakes(review): Harden X-mode artifact publication against symlink corruption * no-mistakes(review): Guard X artifact publication * no-mistakes(review): Enforce private X artifact reads * no-mistakes(test): Fix backend compatibility fixture dependencies * no-mistakes(document): Refresh PR-check documentation * no-mistakes(lint): Remove unused x-mode test locals * no-mistakes: apply CI fixes * fix(bin): compact session-start backlog digest (kunchenguid#636) * fix: compact session-start backlog digest * no-mistakes(test): Fix legacy backend fixture helper * no-mistakes(test): Fix watcher exit wait helper * no-mistakes(document): Document compact backlog digest * fix: dedupe stale watcher guard banners (kunchenguid#637) * fix: dedupe stale watcher guard banner * no-mistakes(review): Keep read-only guard state nonmutating * no-mistakes(document): Clarify stale watcher docs * fix(bin): balance bearings landed baseline (kunchenguid#640) * fix: balance bearings landed defaults * no-mistakes(document): Document balanced landed baseline * no-mistakes: apply CI fixes * fix: clarify captain-facing translation contract (kunchenguid#644) * docs: clarify captain-facing translation contract * no-mistakes(review): Restore runtime fallback mandate * no-mistakes(document): Align Bearings translation wording * fix(bin): make bootstrap output and nudges deterministic (kunchenguid#646) * fix: make bootstrap nudges deterministic * no-mistakes(review): Honor state override for bootstrap nudges * no-mistakes(review): Update benign bootstrap documentation labels * no-mistakes(review): Validate bootstrap nudge retry markers * no-mistakes(document): Align bootstrap nudge documentation * no-mistakes: apply CI fixes * docs(secondmate-provisioning): clarify concise registry ownership (kunchenguid#649) * Clarify concise secondmate registry contract * no-mistakes(review): Expand secondmate registry boilerplate coverage * no-mistakes(document): Point route docs to owner * fix(bin): strip quoted blocked_by values during decision hold resolve (kunchenguid#654) * fix(bin): strip quotes on blocked_by in decision-hold resolve tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary membership test only matched middle elements. Strip surrounding quotes before matching so first and last hold ids resolve correctly. * no-mistakes(document): Refresh decision-hold regression evidence * feat(secondmate): inherit shared captain preferences (kunchenguid#656) * feat(secondmate): inherit shared captain preferences * no-mistakes(review): Honor shared captain data overrides * no-mistakes(review): Honor bootstrap data override registry * no-mistakes(document): Refresh shared inheritance docs * no-mistakes(document): Clarify inherited local-material docs * feat: gate local agent secret injection (kunchenguid#658) * feat(spawn): gate local agent secret injection * fix(spawn): align final Keychain slot * no-mistakes: apply CI fixes * test: isolate Herdr autodetect smoke sessions (kunchenguid#662) * test: isolate herdr autodetect smoke session * no-mistakes(review): Restored autodetect smoke gate bypass * no-mistakes(test): Harden Herdr lab provisioning * no-mistakes(document): Refresh Herdr lab docs * docs: adopt under way for active work (kunchenguid#666) * Revert "feat: gate local agent secret injection (kunchenguid#658)" (kunchenguid#668) This reverts commit c27135c. * fix(pi): distinguish stale locks when arming watcher (kunchenguid#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (kunchenguid#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (kunchenguid#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (kunchenguid#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (kunchenguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (kunchenguid#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> kunchenguid#166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (kunchenguid#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (kunchenguid#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (kunchenguid#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (kunchenguid#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (kunchenguid#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (kunchenguid#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (kunchenguid#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * refactor: slim AGENTS.md to ~200 lines, reference files for details * docs: use canonical expanded reference files from main repo --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: Johans Ballestar <47162770+Ballestar@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com>
vitalNohj
added a commit
to vitalNohj/firstmate
that referenced
this pull request
Jul 24, 2026
* feat(pi): simplify primary session launch (#386)
* docs(readme): reformat Quick Start and recommend Grok equally with Claude Code
* no-mistakes(review): Captain: align harness launch guidance
* no-mistakes(review): Captain, clarify Pi supervised launch
* no-mistakes(review): Captain, document Pi first-launch bridge
* feat(pi): track primary watcher extension for plain-pi launch
Move Pi's primary watcher bridge from a generated state/ file to a
tracked .pi/extensions/fm-primary-pi-watch.ts, matching how the turn-end
guard extension already works: self-hashing version, project-local
auto-discovery after one-time Pi trust. This drops the state/-generation
step and dual -e requirement from the happy path, so Pi's Quick Start
launch becomes plain 'pi', the same friction class as 'claude' and
'grok --trust'.
- bin/fm-pi-watch-extension.sh is removed; nothing generates the
extension anymore since it is committed.
- fm-session-start.sh and fm-supervision-instructions.sh resolve the
watcher extension path from FM_ROOT instead of state/, and the
session-start diagnostic now points at restarting plain pi after
trust, with -e as a documented fallback.
- fm-spawn.sh points Pi secondmate launches at the tracked extension
path in the secondmate home instead of generating a state/ copy.
- README Quick Start Pi block is now just 'pi' plus a trust note.
- Tests, docs, and the harness-adapters skill updated to match.
* fix(pi): drop backticks from session-start diagnostic to satisfy shellcheck SC2016
* feat(supervision): prevent unsafe watcher-arm commands (#387)
* feat(supervision): add PreToolUse seatbelt against watcher-arm anti-patterns
Adds bin/fm-arm-pretool-check.sh, a shared PreToolUse-style checker that
denies a primary shell command backgrounding, piping, or bundling the
watcher arm/checkpoint, or force-killing the watcher process broadly -
the exact shapes that silently took Grok's supervision down. Wires it
into all five verified harnesses (grok, claude, codex, opencode, pi),
each validated empirically against the real harness.
Also fixes a grok 0.2.93 regression discovered during that validation: the
existing turnend-guard Stop hook's bare root variable broke grok's own
variable pre-substitution and silently no-op'd the hook.
* no-mistakes(review): Harden watcher arm validation
* no-mistakes(review): Harden arm guard metacharacter checks
* no-mistakes(review): Harden nested shell arm guard
* fix(lint): rewrite SC2015 guards in fm-arm-pretool-check.sh as if/then
A && B || C is not if-then-else; C can run when A is true. Replace both
occurrences of the quote-state early-continue with an explicit if/then.
* fix(pi): restore primary watcher supervision lifecycle (#397)
* fix Pi primary supervision lifecycle
* no-mistakes(document): Synchronize Pi primary extension documentation
* fix: keep persistent secondmates out of the main backlog (#398)
* fix secondmate backlog guidance
* no-mistakes(review): Require reasons for captain backlog holds
* no-mistakes(test): Document secondmate handoff skill requirement
* fix secondmate teardown reminder
* no-mistakes(document): sync teardown reminder docs to work-items-only backlog contract
* fix(backlog-handoff): move full item blocks including indented bodies (#401)
* fix(backlog-handoff): move full item blocks including indented bodies
fm-backlog-handoff only moved the checklist header line, so multi-line
item bodies were left orphaned in the source backlog and never reached
the secondmate. Move the full block (header plus indented body lines)
atomically, treating body membership by indentation so lines like
## Intent stay with the item, and add regression coverage.
* no-mistakes(review): Captain: preserve EOF handoff terminators
* no-mistakes(review): treat blank lines inside item bodies as movable body
* no-mistakes(document): sync backlog-handoff docs with full-block move behavior
* feat(herdr): make Herdr lab lifecycle safety deterministic for briefs (#402)
* guard Herdr lab lifecycle in briefs
* no-mistakes(review): Fix Herdr lab helper and provisioning safety
* no-mistakes(review): Captain, harden Herdr lab lifecycle safety
* no-mistakes(review): fix Herdr lab test cleanup ordering and brief help range
* no-mistakes(review): reject leading options in Herdr lab run guard
* no-mistakes(review): strip leading non-alnum in Herdr lab name generator
* no-mistakes(document): document Herdr lab helper and --herdr-lab brief flag
* no-mistakes(lint): add shellcheck disable for deliberate SC2016 literals in fm-brief herdr-lab
* no-mistakes: apply CI fixes
* fix(watcher): classify arm-command seatbelt by execution position (#403)
* fix watcher arm command policy
* no-mistakes(review): Harden watcher command policy parsing
* no-mistakes(review): Captain: harden watcher policy parsing
* no-mistakes(review): harden watcher policy for expanded paths, direct-watch, and sound prefilter
* no-mistakes(review): close prefilter and classifier locale/ANSI-C watcher-path decode gaps
* no-mistakes(review): fail closed on loop-wrapped broad watcher kills
* no-mistakes(document): sync docs for watcher-arm command-position policy
* fix: reconcile existing AGENTS.md safely (#405)
* fix(agents-md): inject self-governance section into existing AGENTS.md
fm-ensure-agents-md.sh only appended the canonical "## Maintaining this
file" section on skeleton create or CLAUDE.md promotion, so an existing
AGENTS.md that lacked it exited unchanged and forced hand-copying the
wording during a rollout across existing projects. Call the already-
idempotent ensure_maintenance_section on the existing-AGENTS.md paths and
report whether the file changed; a re-run and an already-complete file stay
byte-identical.
Also fixes #389: refuse a case-variant real memory file (e.g. a lowercase
agents.md) instead of silently emitting a CLAUDE.md symlink whose uppercase
literal target dangles once the tree lands on a case-sensitive filesystem.
Tests extend tests/fm-ensure-agents-md.test.sh; skeleton-create and
CLAUDE.md-promotion regressions still pass. Docs updated to match.
* no-mistakes(review): Captain: preserve CRLF maintenance-section idempotency
* no-mistakes(review): Preserve CRLF during maintenance-section injection
* no-mistakes(review): Captain: harden dangling-symlink regression coverage
* no-mistakes(document): Document agent-memory injection outcomes
* feat: support project-less secondmate homes (#409)
* feat(secondmate): support project-less homes via --no-projects
fm-brief.sh --secondmate and fm-home-seed.sh now accept an explicit
--no-projects signal to scaffold, seed, and register a secondmate home
whose subject is the firstmate repo itself (no clones). The signal is
mutually exclusive with a project list; omitting both still fails loudly
so an accidental omission is never a silent project-less seed. The
registry line renders an empty projects: field, which spawn and the
snapshot already tolerate. Docs updated in the secondmate-provisioning
skill and both script headers.
* no-mistakes(review): Captain: document project-less secondmate flow
* no-mistakes(review): Captain: refuse project-less reseeding of populated homes
* fix(seed): fail closed on unreadable project data
* no-mistakes(review): Captain: reject stale projectful charters
* no-mistakes(review): Captain: fail closed on unsafe project paths
* no-mistakes(review): Captain: validate project-less charter clone sections
* no-mistakes(document): Document project-less secondmate seeding
* fix: delegate backlog handoffs to tasks-axi (#411)
* wip(handoff): record verified delegation design + tasks-axi mv blocker
No production code changed yet. tasks-axi mv (v0.2.1) cannot atomically
move a blocked-by-linked item set across backlogs (deadlocks both orders,
no batch/--force), which fm-secondmate-lifecycle-e2e requires. Parked
pending a tasks-axi connected-set mv enhancement; note captures the
verified design, semantics, test/CI/doc changes, and resume checklist.
* refactor(handoff): delegate the item move to tasks-axi mv
fm-backlog-handoff.sh's two-pass awk was a second parser of the backlog
format and the source of the PR #401 body-orphaning drift. Delete it and
delegate the move to `tasks-axi mv <id>... --to <dest>` (v0.2.2 atomic
multi-id), the single owner of the format: a connected set (blocker plus
dependents) moves together with blocked-by preserved, item blocks stay
byte-exact, and destination section placement holds. The helper keeps only
the fleet-level validation tasks-axi cannot know - secondmate-home
resolution, the seeded-home safety checks, the In-flight refusal, and
idempotent per-key reporting - and is atomic: on any move failure nothing
moves.
Tests: fm-backlog-handoff.test.sh keeps PR #401's regression matrix but now
exercises the delegated path and skips cleanly when tasks-axi is absent; the
two whole-file fixtures move to tasks-axi's canonical whitespace. The
lifecycle-e2e and safety move-cases gain the same skip guard. CI installs
tasks-axi so the delegated path is exercised. Docs state that
config/backlog-backend=manual governs firstmate's own hand-editing, not this
validated helper, which delegates fleet-wide because bootstrap requires
tasks-axi on PATH.
Remove the now-redundant WIP design note.
* no-mistakes(review): Captain: harden atomic backlog handoffs
* no-mistakes(review): Captain: enforce queued-only backlog handoffs
* no-mistakes(review): Captain: harden handoff section parsing
* no-mistakes(document): Document delegated backlog handoffs
* no-mistakes(lint): Silence ShellCheck source diagnostics
* fix: ignore secondmate home marker during sync (#417)
* fix: gitignore the secondmate home marker
bin/fm-home-seed.sh writes an untracked .fm-secondmate-home marker into
every seeded secondmate home. A secondmate home is a worktree of the
firstmate repo, so any plain `git status --porcelain` dirtiness check
counted the untracked marker and the home read as dirty forever:
fleet-sync reported it STUCK and the local fast-forward convergence
sweeps risked leaving it stale on firstmate updates.
Add .fm-secondmate-home to the tracked .gitignore so the marker is
invisible to every dirtiness check uniformly, without weakening
fleet-sync's deliberate untracked-counting for project clones.
Convergence chicken-and-egg: existing homes predate the fix and it only
arrives by fast-forward. The already-present marker-tolerant ff-skip
(ignore_seed_marker=yes, used by the bootstrap sweep, /updatefirstmate,
and spawn pre-launch) advances such a home past the fix commit, after
which .gitignore takes over - no hand intervention.
Tests in tests/fm-secondmate-sync.test.sh cover a freshly seeded home
reading clean, an existing marker-only home converging then reading
clean, and a genuinely dirty home still skipping.
* no-mistakes(review): Captain: document standalone-clone update path
* no-mistakes(document): Document secondmate marker migration
* fix(composer): prevent dead-shell message injection (#416)
* fix(composer): stop reading dead-shell prompts as empty agent composers
Consolidate composer empty/pending/unknown classification into one shared
owner, bin/fm-composer-lib.sh's fm_composer_classify_content, delegated to by
all four backend adapters (tmux via fm-tmux-lib.sh, herdr, orca, cmux). This
replaces four drifting copies of the glyph decision.
Safety fix: a bare shell prompt glyph (> $ % #) on an unstructured row is now
classified unknown (a dead shell, unsafe for injection), not empty. It is only
empty inside a bordered composer box (the harness's own prompt). Agent glyphs
❯ (claude) and › (codex) read empty either way. The away-mode injector
(inject_msg) now requires an affirmatively-empty composer, deferring on pending
or unknown, so an escalation can never be typed into (or executed by) a pane
whose agent exited to its login shell.
Regression coverage: new tests/fm-composer-lib.test.sh pins the shared owner;
per-backend dead-shell tests in fm-daemon (tmux + injector), orca, and the
existing herdr/cmux suites. shellcheck clean; herdr incident regressions stay
green.
* no-mistakes(review): Captain: harden composer safety checks
* no-mistakes(test): Stabilize Herdr prune safety setup
* no-mistakes(document): Document composer injection safety
* no-mistakes(lint): Clean composer safety lint
* no-mistakes: apply CI fixes
* feat(watcher): add paused external-wait supervision (#421)
* feat(watcher): add paused/awaiting-external crew state
A crew (or firstmate steering it) can declare a deliberate wait on a known
external dependency with a paused: <reason> status. Both the always-on watcher
and the away-mode daemon absorb such an idle pane through shared fm-classify-lib.sh
vocabulary instead of tripping the possible-wedge stale escalation, and re-surface
it for a recheck only on a long bounded cadence (FM_PAUSE_RESURFACE_SECS) so a
forgotten pause cannot rot invisibly. fm-crew-state.sh reports state: paused
distinctly. A crew that goes idle without declaring a pause classifies exactly as
before. Docs and brief scaffold state lists updated; tests colocated.
* no-mistakes(review): Captain: fix paused-state transitions
* init
* no-mistakes(review): Captain: fix paused-state supervision transitions
* no-mistakes(review): Captain: fix paused supervision handoffs
* no-mistakes(review): Reconcile paused supervision markers
* no-mistakes(review): Captain: prioritize paused states over captain relevance
* no-mistakes(review): Captain: preserve paused-working wedge timer
* no-mistakes(review): Captain: honor configured pause verb in briefs
* no-mistakes(test): Captain: fix AFK paused watcher handoff
* no-mistakes(document): Document declared external waits
* no-mistakes(lint): Clean paused-state lint
---------
Co-authored-by: fmtest <fmtest@example.invalid>
* fix: preserve X-mode follow-up platform limits (#425)
* fix(x-mode): make follow-up platform splitting immune to link ordering
A ~470-char Discord follow-up posted as a (1/2)(2/2) thread split at ~280
chars because fm-x-link only learned the platform from the inbox payload,
and the fmx-respond ack path can drain that inbox file before the task is
linked. A link recorded after cleanup silently lost the platform and the
splitter defaulted to the X 280-char budget.
Make platform resolution ordering-proof:
- fm-x-link now resolves the platform AUTHORITATIVELY by request_id via a
new fmx_request_relay_context helper (POST /connector/request-context)
when neither the inbox payload nor carry flags carry it. The request_id
survives the inbox drain, so a post-cleanup link still learns the right
split budget. Best-effort: no token/curl or a non-2xx relay degrades to
the loud warning below rather than a silent X default.
- fm-x-link warns loudly when no platform source resolves, so the loss is
never silent.
- The fmx-respond procedure now orders link-before-inbox-cleanup so the
fast local path stays correct without a relay round-trip.
Colocated regression tests: a Discord follow-up >280 <2000 posts as ONE
message even when linked after inbox cleanup, and an unresolvable platform
warns loudly instead of splitting silently. docs/configuration.md documents
the request-context lookup.
The relay endpoint is the companion durable change (see done status); until
it ships, the link-before-cleanup reorder keeps the normal path correct.
* no-mistakes(document): Document X-mode platform recovery
* fix(composer): handle ANSI ghost text safely (#429)
* fix(composer): one ANSI-aware ghost owner covers claude dim + grok truecolor
Away-mode injection wedged all night on the primary claude-on-herdr pane:
the herdr composer classifier never stripped generic dim ghost text (only a
narrow codex bold-wrapped byte-pattern check), so claude's rotating
prompt-suggestion ghost - a bare "❯" then SGR-2 dim text, which herdr's ANSI
pane read preserves - read as real pending input and every escalation deferred
(6524 lifetime "pending input (non-empty composer)" defers; wedge 30623s).
Consolidate ghost extraction into one fleet-wide ANSI-aware owner,
fm_composer_strip_ghost (bin/fm-composer-lib.sh), that drops every
de-emphasised run - dim/faint (SGR 2: claude, codex) AND a dark/muted truecolor
foreground (grok's placeholder, luminance below FM_COMPOSER_GHOST_LUMA_MAX,
default 128, dark-theme assumption). Both ANSI-capable backends route through
it: fm_tmux_composer_state (fm_tmux_strip_ghost is now a thin adapter) and
fm_backend_herdr_composer_state. The herdr-only faint byte-pattern check is
removed and fm_backend_herdr_strip_ansi reduced to a thin adapter over the
shared fm_composer_strip_ansi. Bordered detection now reads the plain row so a
dark box border dropped with the ghost does not lose the composer shape.
This also closes the documented grok TRUECOLOR placeholder gap by the same
mechanism (harness-adapters skill note updated).
Empirical evidence (read-only live capture + isolated tmux, no herdr lifecycle)
and the incident write-up are in docs/herdr-backend.md; deterministic
regressions feed the exact captured bytes through the real classifiers
(tests/fm-backend-herdr.test.sh, tests/fm-composer-ghost.test.sh). Two prior
ghost-test fixtures that used a near-black 38;2;1;2;3 as "real" colored text
(never a realistic real-input color) are corrected to a bright 38;2;224;222;244,
preserving the truecolor payload-skip parser intent.
* no-mistakes(review): Preserve dark shell prompt safety
* no-mistakes(review): Harden erased shell prompt classification
* no-mistakes(document): Document shared composer ghost extraction
* no-mistakes(lint): Normalize tmux comment punctuation
* fix(spawn): make tmux window handling robust under non-default config (#134)
* test: isolate session-start suite from ambient harness markers (#432)
* fix(session-start): isolate harness env markers in suite runner
Neutralize CLAUDECODE, PI_CODING_AGENT, and GROK_AGENT in
run_session_start so ambient interactive shells cannot override the
suite's fake ps harness (local-vs-CI split on the pi supervision case).
* no-mistakes(document): Correct Pi marker documentation
* fix(teardown): retry transient index locks during worktree return (#435)
* fix(teardown): retry treehouse return on transient index.lock
Killed crew git ops can leave a short-lived worktree index.lock that
makes treehouse return fail. Retry on that error signature with a
bounded wait (env-overridable), never force-delete a live lock, and
only then fall back to the existing provably-stale cleanup path.
* no-mistakes(review): Harden teardown retry configuration
* no-mistakes(document): Document teardown index-lock retry behavior
* no-mistakes(lint): Fix empty shell variable assignments
* fix: complete brief help and consolidate documentation (#438)
* docs: de-feature the scripts.md and CONTRIBUTING test inventories
Slice 1 of the documentation redundancy cleanup wave (firstmate scope).
docs/scripts.md: every row is now one purpose clause; script headers
are the declared owner of behavior, flags, and contracts. Coverage
stays 61/61 scripts; bytes drop 19,922 -> 7,958.
CONTRIBUTING.md: the 54-row per-test inventory is gone; contributors
discover tests by listing tests/*.test.sh and reading each script's
own header, and gated tests print their own skip gates. The run
commands, symlink assertions, and watcher smoke line are unchanged.
Lines drop 135 -> 84 (18,797 -> 7,831 bytes).
Two facts that existed only as inventory rows moved into their
owners' headers first: fm-brief.sh's paused-vs-blocked scaffold
distinction and fm-session-start.sh's Pi extension-loaded check.
No instruction-surface or behavior change; AGENTS.md untouched.
* no-mistakes(review): Captain, fix brief help and Grok test discovery
* no-mistakes(review): Captain: document Grok lock-holder test coverage
* fix: detect Git and centralize backend configuration (#445)
* docs: consolidate universal backend contracts into configuration.md
Slice 2 of the documentation redundancy cleanup wave (firstmate scope).
docs/configuration.md is now the declared single owner of three
universal contracts, each with an explicit ownership sentence:
- the universal toolchain list (Toolchain), now also carrying the
per-tool purpose clauses that previously lived only in the tmux guide;
- the task-selector vocabulary (Runtime backend);
- the tasks-axi compatibility definition (Backlog backend).
The five backend guides' prerequisites replace their verbatim
universal-requirements parentheticals (5 full copies) with a pointer
plus only backend-specific items; zellij/cmux selector restatements
and architecture.md's partial copy become pointers or are dropped;
CONTRIBUTING's compatibility sentence becomes a pointer; two
near-verbatim orca-bootstrap restatements (configuration.md Runtime
backend, orca guide) collapse into the Toolchain owner copy.
Backend-specific setup, behavior, target-string shapes, and every
empirical verification record are untouched. AGENTS.md untouched
(slice 3).
* docs: include git and GitHub auth in the toolchain owner list
The review flagged that the new universal-toolchain owner omitted git
and GitHub authentication while every backend guide now defers its
prerequisites here; bootstrap's NEEDS_GH_AUTH check makes them real
universal requirements.
* no-mistakes(review): Detect Git in bootstrap toolchain
* no-mistakes(document): Clarify GitHub CLI and centralize selector documentation
* feat(daemon): add backend-independent wedge alerts (#444)
* feat(daemon): backend-independent active alert for the wedge alarm
When away-mode injection wedges past max-defer, inject_wedge_alarm only
actively signalled via the tmux status-line, which is skipped on non-tmux
backends. A wedged claude-on-herdr primary left only the passive
state/.subsuper-inject-wedged marker (2026-07-10 overnight incident).
Add a config-gated active alert (config/wedge-alarm, local/gitignored;
FM_WEDGE_ALARM_CHANNEL) that reaches the captain even when every pane and
its status-line is unreadable: an OS-level macOS notification (osascript),
a herdr notification, or a captain-supplied command. Default-on (auto) so
the alarm is never silent; each channel best-effort, degrading to the next
and never crashing the daemon loop. The tmux flash and durable marker stay.
The OS notifiers route through a single FM_WEDGE_ALARM_EXEC seam. When the
daemon is sourced (only tests do this; production execs it) the seam
defaults to "discard", and tests/wake-helpers.sh points it at a recorder,
so it is structurally impossible for any test to post a real notification.
Channels verified once manually on macOS 26.5.2 / herdr 0.7.3; see
docs/wedge-alarm.md.
* no-mistakes(review): Bound wedge alarm notifier execution
* no-mistakes(review): Captain: harden wedge alarm notifier safety
* no-mistakes(review): Captain: harden wedge alarm test notifier isolation
* no-mistakes(review): Captain: harden wedge alarm throttling
* no-mistakes(review): Redact wedge alarm directive logs
* no-mistakes(review): Harden wedge alarm notifier safety
* no-mistakes(review): Track notifier process groups through cleanup
* no-mistakes(document): Document wedge-alarm active alert behavior
* docs: centralize firstmate operating contracts (#447)
* docs(agents): extract conditional AGENTS.md material to owned homes
Slice 3 of the documentation redundancy cleanup wave (firstmate scope):
the always-loaded instruction surface drops from 941 lines / 116,733
bytes (~29k tokens per session per fleet member) to 785 / 91,353
(~22.8k tokens), moving only audit-identified conditional and
situational material while preserving every load-bearing invariant at
its trigger point via the inline-stub pattern.
Moves, each to one declared owner plus an inline stub:
- section 3's bootstrap output-line handbook (~44 lines) -> new
agent-only bootstrap-diagnostics skill, added to the section 13
trigger index; the detect-consent-install rule and the
do-not-dispatch gate stay inline as safety-critical.
- section 4's crew-dispatch JSON schema and field semantics ->
docs/configuration.md 'Crew dispatch profiles' (pointer direction
flipped); the intake procedure, precedence, backstop, and
never-select-unverified rules stay inline.
- section 4's quota-balanced algorithm -> bin/fm-dispatch-select.sh
header (now the declared owner; usage() converted to the dynamic
header extraction pattern PR #438 established for fm-brief.sh).
- section 7's spawn resolution narrative and example sprawl ->
bin/fm-spawn.sh header; the isolated-worktree assertion, refusal-is-
a-blocker rule, and post-spawn duties stay inline.
- section 7's teardown landed-work mechanics -> bin/fm-teardown.sh
header (section 1's containment pointer retargeted); the fork benign
case and never-force rule stay inline.
- section 8's watcher classification narrative -> docs/architecture.md
'Event-driven supervision' (already the owner); every operative rule
(one live cycle, no turn ends blind, drain first, wake ladder,
never-pkill, guard responses) stays inline.
- sections 3/4/6/7 secondmate sync, propagation, schema, and handoff
restatements -> secondmate-provisioning skill, now the declared
owner including the literal-file inheritance nuance.
- section 14's X-mode cadence mechanism -> docs/configuration.md
'X mode (.env)', closing issue #363; activation semantics, the
fmx-respond trigger, and the terminal-wake final-follow-up duty
stay inline.
CLAUDE.md stays a symlink; no behavior or test change.
* no-mistakes(document): Centralize contract-owner documentation
* fix(cmux): close last workspace during teardown (#449)
* fix(cmux): close the last/selected workspace in a window at teardown
cmux keeps every window at >=1 workspace, so close-workspace on the only
workspace in a window silently no-ops (returns OK, workspace stays), and a
window holding a live session cannot be closed over the control socket.
That left a selected task workspace open at teardown (the last workspace
in a window is always the selected one).
Add fm_backend_cmux_window_of_workspace and have fm_backend_cmux_kill
create a throwaway default sibling in the target's window before closing
when the target is the last workspace there, so the close lands; the
window keeps a fresh default workspace (cmux's own "closed the last tab"
outcome). Non-last teardown closes directly, as before.
Cover both kill branches plus the helper with fake-CLI unit tests, add a
real-cmux window/count detection smoke assertion, and record the
empirical evidence in docs/cmux-backend.md.
* no-mistakes(review): Derive cmux count from membership snapshot
* no-mistakes(document): Document cmux last-workspace teardown behavior
* fix: recover orphaned packed-refs locks during fleet sync (#453)
* fix(fleet-sync): recover from an orphaned packed-refs.lock
A git ref rewrite (fetch --prune, pack-refs, branch -D) killed after
creating .git/packed-refs.lock but before renaming it - e.g. bootstrap's
timed-out fleet-sync kill or teardown's process kills - leaves a lock that
makes the next sync's fetch fail with "Unable to create
'...packed-refs.lock': File exists", leaving the clone unsynced.
On that signature only, fm-fleet-sync.sh now retries the fetch with a
bounded wait (transient locks self-clear), then removes the lock and
retries once more ONLY when it is provably stale: still present, mtime
age past a threshold, and no lsof holder of the lock file or of the clone
worktree itself (a live git keeps that as its cwd even in the window after
it closes the lock and before it exits). A live lock, a missing lsof, any
failed check, or any other fetch failure keeps today's behavior. Every
wait/retry/removal prints to stderr, and a successful recovery also prints
one "recovered:" summary to stdout so a session-start refresh - which
discards fleet-sync stderr and relays only stdout - still surfaces it.
The shared "is this git lock provably abandoned?" proof is extracted into
bin/fm-lock-lib.sh so it has one owner, used by both fm-teardown.sh and
fm-fleet-sync.sh. Constants are env-overridable knobs. tests/fm-gotmp.test.sh
gains the fm-lock-lib.sh symlink teardown now needs in its fake bin/.
* no-mistakes(review): Captain, remove obsolete teardown wake dependency
* no-mistakes(document): Document packed-refs lock recovery architecture
* feat(herdr): escalate blocked panes immediately (#472)
* feat(herdr): immediate blocked-state escalation via native events.subscribe push
Fold herdr's native pane.agent_status_changed stream into the single watcher so
a crew entering blocked wakes its supervisor sub-second (measured 0.129s)
instead of after the ~240s stale-pane wedge timer.
- bin/fm-transition-lib.sh: backend-neutral normalized-transition record shape
plus the single-owner status->action policy table (blocked=actionable,
working=absorb+clear-dedupe, idle/done=defer, else=fall back to polling).
- bin/backends/herdr.sh + herdr-eventwait.py: a raw AF_UNIX events.subscribe
subscriber over one connection for all this home's herdr panes, subscribing to
ALL statuses, returning the first fresh blocked edge, with a per-pane dedupe
marker and a reconnect level-reconcile. Version/schema capability gate.
- bin/fm-backend.sh: has-push / events-capable / wait-transition dispatchers so
the watcher stays backend-agnostic and the shape+policy are reusable.
- bin/fm-watch.sh: splice the bounded event wait in as the watcher's terminal
wait primitive (replacing the blind sleep POLL for push-capable homes),
behind a source guard so the splice is unit-testable; secondmate/paused
exemptions; map pane->window->task and enqueue a stale wake. No second
watcher process; the single-cycle invariant and every guard/beacon/turn-end
mechanism are unchanged.
- Polling stays the permanent fail-closed backstop: below-capability, subscribe
failure, and repeated runtime failures all degrade to sleep.
- Tests: fake-CLI units (fm-transition-lib, wait/apply/dedupe/reconcile/
fallbacks in fm-backend-herdr, watcher exemptions in fm-supervision-events)
plus an isolated real-herdr idle->blocked smoke. docs/herdr-backend.md carries
the dated evidence and retires the old gap note.
* no-mistakes(review): Captain, fix Herdr disconnect handling and dedupe docs
* no-mistakes(review): Captain, commit markers after wake and reuse capability cache
* no-mistakes(review): Captain, clear stale markers and secure Herdr FIFOs
* no-mistakes(review): Captain, subscribe before Herdr reconciliation
* no-mistakes(review): Captain, make Herdr FIFO handling Bash 3.2-safe
* no-mistakes(test): Captain: include lock library in teardown fixture
* no-mistakes(document): Captain: document Herdr immediate blocked escalation
* fix: clarify shellcheck conditionals
* docs(readme): reposition firstmate as an agent distro (#473)
* feat: add deterministic bounded bearings snapshots (#475)
* feat(bearings): deterministic bearings snapshot + durable decision model
Add bin/fm-bearings-snapshot.sh: a bounded TOON-by-default projection over the
canonical fm-fleet-snapshot. Default is local-only (zero network); live open-PR
discovery and checks happen only under --include-prs, which fails soft. Every
dropped surface is marked in omitted[] with the flag that reveals it, and the
prs: line states when checks were not requested, so absence is never silent.
Fix the unresolved-decision masking bug in the canonical layer. fm-classify-lib
gains status_open_decisions, the one authoritative keyed open/resolved fold over
the whole status stream: needs-decision/blocked opens a keyed entry, only an
explicit keyed resolution (or, for run-backed tasks, run-step advancement)
closes it, so a later unrelated done/paused can no longer mask a still-open
captain decision. fm-fleet-snapshot surfaces hints.open_decisions and derives
pending_decision/blocked_event from it; the canonical schema stays complete.
Point the /bearings skill at the one command; add the resolved: writer line to
ship, scout, and secondmate briefs. Register the script and add regression
tests for the output bound, TOON/JSON parity, local-only default, opt-in PR
fetch, partial-failure degradation, decision durability, and report pointers.
* fix(bearings): completed scout report is a pointer, not a pending decision
A completed scout that raised a needs-decision and then finished (done) without
a keyed resolution falsely surfaced as an open/pending decision (the Lavish-103
case). Root cause: the open-decision reconciliation in bin/fm-fleet-snapshot.sh
cleared a stale decision only for a live run-step/pane activity read, so a
terminal task whose current state is read from the status log (a scout or ship
that reached done/failed) never cleared its stale, never-keyed-resolved
needs-decision, and it lingered as pending.
The open-decision set is still derived purely from the keyed fold - never from a
report body or decision-like prose - and reconciled against the crew lifecycle.
Extend that reconciliation so a terminal done/failed state on a single-owner
task (scout or ship), whose deliverable is its report or PR, also clears the set;
a completed scout now surfaces only as a report pointer. Secondmates are excluded
from the terminal clear (persistent, multiplexed stream), which keeps the
unrelated-event masking fix intact. Add regression tests: a completed scout with
decision-like report prose is a pointer not pending (canonical + end-to-end), and
a scout still parked at a decision stays pending so the terminal clear never
over-fires.
* no-mistakes(review): Captain, preserve keyed decisions across shared status parsing
* no-mistakes(review): Captain, close blockers and harden keyed decision parsing
* no-mistakes(review): Captain, bound GitHub enrichment without coreutils timeout
* no-mistakes(review): Captain, bound bearings sections and fail closed
* no-mistakes(review): Captain, disclose capped per-repository PR results
* no-mistakes(document): Refresh bearings documentation and status contracts
* fix(bearings): avoid ambiguous worktree guard
* fix: enforce deterministic ShellCheck parity (#481)
* fix(lint): one shellcheck owner pinned to 0.11.0 for CI/local parity
Firstmate PRs passed local no-mistakes validation but failed CI's
"Lint shell scripts" job on shellcheck findings (SC2015, SC1007, SC2034).
Two divergences caused it:
1. The no-mistakes gate had no commands.lint, so its lint step never ran
the deterministic shellcheck bin/*.sh bin/backends/*.sh tests/*.sh that
CI runs. Confirmed from state.sqlite: the lint step_result recorded
findings:null with no lint agent invocation.
2. CI's shellcheck floated with the runner image while local ran a newer
build; shellcheck retired SC2015 in 0.11.0, so an older CI shellcheck
rejected an SC2015 that the newer local one no longer emits.
Establish bin/fm-lint.sh as the single owner of the lint definition: the
file set, the config, and the pinned shellcheck version (0.11.0, printed
via --required-version). Both CI (.github/workflows/ci.yml) and the
no-mistakes gate (.no-mistakes.yaml commands.lint) invoke it; CI installs
the exact version it names and logs the resolved version, and fm-lint.sh
refuses to lint under any other version. This is not a CI relaxation: it
adopts shellcheck 0.11.0's rule set consistently, dropping only the
upstream-retired, false-positive-prone SC2015; default severity and every
still-supported finding stay enforced (no severity downgrade, no excludes).
tests/fm-lint.test.sh asserts both gates invoke the owner, that CI installs
and logs the pinned version, that the owner refuses a non-pinned shellcheck,
and that it rejects a real lint defect the old no-op gate passed.
* no-mistakes(review): Captain, harden deterministic ShellCheck parity
* no-mistakes(review): Captain, neutralize ambient ShellCheck overrides
* feat: guard primary shells from persistent cd commands (#483)
* feat: add cd-guard PreToolUse seatbelt for the primary shell
A stray persistent top-level `cd projects/<clone>` in the primary firstmate
shell relocates the shell, so a later firstmate-owned command (a backlog write,
an fm-* lifecycle call, tasks-axi) runs inside a project clone instead of the
home. The cd-guard denies exactly that command shape before it runs, across all
five verified primary harnesses, mirroring the watcher-arm PreToolUse seatbelt.
- bin/fm-cd-command-policy.mjs: sole block/allow decision owner. Reuses the
shell classifier exported from bin/fm-arm-command-policy.mjs (no duplicate
lexer; that file's CLI now runs only when invoked directly).
- bin/fm-cd-pretool-check.sh: transport, strict-superset prefilter, harness
output rendering, and primary-checkout scoping - fires in a secondmate's own
primary session, inert in crew/scout child worktrees and non-firstmate repos.
- Wired into claude, codex, grok, opencode, and pi PreToolUse-equivalents;
per-harness hooks only call the owner.
- Blocks top-level cd/pushd/popd (including cd to an absolute path, X=1 cd,
and command cd). Allows git -C, subshell / bash -c / env -C / make -C /
find -execdir, pipeline and background forms, and cd-as-data. Fails open on
malformed input; agent-mistake threat model.
- tests/fm-cd-pretool-check.test.sh: 43-case x 5-harness-entry-form matrix,
end-to-end cwd-leak regression, scoping, fail-open, prefilter, and wiring.
- docs/cd-guard.md: full contract plus live validation (claude, codex,
opencode, pi blocked end-to-end; grok live run blocked by an API balance
limit, with mechanism parity and deterministic coverage recorded).
* no-mistakes(review): Captain, fix cd-guard classification and prefilter coverage
* no-mistakes(review): Captain, allow path-qualified command wrappers
* no-mistakes(review): Captain, allow non-executing command queries
* no-mistakes(test): Captain, clarify cd-guard safe-path remediation
* docs: clarify cd guard guidance
* no-mistakes(document): Clarify cd-guard safe target guidance
* brief: add no-mistakes shared-daemon rule to ship and scout scaffolds (#267)
Crews must never stop, restart, or update the shared no-mistakes
daemon since one instance serves every firstmate lane/home; a restart
kills other lanes' in-flight pipeline runs and forces expensive
re-runs. Encodes this as a new numbered rule in both the ship-task and
scout-task brief scaffolds.
Co-authored-by: mielyemitchell <249051873+mielyemitchell@users.noreply.github.com>
* feat: make bearings concise and accurate (#485)
* feat(bearings): four-section chat contract, accurate secondmate landed, resolved-event state render
/bearings skill (one owner of the chat-response format): mandate the four
always-present chat sections - Captain's Call, Recently Landed, Underway,
Charted Next - each with an explicit empty-state sentence, no At Anchor,
materially shorter than and linking to the report file. Resolves the ambiguous
Check first / Decisions pending split into one strict captain-action section.
fm-crew-state: the log fallback derives current state only from a real
run-state verb, so a trailing decision-closing resolved: event no longer
renders a healthy idle crew (typically a secondmate) as unknown with the
resolution prose as its detail. The keyed-decision contract in
fm-classify-lib.sh is untouched; map_log_state stays the one verb->state owner.
fm-fleet-snapshot: add a bounded, read-only secondmate_landed roll-up of Done
records from registered secondmate homes, reusing the single backlog parser and
the one secondmate-home enumerator (meta home= with data/secondmates.md
fallback); no network, per-home capped.
fm-bearings-snapshot: landed now merges main-home Done with the secondmate
roll-up, bounded by a per-home cap and an overall cap with omitted[] disclosure
(also fixing the previously-silent landed truncation); --all-landed reveals the
full set.
tests: resolved-event state render, secondmate landed aggregation with caps and
omitted[] disclosure, Captain's Call anti-leak, and the four-section contract.
* no-mistakes(review): Captain, ensure bearings reveals all landed work
* no-mistakes(document): Document bearings accuracy contracts
* fix: harden away-mode daemon lifecycle (#490)
* fix: script-owned non-visible away-daemon launch + stale-artifact lifecycle
Away-mode entry left "make the daemon a tracked background terminal" to the
operator; on a pi/herdr primary that meant splitting the captain's active pane,
which visibly shrank it. Add bin/fm-afk-launch.sh, a single owner that launches
the daemon in a non-visible tracked terminal per backend (herdr dedicated
--no-focus workspace, detached tmux session), never a split, pins the captain
pane as FM_SUPERVISOR_TARGET/FM_SUPERVISOR_BACKEND, records the exact terminal
id, and tears it down or reconciles a leaked one by that id. No shell &.
Extract supervisor-pane discovery into bin/fm-supervisor-target-lib.sh, shared
with the daemon (one owner).
Fix the stale subsuper-artifact leak: clear the prior away session's delivery
cache on a fresh entry (fm_afk_clear_stale_artifacts), and stop the daemon
before clearing state/.afk so its shutdown flush runs instead of being a no-op.
Tests: tests/fm-afk-launch.test.sh (per-backend topology invariant in a lab
session, stale clear-on-entry vs refresh, exit ordering). Docs: /afk SKILL.md,
docs/herdr-backend.md (dated herdr evidence), AGENTS.md exit stub, docs/scripts.md.
* no-mistakes(review): Captain, serialize AFK launcher lifecycle safely
* no-mistakes(review): Captain, harden AFK launcher lifecycle races
* no-mistakes(review): Captain, ensure AFK daemon launch readiness
* no-mistakes(review): Captain, unify AFK lifecycle ownership and teardown
* no-mistakes(review): Captain, preserve AFK reconciliation records uniformly
* no-mistakes(review): Captain, harden AFK recovery state durability
* no-mistakes(review): Captain, harden AFK tmux ownership checks
* no-mistakes(review): Captain, simplify AFK lifecycle failure handling
* no-mistakes(review): Captain, require confirmed AFK daemon shutdown
* no-mistakes(review): Captain, confirm AFK exit by process identity
* no-mistakes(document): Align AFK launcher lifecycle documentation
* no-mistakes: apply CI fixes
* fix: prevent no-mistakes gate agents from driving the fleet (#518)
* feat: contain no-mistakes gate agents from driving the fleet
Add bin/fm-gate-refuse-lib.sh, sourced at the top of fm-spawn/fm-send/
fm-teardown before any fleet mutation. It fails closed when NO_MISTAKES_GATE
is set, and via an unspoofable git-common-dir backstop when invoked from a
no-mistakes gate worktree (.no-mistakes/repos/*.git) even with the marker
unset. A normal firstmate session has neither signal and is unaffected.
Set disable_project_settings: true in the tracked .no-mistakes.yaml so the
installed pipeline neutralizes gate agents' project instructions for this repo
(trusted-only, honored from the default branch).
firstmate's own suite runs from a gate worktree during validation, so the
shared test helpers set FM_GATE_REFUSE_BYPASS=1 to exempt it; the dedicated
tests/fm-gate-refuse.test.sh strips it to verify real refusal.
* no-mistakes(review): Captain, refuse empty no-mistakes gate markers
* no-mistakes(document): Document no-mistakes gate authority boundary
* fix: guard secondmate primary sessions from blind turn ends (#505)
* fix: guard secondmate own-home turn ends
Remove the .fm-secondmate-home early-exit in fm-turnend-guard.sh so the
'no turn ends blind' backstop fires in a secondmate's own primary session,
matching the cd-guard's scope: the own home is guarded, child crew/scout
worktrees stay exempt via the retained git-dir/git-common-dir test. This
was pure scoping from the guard's primary-only origin and guarded against
no secondmate-specific hazard.
Add secondmate regression tests (blind-turn block, idle-by-default,
stop_hook_active loop guard, deferred-death recovery loop, child-worktree
exemption) and record the autonomous background-notify re-invoke
measurement (Claude Code 2.1.207, 11s) in docs/turnend-guard.md.
* no-mistakes(document): Correct secondmate guard documentation, captain
* fix: force-include marked secondmate homes in turn-end guard
The prior remove-only form (just deleting the .fm-secondmate-home check)
left the DEFAULT secondmate topology unguarded: a treehouse-leased home is
a linked git worktree (git-dir != git-common-dir), which the retained
git-dir exemption still skipped, so its own primary session could still end
a turn blind. Invert the marker: a genuinely-marked home is force-included
as a guarded primary (treehouse-leased linked OR git-cloned plain), and the
git-dir exemption applies only to UNMARKED child worktrees. Marker
validation (regular non-symlink file, non-empty id-token content) blocks a
stray or empty marker from spoofing inclusion.
Add real linked-worktree regression tests: a treehouse-leased LINKED
secondmate home is guarded, a stray/empty marker stays exempt, and the
unmarked child worktree stays exempt - the topology the plain git-init
fixtures masked. Predicates, in-flight gate, and loop guard untouched.
* fix: force ASCII collation in secondmate marker validation
Add a function-scoped local LC_ALL=C in fm_root_is_secondmate_home so the
[A-Za-z0-9._-] id allowlist matches under C collation, not the ambient
locale - a locale-crafted non-ASCII marker id can no longer slip through
the range match and spoof force-inclusion of a linked child worktree.
Add a regression test proving a non-ASCII marker id is rejected and the
linked worktree stays exempt.
* no-mistakes(test): fix backend baseline gate-refusal dependency
* no-mistakes(document): Correct secondmate turn-end guard documentation
* fix: make bootstrap diagnostics backend-aware (#519)
* fix: make bootstrap required-tool detection backend-aware
Bootstrap demanded tmux and treehouse for every backend except orca, so a
herdr/zellij/cmux home with tmux absent was wrongly told MISSING: tmux.
Required tools now follow the resolved backend via the single-owner
fm_backend_required_tools helper (bin/fm-backend.sh): each backend's own
session-provider CLI, jq for the JSON-emitting adapters (herdr/zellij/cmux),
and treehouse for session-provider-only backends (orca owns its worktree).
The treehouse lease-support check is gated to backends that use treehouse.
Adds install hints for herdr/zellij/cmux, regression tests for the full
backend dependency matrix (herdr-without-tmux repro plus each boundary),
and updates the authoritative Toolchain docs.
* no-mistakes(review): Captain, prevent executing Herdr install guidance
* no-mistakes(review): Captain, harden backend-aware bootstrap diagnostics
* no-mistakes(review): Captain, separate manual dependency remediation
* no-mistakes(review): Captain, align bootstrap diagnostic consumers
* no-mistakes(document): Align backend adapter dependency comments
* fix: preserve follow-up platform context after inbox cleanup (#520)
* fix: recover X/Discord follow-up platform after inbox cleanup
A milestone follow-up posted directly by request_id after the inbox was
drained - and with no task link, because one persistent secondmate's single
x_request slot collides across concurrent requests - resolved platform only
from the local inbox, so a >280 Discord reply silently defaulted to the X
280-char budget and threaded as (1/2).
- fm-x-poll records a durable per-request reply context
(state/x-context/<rid>.json) at stash time, keyed by request_id so
concurrent requests never overwrite each other; it survives inbox cleanup
and restart.
- fm-x-reply resolves platform/budget through registry -> inbox -> relay
(the relay lookup confined to a live follow-up), recovering the original
platform independent of task-link availability.
- Fail-safe: a follow-up whose platform/budget cannot be authoritatively
resolved and that would split is refused (exit 8) and held for retry,
never wrongly split; fm-x-followup keeps the link on that exit.
- fm-x-dismiss clears the durable context for a dismissed mention.
Refactors reply-context extraction into a single owner and adds regression
coverage for all four cases.
* no-mistakes(review): Captain, fail closed on incomplete follow-up context
* no-mistakes(review): Captain, bound X context registry retention
* no-mistakes(review): Captain, align context retention with answer binding
* no-mistakes(document): Align X follow-up context documentation
* no-mistakes(document): Align durable X follow-up documentation
* no-mistakes(review): make cursor stop-hook install idempotent; align checkpoint fallback chain
* fix: preserve secondmate routing markers in terminal sends (#533)
* fix: preserve secondmate routing markers
* no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends
* no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift
* no-mistakes(document): Refresh Herdr marker documentation
* fix: align Grok effort handling with 0.2.99 (#527)
* fix: align grok effort docs and spawn with 0.2.99 ceiling
grok 0.2.99 accepts only low|medium|high for --reasoning-effort and
rejects both xhigh and max. Omit unsupported values on spawn, flag them
in crew-dispatch validation, and update harness-adapters.
* no-mistakes(test): Captain: refresh gotmp teardown fixture dependencies
* no-mistakes(document): Clarify Grok effort documentation ownership
* fix: derive bearings from authoritative secondmate state (#555)
* fix: make bearings use secondmate home state
* test: anonymize bearings fixtures
* no-mistakes(review): Bound parent activity evidence scans, captain
* no-mistakes(review): Preserve structured secondmate authority and bounds, captain
* no-mistakes(review): Preserve registry completeness and child inventory, captain
* no-mistakes(review): Reconcile parent evidence by verb and key, captain
* no-mistakes(review): Treat unkeyed parent evidence as inconclusive, captain
* no-mistakes(document): Document bearings local snapshot and PR opt-in
* no-mistakes(lint): Fix fleet snapshot ShellCheck findings
* no-mistakes: apply CI fixes
* fix: restore fleet snapshots on stock macOS Bash (#578)
* fix: restore stock macOS snapshot parsing
* no-mistakes(document): Clarify Linux gate and macOS CI coverage
* fix(afk): make Pi escalation and return catch-up reliable (#587)
* fix: close away-mode blocker supervision gap
* no-mistakes(review): Gate teardown retries and verify U+2063 dedupe
* no-mistakes(test): Fail closed on incomplete Pi composer separators
* no-mistakes(document): Document Pi composer recognition and return gating
* feat: support Pi max reasoning profiles (#537)
* support Pi max thinking profiles
* no-mistakes(review): Captain, allow Pi max dispatch profiles
* chore: no-mistakes(document): Clarify yolo response ownership (#595)
* Clarify validation response ownership
* no-mistakes(document): Clarify yolo response ownership
* feat: establish instruction ownership foundation (#619)
* Add instruction owners foundation
* no-mistakes(document): Refresh project-management owner pointers
* fix: compress Firstmate contract and enforce delivery rigor ownership (#626)
* docs: compress firstmate operating contract
* docs: make delivery rigor single-owner
PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion.
* no-mistakes(review): Honor configured merge authority across faster delivery paths
* no-mistakes(document): Align docs with compressed operating contract
* feat: add durable captain decision holds (#593)
* Add durable captain decision holds
* no-mistakes(review): Validate decision hold retries and origin paths
* no-mistakes(review): Enforce durable decision lifecycle boundaries
* no-mistakes(review): Harden decision display and partial retry recovery
* no-mistakes(test): Update scout teardown fixtures for decision inventory
* no-mistakes(document): Align decision lifecycle and scout teardown documentation
* no-mistakes: apply CI fixes
* no-mistakes(review): Reconcile terminal decision holds
* no-mistakes(document): Align captain decision-hold documentation
* fix(bin): harden PR check artifacts (#556)
* fix: harden PR check artifacts
* fix: close PR check migration gaps
* fix: close PR check retry gaps
* fix: clarify migration outcomes and ESM boundary
* fix: keep failed migrations authoritative
* test: use inert PR validation fixtures
* no-mistakes(review): Reserve noncanonical PR quarantine namespace
* no-mistakes(review): Prevalidate final PR-check teardown artifacts
* no-mistakes(review): Preserve X metadata and validate teardown IDs
* no-mistakes(review): Initialize migration state before watcher exclusion
* no-mistakes(review): Isolate failed poll migrations from bootstrap recovery
* no-mistakes(review): Allow safe polling during incomplete private repairs
* no-mistakes(review): Authenticate watcher checks at execution time
* no-mistakes(review): Preserve custom checks with hash-bound registration
* no-mistakes(review): Clean custom check snapshots on watcher signals
* no-mistakes(review): Stop watcher checks promptly on signals
* no-mistakes(review): Terminate watcher check groups before cleanup
* no-mistakes(document): Correct stale X-mode watcher documentation
* fix: drain returned watcher check groups
* no-mistakes(review): Harden quarantine links and recover validated replacement polls
* no-mistakes(review): Preserve X mode across shim version transitions
* no-mistakes(review): Refresh legacy X shims before marker short-circuits
* no-mistakes(document): Correct persisted PR-check artifact documentation
* no-mistakes(document): Correct stale PR-check documentation
* fix: bind PR poll repair provenance
* no-mistakes(review): Enforce single-link ownership for custom check artifacts
* no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs
* no-mistakes(review): Separate task creation and legacy teardown validation
* no-mistakes(review): Restore safe legacy operations and teardown validation
* no-mistakes(review): Disambiguate migration obligations and preserve legacy retries
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits
* no-mistakes(document): Document private poll artifact safety contracts
* no-mistakes(lint): Suppress intentional literal-dollar lint finding
* fix: migrate historical X poll identity
* fix: harden PR check artifacts
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* fix: migrate historical X poll identity
* no-mistakes(review): Harden X-mode artifact publication against symlink corruption
* no-mistakes(review): Guard X artifact publication
* no-mistakes(review): Enforce private X artifact reads
* no-mistakes(test): Fix backend compatibility fixture dependencies
* no-mistakes(document): Refresh PR-check documentation
* no-mistakes(lint): Remove unused x-mode test locals
* no-mistakes: apply CI fixes
* fix(bin): compact session-start backlog digest (#636)
* fix: compact session-start backlog digest
* no-mistakes(test): Fix legacy backend fixture helper
* no-mistakes(test): Fix watcher exit wait helper
* no-mistakes(document): Document compact backlog digest
* fix: dedupe stale watcher guard banners (#637)
* fix: dedupe stale watcher guard banner
* no-mistakes(review): Keep read-only guard state nonmutating
* no-mistakes(document): Clarify stale watcher docs
* fix(bin): balance bearings landed baseline (#640)
* fix: balance bearings landed defaults
* no-mistakes(document): Document balanced landed baseline
* no-mistakes: apply CI fixes
* fix: clarify captain-facing translation contract (#644)
* docs: clarify captain-facing translation contract
* no-mistakes(review): Restore runtime fallback mandate
* no-mistakes(document): Align Bearings translation wording
* fix(bin): make bootstrap output and nudges deterministic (#646)
* fix: make bootstrap nudges deterministic
* no-mistakes(review): Honor state override for bootstrap nudges
* no-mistakes(review): Update benign bootstrap documentation labels
* no-mistakes(review): Validate bootstrap nudge retry markers
* no-mistakes(document): Align bootstrap nudge documentation
* no-mistakes: apply CI fixes
* docs(secondmate-provisioning): clarify concise registry ownership (#649)
* Clarify concise secondmate registry contract
* no-mistakes(review): Expand secondmate registry boilerplate coverage
* no-mistakes(document): Point route docs to owner
* fix(bin): strip quoted blocked_by values during decision hold resolve (#654)
* fix(bin): strip quotes on blocked_by in decision-hold resolve
tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary
membership test only matched middle elements. Strip surrounding quotes
before matching so first and last hold ids resolve correctly.
* no-mistakes(document): Refresh decision-hold regression evidence
* feat(secondmate): inherit shared captain preferences (#656)
* feat(secondmate): inherit shared captain preferences
* no-mistakes(review): Honor shared captain data overrides
* no-mistakes(review): Honor bootstrap data override registry
* no-mistakes(document): Refresh shared inheritance docs
* no-mistakes(document): Clarify inherited local-material docs
* feat: gate local agent secret injection (#658)
* feat(spawn): gate local agent secret injection
* fix(spawn): align final Keychain slot
* no-mistakes: apply CI fixes
* test: isolate Herdr autodetect smoke sessions (#662)
* test: isolate herdr autodetect smoke session
* no-mistakes(review): Restored autodetect smoke gate bypass
* no-mistakes(test): Harden Herdr lab provisioning
* no-mistakes(document): Refresh Herdr lab docs
* docs: adopt under way for active work (#666)
* Revert "feat: gate local agent secret injection (#658)" (#668)
This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef.
* fix(pi): distinguish stale locks when arming watcher (#681)
* fix(pi): distinguish stale locks when arming watcher
* no-mistakes(test): Stabilize watcher extension async waits
* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate house vocabulary (#685)
* fix: accept secondmate as house vocabulary
* no-mistakes(test): Update captain vocabulary contract test
* no-mistakes(document): Align secondmate documentation vocabulary
* fix(bin): parse handoff homes after registry parentheticals (#686)
* fix: parse secondmate home after pre-field parentheses
Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.
* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges (#687)
* feat: add native session-start nudges
* no-mistakes(document): Document nudge script inventory
* docs: call built-in defaults the firstmate repo, not template (#688)
Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
* fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205)
* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn
Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(brief): harden fm-brief regression coverage for parse and scaffolds
Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the
Co-authored-by: Cursor <cursoragent@cursor.com>
#166 apostrophe regression cannot return unnoticed.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(bin): keep watcher supervision continuous across child cycles (#693)
* fix: make watcher supervision continuous
* no-mistakes(review): Bound watcher retries and log attached signals
* no-mistakes(review): Add bounded successor-recovery wake fallbacks
* no-mistakes(review): Prevent overlapping successor-arm retries
* no-mistakes(review): Resume supervision after late arm closes
* no-mistakes(review): Bind OpenCode recovery to attempted arm
* no-mistakes(test): Synchronize peer beacon regression fixture
* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures
* no-mistakes(document): Captain: document watcher successor protocol behavior
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: fetch current PR head for review diffs (#722)
* fix: always fetch PR head for review diffs
Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.
* no-mistakes(test): Isolate session-start nudge tests from gate state
* no-mistakes(document): Correct review-diff documentation
* docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736)
* docs: resolve five contract contradictions
* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): correct Grok exit guidance (#742)
* docs(harness): reverify grok exit command
* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for parked crew (#743)
* fix(watcher): bound stale wakes for exited paused crew
* no-mistakes(review): Gate pause suppression on confirmed agent death
* no-mistakes(test): Fixed stale pause cadence
* no-mistakes(document): Document dead-agent hold cadence
* fix(supervision): distinguish ordinary wakes from recovery (#744)
* fix(supervision): distinguish ordinary wakes from repair
* no-mistakes(review): Make passive guard follow-ups recovery-only
* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes (#745)
* fix(x-mode): dedupe pending mention wakes
* no-mistakes(review): fix x-poll claim error deduplication
* no-mistakes(review): separate claim diagnostics from relay recovery
* no-mistakes(document): Document X-mode once-only mention wakes
* feat(wake): enrich drained signals with bounded status context (#747)
* feat(wake): enrich drained signal context
* no-mistakes(review): Bound wake enrichment reads
* no-mistakes(document): Document wake-drain annotations
* docs(wake): explain at-least-once drain boundary
* no-mistakes(review): Prevent symlink races in wake annotations
* no-mistakes(review): Exercise wake symlink race regression
* test: document intentional AFK marker subprocesses
* fix(wake): isolate annotation marker state
* docs: default future planning to Markdown
* feat(herdr): add optional presentation spaces (#784)
* feat(herdr): add optional presentation spaces
* no-mistakes(review): Harden Herdr projection creation and spawn serialization
* no-mistakes(review): Captain, disarm Herdr cleanup before launch submission
* no-mistakes(test): Correct stale Orca metadata failure fixture
* no-mistakes(document): Document Herdr presentation projection accurately
* fix(send): treat opencode busy-queued composer state as submitted (#775)
* fix(send): treat opencode busy-queued composer state as submitted
When fm-send sends a message to a BUSY opencode crewmate on the tmux
backend, opencode accepts the Enter and queues the message for the next
turn, but leaves the typed text visible in the composer row. The
submit-verification loop sees a pending composer, exhausts retries, and
reports a false "Enter swallowed" failure while the message is actually
delivered.
Fix: after Enter retries are exhausted and the composer still shows
pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn,
footer shows "esc interrupt"), the harness queued the message, so
return "empty" (accepted). On an idle pane, keep returning "pending"
(genuine swallow detection preserved).
Regression tests cover four scenarios:
- busy pane + pending composer -> empty (message queued)
- idle pane + pending composer -> pending (genuine swallow)
- busy pane + composer clears on first Enter -> empty
- idle pa…
samchu8
added a commit
to SABS-Technology/firstmate
that referenced
this pull request
Jul 28, 2026
* fix(pi): distinguish stale locks when arming watcher (kunchenguid#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (kunchenguid#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (kunchenguid#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (kunchenguid#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (kunchenguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (kunchenguid#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> kunchenguid#166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (kunchenguid#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (kunchenguid#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (kunchenguid#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (kunchenguid#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (kunchenguid#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (kunchenguid#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (kunchenguid#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (kunchenguid#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * feat(herdr): add optional presentation spaces (kunchenguid#784) * feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately * fix(send): treat opencode busy-queued composer state as submitted (kunchenguid#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable * fix(spawn): require two stable reads before accepting worktree path (kunchenguid#765) * fix(spawn): require two stable reads before accepting worktree path The treehouse-get worktree-detection loop in fm-spawn.sh accepted the first pane_current_path read that differed from the project path, but on some tmux/WSL setups a brand-new window transiently reports a stale-but-real path before the pane actually settles into the worktree. Since that stale path is itself a real, distinct git checkout, it also passes validate_spawn_worktree's isolation check, so the loop silently recorded the wrong worktree in state/<id>.meta (and, for claude harness spawns, installed the turn-end hook there too). Require two consecutive polls to agree on the same non-project path before accepting it, using the existing inter-poll sleep as the confirmation gap so an already-settled pane isn't slowed down by an extra cycle. * fix(tests): drop unused CASE_DIR read in worktree-settle test ShellCheck SC2034: CASE_DIR is split out of the case record but never referenced; discard it with _ instead. --------- Co-authored-by: Freudator86 <tim@allesknut.de> * fix(bin): make watcher process identity immune to Linux wall-clock changes (kunchenguid#752) * fix(watcher): stabilize Linux process identity * no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale * fix: prevent AFK idle stalls and stale run attribution (kunchenguid#758) * fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts * fix(bin): allow safe teardown during watcher recovery (kunchenguid#750) * fix: allow safe teardown during watcher recovery * no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code * no-mistakes(document): Sync continuity-gate docs to allow teardown recovery * test: mark dynamic teardown fixture literal * no-mistakes(document): docs: add teardown to continuity gate allow list * feat(herdr): order presentation spaces while preserving focus (kunchenguid#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation * fix(bin): send literal config reread nudges after pushes (kunchenguid#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation * feat(watch): follow GitLab merge requests to merge (kunchenguid#797) * feat(watch): follow GitLab merge requests to merge The merge watch only understood GitHub pull requests, so a task whose deliverable is a GitLab merge request was never followed to merge. Generalize the stored poll identity from owner/repository to a provider-tagged provider/url/host/path/number record. GitLab runs mostly on self-hosted instances and its projects nest under groups at no fixed depth, so the host and the full project path are data in the record rather than constants, and every consumer rebuilds the URL from those parts and refuses any record that does not reconstruct it exactly. The GitLab state is read with plain glab, matching the GitHub path's use of plain gh, so an upstream checkout needs no extra tooling. Two things about glab were established by running it rather than assumed, because a wrong invocation here fails silently into a permanent "not merged": - glab has no field selector, and its JSON would need a JSON processor that firstmate does not require, so the state is read from glab's own field output. Only an exact "merged" wakes firstmate, so a changed format stays silent instead of reporting a merge. - glab cannot take a merge request URL the way gh can, because that form resolves through the current git repository and the watcher has none. It is addressed by project URL and merge request number instead. An absent glab produces no wake rather than a false merge, and arming refuses with a clear message since that is the one point where a missing CLI can still be reported. A GitLab task records no pr_head, which both consumers already treat as optional. The merge path still addresses GitHub only and refuses a merge request URL rather than sending it to the wrong forge. The record version moves to v2, and the existing non-executing migration rebuilds an already-armed watch from its recorded URL, so no watch is lost by upgrading. docs/gitlab-merge-watch.md records the evidence, taken against the public fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture. * no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation * no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs * fix(herdr): group projected children beneath owning parents (kunchenguid#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck * fix: keep local no-mistakes tests intent-targeted (kunchenguid#823) * fix(no-mistakes): drop full-suite local Test override Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a focused contract test so the override cannot silently return. * no-mistakes(lint): Make CI contract assertion ShellCheck-clean * feat: add canonical timed test runner (kunchenguid#825) * feat(test): add canonical timed suite runner and honest CI timeout Introduce bin/fm-test-run.sh as the single serial owner for selecting one script, a family, a conservative changed-file set, or the explicit complete suite, with per-script timing markers and a JSON artifact. Wire CI Behavior through the runner, raise the hang-tripwire timeout to 25 minutes, and document entry points without restoring a full-suite local no-mistakes Test command. * no-mistakes(review): Captain: fix changed selection and empty summaries * no-mistakes(review): Captain: fail closed on unmapped changed sources * no-mistakes(document): Document canonical timed test entry points * fix: surface main inventory gaps in Bearings (kunchenguid#830) * fix: disclose main-home orphan and unstructured inventory gaps Main Bearings could report an empty fleet while structured in-flight rows lacked meta or current backlog rows were free-form. Emit main_inventory from the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next gate, and keep meta as the only live Underway source. * no-mistakes(document): Document Bearings inventory-integrity projection * no-mistakes: apply CI fixes * feat: add bounded concurrent test isolation proof (kunchenguid#832) * feat: add concurrent test isolation proof for Phase 2 Prove an audited portable candidate set passes under concurrent workers with private mode-0700 temp roots, without enabling production CI sharding or fm-test-run --jobs. * no-mistakes(review): Pin isolation proof to audited candidate manifest * feat: guard against missed secondmate reports (kunchenguid#834) * feat(secondmate): parent-owned guards for missed status reports Marked parent-to-secondmate requests now create a durable pending-reply expectation with a privacy-safe correlation id before delivery. Transport success never resolves it; only a correlated parent status or document pointer does. After a completed turn with no report, the parent sends one recovery repost and escalates once if that turn is also missed, without scraping the secondmate conversation or looping. * no-mistakes(review): Deduplicate wrong-home pending-reply sightings * no-mistakes(review): Harden pending-reply recovery and escalation guards * no-mistakes(review): Bound pending-reply backend polling * no-mistakes(review): Cache pending-reply status scans * no-mistakes(review): Protect undelivered pending-reply records from scans * no-mistakes(review): Close pending-reply delivery durability gaps * no-mistakes(review): Separate pending-reply transport outcomes * no-mistakes(review): Escalate stalled pending-reply deliveries once * no-mistakes(review): Resolve attempted deliveries from correlated reports * no-mistakes(review): Resolve late reports after delivery escalation * no-mistakes(document): Document pending-reply grace and ownership * no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings * feat: require pinned real-Herdr CI coverage (kunchenguid#838) * feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat: shard portable tests and add bounded local parallelism (kunchenguid#841) * feat: shard portable CI tests after isolation proof Balance the Phase 2 proven-isolated set into two LPT portable parallel lanes from Phase 1 timing evidence, keep stateful work in a required portable serial lane, exclude real Herdr to its dedicated required lane, and prove complete inventory coverage with a deterministic guard. Add bounded local --jobs only for the proven set, per-lane timing plus aggregate artifacts, and reduce the interim portable hang tripwire now that the serial remainder owns the long wall-clock path. * no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling * no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests * no-mistakes(document): Document portable sharding and timing aggregation * no-mistakes: apply CI fixes * fix: block primary-session delegation outside the fleet (kunchenguid#854) * feat: fence primary-session delegation outside the fleet A firstmate primary that delegates through Claude Code's built-in delegation tools creates work with no state/<id>.meta. Because fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits silently at zero, such work does not merely go unsupervised: it makes the whole guard stack structurally inert, and it dies with the primary session. On 2026-07-22 that cost two workers mid-flight and left supervision down for 73 minutes unnoticed. Layer 1, the primary fix: a permissions.deny list in .claude/settings.json removes the 18 delegation, scheduling, worktree, and task-tracking tools from the model's schema, so they are never offered. This is removal rather than interception, so there is no call to intercept and no fail-open path. The list is flat and in one file so its width stays reviewable; the captain owns that width. Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open against tools that do not exist yet, and permissions.allow is a pre-approval list rather than an availability list, so there is no fail-closed allowlist to use instead. This backstop classifies the tool NAME by shape rather than against a fixed list, so a delegation tool that ships before the deny list is updated is still refused. It excludes mcp__* names and observe-or-stop operations, scopes itself to a genuine primary home via the shared fm_primary_scope_matches predicate so a crewmate's task worktree is unaffected, and offers one deliberate FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch. Verified live against Claude Code 2.1.217, including a deny-key A/B with a nonsense-name control, layer 2 denying an un-denied Workflow call, the same call allowed in a linked worktree, and the escape hatch. Corrects a prior finding: both Task and Agent work as deny keys, so both are pinned. Codex 0.144.1 verified to expose no delegation tool; grok, opencode, and pi are inspected and documented as not wired because those binaries are absent from this host and the repo requires live validation before trusting a harness hook. Evidence in docs/subagent-guard.md. * no-mistakes(review): Ship scoped Claude delegation guard * no-mistakes(test): Ship Claude delegation deny list * no-mistakes(document): Clarify PreToolUse guard ownership * no-mistakes(lint): Keep Claude deny list local * fix: install tasks-axi in portable CI shards (kunchenguid#866) Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged. * feat(bin): make dispatch profiles quota aware (kunchenguid#867) * feat: make dispatch profiles quota aware * no-mistakes(review): Fix quota window and Grok product scoping * no-mistakes(document): Document implicit quota-aware dispatch accurately * Add built-in ahoy recap skill (kunchenguid#873) * fix: preserve trustworthy Bearings data in partial snapshots (kunchenguid#875) * fix: preserve mixed Bearings projections * no-mistakes(review): Enforce strict invalidity precedence for partial snapshots * no-mistakes(review): Enforce ownership for unknown child metadata * no-mistakes(document): Document partial structured Bearings projections * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat(pi): add session-local calm mode (kunchenguid#884) * Add session-local Pi calm mode * no-mistakes(review): Preserve Pi HTML exports during calm mode * no-mistakes(review): Preserve calm exports across submit bindings and share * no-mistakes(document): Document calm-mode feasibility across supported harnesses * fix(pi): prevent redundant watcher re-arms (kunchenguid#885) * fix(pi): limit watcher arm tool to recovery * no-mistakes(review): Strengthen Pi live re-arm regression coverage * no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming * fix(pi): clean up Calm transcript rendering (kunchenguid#895) * fix(pi): clean up Calm transcript rendering * no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs * no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations * no-mistakes(review): Restore Calm rows received while active * no-mistakes(review): Preserve diagnostics during Calm restoration * no-mistakes(document): Clarify Calm transcript behavior and injection paths * fix: execute every PR body compliance event (kunchenguid#898) * fix: execute every PR body compliance event * no-mistakes(document): Document independent PR compliance events * fix: exclude operational injections from ahoy boundaries (kunchenguid#899) * fix: distinguish operational input in ahoy * no-mistakes(review): Handle legacy Ahoy operational boundaries * no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions * no-mistakes(document): Document Ahoy operational marker ownership * no-mistakes(lint): Suppress intentional literal fixture lint warnings * fix: canonically classify operational inputs across harnesses (kunchenguid#909) * fix: type canonical operational inputs * no-mistakes(document): Correct canonical operational-input documentation ownership * fix: avoid generic secondmate start acknowledgements (kunchenguid#926) * fix: avoid generic secondmate acknowledgements * no-mistakes(document): Document sparse secondmate acknowledgement behavior * no-mistakes: apply CI fixes --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Johans Ballestar <47162770+Ballestar@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com> Co-authored-by: Kostadin Pop-Kochev <kostadin.popkocev@gmail.com> Co-authored-by: Freudator86 <94322668+Freudator86@users.noreply.github.com> Co-authored-by: Freudator86 <tim@allesknut.de> Co-authored-by: vvizlan <steve.rule.wilson@gmail.com> Co-authored-by: jjames27th-eng <jjames27th@gmail.com> Co-authored-by: nithingm <nithingm31@gmail.com> Co-authored-by: Christopher McKay <101884182+karotkriss@users.noreply.github.com> Co-authored-by: ItsFlow <florian.eberhart.z@gmail.com>
purple-phoenix
added a commit
to purple-phoenix/firstmate
that referenced
this pull request
Jul 29, 2026
* fix(pi): distinguish stale locks when arming watcher (kunchenguid#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (kunchenguid#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (kunchenguid#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (kunchenguid#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (kunchenguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (kunchenguid#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> kunchenguid#166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (kunchenguid#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (kunchenguid#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (kunchenguid#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (kunchenguid#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (kunchenguid#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (kunchenguid#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (kunchenguid#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (kunchenguid#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * feat(herdr): add optional presentation spaces (kunchenguid#784) * feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately * fix(send): treat opencode busy-queued composer state as submitted (kunchenguid#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable * fix(spawn): require two stable reads before accepting worktree path (kunchenguid#765) * fix(spawn): require two stable reads before accepting worktree path The treehouse-get worktree-detection loop in fm-spawn.sh accepted the first pane_current_path read that differed from the project path, but on some tmux/WSL setups a brand-new window transiently reports a stale-but-real path before the pane actually settles into the worktree. Since that stale path is itself a real, distinct git checkout, it also passes validate_spawn_worktree's isolation check, so the loop silently recorded the wrong worktree in state/<id>.meta (and, for claude harness spawns, installed the turn-end hook there too). Require two consecutive polls to agree on the same non-project path before accepting it, using the existing inter-poll sleep as the confirmation gap so an already-settled pane isn't slowed down by an extra cycle. * fix(tests): drop unused CASE_DIR read in worktree-settle test ShellCheck SC2034: CASE_DIR is split out of the case record but never referenced; discard it with _ instead. --------- Co-authored-by: Freudator86 <tim@allesknut.de> * fix(bin): make watcher process identity immune to Linux wall-clock changes (kunchenguid#752) * fix(watcher): stabilize Linux process identity * no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale * fix: prevent AFK idle stalls and stale run attribution (kunchenguid#758) * fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts * fix(bin): allow safe teardown during watcher recovery (kunchenguid#750) * fix: allow safe teardown during watcher recovery * no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code * no-mistakes(document): Sync continuity-gate docs to allow teardown recovery * test: mark dynamic teardown fixture literal * no-mistakes(document): docs: add teardown to continuity gate allow list * feat(herdr): order presentation spaces while preserving focus (kunchenguid#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation * fix(bin): send literal config reread nudges after pushes (kunchenguid#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation * feat(watch): follow GitLab merge requests to merge (kunchenguid#797) * feat(watch): follow GitLab merge requests to merge The merge watch only understood GitHub pull requests, so a task whose deliverable is a GitLab merge request was never followed to merge. Generalize the stored poll identity from owner/repository to a provider-tagged provider/url/host/path/number record. GitLab runs mostly on self-hosted instances and its projects nest under groups at no fixed depth, so the host and the full project path are data in the record rather than constants, and every consumer rebuilds the URL from those parts and refuses any record that does not reconstruct it exactly. The GitLab state is read with plain glab, matching the GitHub path's use of plain gh, so an upstream checkout needs no extra tooling. Two things about glab were established by running it rather than assumed, because a wrong invocation here fails silently into a permanent "not merged": - glab has no field selector, and its JSON would need a JSON processor that firstmate does not require, so the state is read from glab's own field output. Only an exact "merged" wakes firstmate, so a changed format stays silent instead of reporting a merge. - glab cannot take a merge request URL the way gh can, because that form resolves through the current git repository and the watcher has none. It is addressed by project URL and merge request number instead. An absent glab produces no wake rather than a false merge, and arming refuses with a clear message since that is the one point where a missing CLI can still be reported. A GitLab task records no pr_head, which both consumers already treat as optional. The merge path still addresses GitHub only and refuses a merge request URL rather than sending it to the wrong forge. The record version moves to v2, and the existing non-executing migration rebuilds an already-armed watch from its recorded URL, so no watch is lost by upgrading. docs/gitlab-merge-watch.md records the evidence, taken against the public fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture. * no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation * no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs * fix(herdr): group projected children beneath owning parents (kunchenguid#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck * fix: keep local no-mistakes tests intent-targeted (kunchenguid#823) * fix(no-mistakes): drop full-suite local Test override Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a focused contract test so the override cannot silently return. * no-mistakes(lint): Make CI contract assertion ShellCheck-clean * feat: add canonical timed test runner (kunchenguid#825) * feat(test): add canonical timed suite runner and honest CI timeout Introduce bin/fm-test-run.sh as the single serial owner for selecting one script, a family, a conservative changed-file set, or the explicit complete suite, with per-script timing markers and a JSON artifact. Wire CI Behavior through the runner, raise the hang-tripwire timeout to 25 minutes, and document entry points without restoring a full-suite local no-mistakes Test command. * no-mistakes(review): Captain: fix changed selection and empty summaries * no-mistakes(review): Captain: fail closed on unmapped changed sources * no-mistakes(document): Document canonical timed test entry points * fix: surface main inventory gaps in Bearings (kunchenguid#830) * fix: disclose main-home orphan and unstructured inventory gaps Main Bearings could report an empty fleet while structured in-flight rows lacked meta or current backlog rows were free-form. Emit main_inventory from the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next gate, and keep meta as the only live Underway source. * no-mistakes(document): Document Bearings inventory-integrity projection * no-mistakes: apply CI fixes * feat: add bounded concurrent test isolation proof (kunchenguid#832) * feat: add concurrent test isolation proof for Phase 2 Prove an audited portable candidate set passes under concurrent workers with private mode-0700 temp roots, without enabling production CI sharding or fm-test-run --jobs. * no-mistakes(review): Pin isolation proof to audited candidate manifest * feat: guard against missed secondmate reports (kunchenguid#834) * feat(secondmate): parent-owned guards for missed status reports Marked parent-to-secondmate requests now create a durable pending-reply expectation with a privacy-safe correlation id before delivery. Transport success never resolves it; only a correlated parent status or document pointer does. After a completed turn with no report, the parent sends one recovery repost and escalates once if that turn is also missed, without scraping the secondmate conversation or looping. * no-mistakes(review): Deduplicate wrong-home pending-reply sightings * no-mistakes(review): Harden pending-reply recovery and escalation guards * no-mistakes(review): Bound pending-reply backend polling * no-mistakes(review): Cache pending-reply status scans * no-mistakes(review): Protect undelivered pending-reply records from scans * no-mistakes(review): Close pending-reply delivery durability gaps * no-mistakes(review): Separate pending-reply transport outcomes * no-mistakes(review): Escalate stalled pending-reply deliveries once * no-mistakes(review): Resolve attempted deliveries from correlated reports * no-mistakes(review): Resolve late reports after delivery escalation * no-mistakes(document): Document pending-reply grace and ownership * no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings * feat: require pinned real-Herdr CI coverage (kunchenguid#838) * feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat: shard portable tests and add bounded local parallelism (kunchenguid#841) * feat: shard portable CI tests after isolation proof Balance the Phase 2 proven-isolated set into two LPT portable parallel lanes from Phase 1 timing evidence, keep stateful work in a required portable serial lane, exclude real Herdr to its dedicated required lane, and prove complete inventory coverage with a deterministic guard. Add bounded local --jobs only for the proven set, per-lane timing plus aggregate artifacts, and reduce the interim portable hang tripwire now that the serial remainder owns the long wall-clock path. * no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling * no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests * no-mistakes(document): Document portable sharding and timing aggregation * no-mistakes: apply CI fixes * fix: block primary-session delegation outside the fleet (kunchenguid#854) * feat: fence primary-session delegation outside the fleet A firstmate primary that delegates through Claude Code's built-in delegation tools creates work with no state/<id>.meta. Because fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits silently at zero, such work does not merely go unsupervised: it makes the whole guard stack structurally inert, and it dies with the primary session. On 2026-07-22 that cost two workers mid-flight and left supervision down for 73 minutes unnoticed. Layer 1, the primary fix: a permissions.deny list in .claude/settings.json removes the 18 delegation, scheduling, worktree, and task-tracking tools from the model's schema, so they are never offered. This is removal rather than interception, so there is no call to intercept and no fail-open path. The list is flat and in one file so its width stays reviewable; the captain owns that width. Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open against tools that do not exist yet, and permissions.allow is a pre-approval list rather than an availability list, so there is no fail-closed allowlist to use instead. This backstop classifies the tool NAME by shape rather than against a fixed list, so a delegation tool that ships before the deny list is updated is still refused. It excludes mcp__* names and observe-or-stop operations, scopes itself to a genuine primary home via the shared fm_primary_scope_matches predicate so a crewmate's task worktree is unaffected, and offers one deliberate FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch. Verified live against Claude Code 2.1.217, including a deny-key A/B with a nonsense-name control, layer 2 denying an un-denied Workflow call, the same call allowed in a linked worktree, and the escape hatch. Corrects a prior finding: both Task and Agent work as deny keys, so both are pinned. Codex 0.144.1 verified to expose no delegation tool; grok, opencode, and pi are inspected and documented as not wired because those binaries are absent from this host and the repo requires live validation before trusting a harness hook. Evidence in docs/subagent-guard.md. * no-mistakes(review): Ship scoped Claude delegation guard * no-mistakes(test): Ship Claude delegation deny list * no-mistakes(document): Clarify PreToolUse guard ownership * no-mistakes(lint): Keep Claude deny list local * fix: install tasks-axi in portable CI shards (kunchenguid#866) Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged. * feat(bin): make dispatch profiles quota aware (kunchenguid#867) * feat: make dispatch profiles quota aware * no-mistakes(review): Fix quota window and Grok product scoping * no-mistakes(document): Document implicit quota-aware dispatch accurately * Add built-in ahoy recap skill (kunchenguid#873) * fix: preserve trustworthy Bearings data in partial snapshots (kunchenguid#875) * fix: preserve mixed Bearings projections * no-mistakes(review): Enforce strict invalidity precedence for partial snapshots * no-mistakes(review): Enforce ownership for unknown child metadata * no-mistakes(document): Document partial structured Bearings projections * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat(pi): add session-local calm mode (kunchenguid#884) * Add session-local Pi calm mode * no-mistakes(review): Preserve Pi HTML exports during calm mode * no-mistakes(review): Preserve calm exports across submit bindings and share * no-mistakes(document): Document calm-mode feasibility across supported harnesses * fix(pi): prevent redundant watcher re-arms (kunchenguid#885) * fix(pi): limit watcher arm tool to recovery * no-mistakes(review): Strengthen Pi live re-arm regression coverage * no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming * fix(pi): clean up Calm transcript rendering (kunchenguid#895) * fix(pi): clean up Calm transcript rendering * no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs * no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations * no-mistakes(review): Restore Calm rows received while active * no-mistakes(review): Preserve diagnostics during Calm restoration * no-mistakes(document): Clarify Calm transcript behavior and injection paths * fix: execute every PR body compliance event (kunchenguid#898) * fix: execute every PR body compliance event * no-mistakes(document): Document independent PR compliance events * fix: exclude operational injections from ahoy boundaries (kunchenguid#899) * fix: distinguish operational input in ahoy * no-mistakes(review): Handle legacy Ahoy operational boundaries * no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions * no-mistakes(document): Document Ahoy operational marker ownership * no-mistakes(lint): Suppress intentional literal fixture lint warnings * fix: canonically classify operational inputs across harnesses (kunchenguid#909) * fix: type canonical operational inputs * no-mistakes(document): Correct canonical operational-input documentation ownership * fix: avoid generic secondmate start acknowledgements (kunchenguid#926) * fix: avoid generic secondmate acknowledgements * no-mistakes(document): Document sparse secondmate acknowledgement behavior * no-mistakes: apply CI fixes * fix(pi): make calm mode persistent and gapless (kunchenguid#927) * fix(pi): preserve calm presentation across sessions * no-mistakes(review): Fix Calm home fallback persistence * no-mistakes(document): Clarify Calm gapless and export contracts * no-mistakes: apply CI fixes * fix(watch): retire merged PR polls after durable notification (kunchenguid#932) * fix: retire merged PR polls after notification * no-mistakes(review): Decouple PR retirement recovery from template updates * no-mistakes(review): Recover pending PR retirements before poll migration * no-mistakes(document): Document merged PR poll retirement contracts * fix: refine scout intake and parallel dispatch (kunchenguid#934) * Clarify intake evidence and overlap handling * no-mistakes(review): Align scout guard with intake classification * no-mistakes(document): Clarify scout documentation and intake ownership * fix(pi): prevent duplicate assistant replies in Calm (kunchenguid#936) * fix(pi): preserve operational follow-up semantics in Calm * no-mistakes(document): Correct Calm operational-row visibility documentation * perf(bin): shrink the ShellCheck source graph (kunchenguid#939) * perf(lint): shrink shell source graph * no-mistakes(review): Ensure lint workers terminate fully on cancellation * no-mistakes(document): Repair stale lint documentation ownership * fix(pi): remove Calm hidden-block gaps (kunchenguid#942) * fix(pi): remove Calm hidden-block gaps * no-mistakes(review): Validate Calm geometry against current viewport * no-mistakes(review): Synchronize Calm geometry checks with reload completion * fix: enforce contract boundaries for ask-user findings (kunchenguid#945) * fix: escalate ask-user contract expansion * no-mistakes(document): Point project management to authority owner * docs: prefer direct operational paths (kunchenguid#946) * fix(pi): hide operational user rows in Calm mode (kunchenguid#948) * fix(pi): hide Calm operational user rows * no-mistakes(review): Narrow Calm operational input suppression * no-mistakes(review): Avoid Calm replay classifier subprocesses * no-mistakes(document): docs: point Pi verification to Calm owner * fix: relaunch missing second mates at session start (kunchenguid#950) * fix(session-start): relaunch missing second mates * fix(test): detect completed parallel workers * no-mistakes(review): Isolate session-start recovery test cleanup * no-mistakes(review): Complete backend-safe secondmate session recovery * no-mistakes(review): Resolve Zellij task ownership before recovery * no-mistakes(review): Recover relocated Zellij ghost tabs safely * no-mistakes(review): Restore conservative Zellij recovery boundary * no-mistakes(review): Reject malformed tmux recovery targets * no-mistakes(document): Align secondmate recovery documentation * no-mistakes: apply CI fixes * fix(herdr): reclaim resumed task projections after restart (kunchenguid#967) * fix(herdr): reclaim resumed task projections safely * no-mistakes(review): Enforce safe Herdr reclaim close boundaries * no-mistakes(document): docs: clarify Herdr restart projection contract * Teach Ahoy to surface open decisions (kunchenguid#968) * Require shipshape routine acknowledgement (kunchenguid#969) * docs: separate current guidance from verification evidence (kunchenguid#994) * docs: separate current guides from verification * no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence * fix: preserve Claude watcher continuity across Stop hooks (kunchenguid#997) * feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm Claude primaries (main home and marked secondmate homes) no longer depend on the model remembering to re-arm the watcher after each wake. A tracked Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s) fires on every turn end, claims one home-scoped single-flight owner, foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and translates an actionable close or typed watcher failure into exactly one exit-2 rewake. The hook scopes to genuine primary checkouts, requires the session lock to be held by its own harness ancestor, stays inert while AFK owns triage or the home is idle, and hands AFK transitions mid-cycle to the daemon without rewaking. The synchronous turn-end guard gains a --claude cooperative mode: it ignores stop_hook_active (true on every post-continuation stop, which is what re-opened the 2026-07-21 blind window), waits briefly for a watcher health proof, a live auto-arm owner claim, or a fresh rewake epoch, and re-blocks only when the auto-arm genuinely failed to establish - bounded to 3 consecutive blocks per session, safely below Claude Code's 8-block override, then a degraded allow with a visible systemMessage. Codex keeps the previous one-block loop guard byte-identically, and Pi, OpenCode, and Grok adapters are untouched. Continuity PreToolUse gate and durable wake queue are preserved; the gate's recovery guidance now names the Stop-owned re-arm and reserves manual background arms for auto-arm failure. Claude supervision protocol, harness-adapters facts, architecture, configuration, and continuity docs updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218 contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout process-group kill, 8-block cap, interactive non-stall) and the 2.1.219 product live E2Es. Regression matrix: hermetic tests cover scope, identity, AFK, need, single-flight, translation, guard cooperation, budget, and registration; the new live E2E proves two full tokenless auto-arm rewake cycles with zero model arm commands; Pi and OpenCode Option B live E2Es pass unchanged. * no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop * no-mistakes(review): Remove unsupported Claude contract-lab verification claims * no-mistakes(document): Update Claude auto-arm continuity documentation * fix(herdr): clean stale projections at session start (kunchenguid#996) * Clean stale Herdr projections at session start * no-mistakes(document): Document stale Herdr session-start projection cleanup * no-mistakes(review): Enforce locked exact Herdr projection cleanup * no-mistakes(review): Fail closed on unverified session lock ownership * no-mistakes(review): Serialize session lock acquisition atomically * no-mistakes(document): Align session-start and Herdr cleanup documentation * no-mistakes(document): Generalize lock-refusal diagnostics * no-mistakes(lint): Avoid reserved keyword in concurrency test * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: recover Claude supervision without watcher-status gate (kunchenguid#1001) * fix: recover Claude supervision at session start * fix: remove Claude watcher-status command gate * no-mistakes(document): docs: remove stale continuity gate references * fix: make quota-aware profile selection agent-owned (kunchenguid#1018) * Replace quota dispatch selector instructions * no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection * fix(bin): remove vestigial dispatch selector (kunchenguid#1026) * remove vestigial dispatch selector * no-mistakes(review): Synchronize isolation proof and portable shard evidence * no-mistakes(review): Correct shard history and proof archive date * no-mistakes(review): Remove reintroduced selector documentation reference * no-mistakes(document): Remove stale dispatch strategy documentation * docs(agents): drop superseded interim quota-window rule (kunchenguid#1039) quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per provider, so the successor named in the interim rule has landed and the rule's own removal condition is satisfied. Keep the ownership clause so quota-axi remains the single owner of how model or product windows relate to bounding account windows, and drop the interim weakest-headroom instruction. The unknown-semantics case is already covered by the existing requirement to stop and report a candidate whose applicable quota data or interpretation cannot be established. Drop the matching assertion phrase from tests/fm-instruction-owners.test.sh; the retained ownership phrase still asserts. * fix(tmux): scope busy detection and recognize current Claude turns (kunchenguid#1049) * fix(tmux): scope Claude busy detection by harness * no-mistakes(review): Separate verified and fallback busy signatures * no-mistakes(test): Scope busy signatures to supplied harnesses * no-mistakes(document): Document harness-scoped busy detection * feat: add verified Kimi crewmate adapter (kunchenguid#1047) * Add verified Kimi crewmate harness adapter * no-mistakes(review): Scope Kimi moon detection to spinner lines * no-mistakes(review): Match only complete Kimi spinner rows * no-mistakes(review): Resolve Kimi binary portably before pane creation * no-mistakes(document): Align Kimi adapter documentation * no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override * Fix Kimi busy spinner detection * no-mistakes(review): Recognize Kimi session-lock ancestry and holders * no-mistakes(review): Scope pending-reply Kimi busy detection by harness * no-mistakes(document): Correct Kimi spinner capture documentation * no-mistakes(document): Clarify optional Kimi spinner whitespace * no-mistakes(lint): Silence intentional pending-reply test stub warnings * test: align rebased Kimi busy fixtures * no-mistakes: apply CI fixes * Reconcile Kimi busy detection after per-harness scoping * no-mistakes(review): Clarify observed Kimi spinner whitespace contract * no-mistakes(document): Clarify Kimi harness documentation * fix: harden Kimi submission and spinner matching (kunchenguid#1058) * fix kimi pointer submission and spinner conformance * no-mistakes(review): Preserve Kimi submit target ownership guard * feat(bin): add guarded Kimi turn-end wake (kunchenguid#1059) * Add guarded Kimi turn-end hook * no-mistakes(review): Require jq before installing Kimi turn-end hook * no-mistakes(review): Expose jq inside isolated Kimi test fixtures * no-mistakes(review): Preserve Kimi config boundaries during hook removal * no-mistakes(review): Document Kimi removal newline safeguard * no-mistakes(document): Document Kimi shared-home preservation * fix(tmux): classify bordered composers across all rows (kunchenguid#1066) * Fix structural tmux composer reading * Verify Calm compatibility with Pi 0.82 * no-mistakes(review): Harden structural composer classification boundaries * no-mistakes(review): Refresh composer and Kimi regression fixtures * no-mistakes(review): Fail closed on unbounded composer edges * no-mistakes(review): Enforce aligned composer geometry safely * no-mistakes(review): Make composer ambiguity locale-safe * no-mistakes(review): Preserve ambiguity through composer submission * no-mistakes(review): Carry composer proof through retries * no-mistakes(document): Document structural tmux composer delivery guarantees * no-mistakes: apply CI fixes * feat(bin): add verified pi-signed runtime adapter (kunchenguid#1145) * feat: add verified pi-signed adapter * no-mistakes(review): Correct pi-signed maintainer verification date * no-mistakes(review): Correct remaining pi-signed verification dates * no-mistakes(review): Preserve authoritative pi-signed runtime identity * no-mistakes(document): Document pi-signed shared adapter semantics * no-mistakes: apply CI fixes * fix(pi): rearm watcher across session transitions (kunchenguid#1166) * fix(pi): rearm watcher across same-process session transitions Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement as well as terminal quit. The primary watcher extension latched a module-level stopping flag on every shutdown, so a replacement session in the same process could not arm monitoring until Pi restarted. Own arm authority per session generation so only the active live generation may start, stop, or rearm the child. Replacement sessions can arm again without restarting Pi, stale prior-generation callbacks cannot mutate the active cycle, and real quit still blocks late rearm. * no-mistakes(review): Preserve Pi generation isolation and exit cleanup * no-mistakes(document): Correct Pi watcher transition documentation * feat: route crew dispatch using quota-window pace (kunchenguid#1172) * Consume quota-axi pace signals in dispatch profile array selection. Add quota-array-dispatch as the single owner of the pace-aware candidate choice, keep AGENTS.md to the intake boundary and load trigger, and cover the acceptance cases with sanitized schemaVersion 3 fixtures. * no-mistakes(review): Stop and report genuine quota dispatch ties * no-mistakes(document): Document quota pace freshness and uncertainty * fix(brief): keep Definition-of-done heredocs parseable under stock Bash 3.2 Move each delivery mode's Definition-of-done text into its own function body instead of an inline DOD=$(cat <<EOF ... EOF) assignment. Stock macOS Bash 3.2 tracks quote state through a heredoc body while it scans for the closing paren of a command substitution, so a single apostrophe in that body makes the entire script unparseable - fm-brief.sh could not generate any brief on macOS. A heredoc in a plain function body is parsed normally, so this removes the bug class rather than avoiding apostrophes in the prose, and the upstream wording that tests/fm-ask-user-authority.test.sh pins is restored verbatim. * fix(spawn): fail closed when task metadata cannot be recorded The metadata write used a bare redirect, and fm-spawn.sh runs under set -u without set -e, so a failed write was ignored: the script went on to print 'spawned <id> ...' and exit 0 with no state/<id>.meta on disk. That durable record is what makes a worker supervisable - the watcher, recovery, and teardown all locate a task through it - so a successful-looking spawn left a live worker that nothing was tracking. Stop instead; the existing abort cleanup still owns backend teardown. tests/fm-backend-orca.test.sh already asserted this and was failing. * fix(tests): settle merged-tree invariants and a Bash 3.2 concurrency fixture Three merge-integration fixes and one inherited upstream defect. Merge integration: - Upstream's source-graph boundary (kunchenguid#939) pins which tests may carry production shellcheck context. This fork's two task-id tests sourced bin/fm-pr-lib.sh with a followed directive purely for validator access; both already disabled SC1091, so the directive only widened the graph. Switched to the non-following form and said why inline. - Upstream's documentation-audience inventory did not classify this fork's capacity and user-journey-audit skills, which upstream never had. Both are agent-runtime, matching every other .agents/skills entry. Inherited defect: - tests/fm-session-start.test.sh read $BASHPID in each racer subshell. BASHPID arrived in Bash 4.0, so under stock macOS Bash 3.2 with set -u every racer aborted and the exactly-one-winner assertion always saw zero. The fallback execs sh in the substitution subshell so its PPID is that racer's own pid; $$ would report the shared parent and defeat the race the test exists to prove. * fix(watcher): reap the arm's child by blocking wait, not a fixed poll The signal path polled for up to 2s before escalating to SIGKILL, on top of the ledger-lock wait and the successor check. The HUP regression has an 8s budget, so under a loaded parallel suite the arm could miss it and the test saw a timeout instead of exit 129. Block on the owned child instead: it returns the moment the child dies, and SIGKILL stays as the backstop for a child that ignores TERM outright. This keeps the property the poll was added for - the exact child is fully reaped before any successor check, so a still-fresh dying child cannot read as a healthy successor and suppress the arm-death alarm - while removing the fixed delay. Verified with six concurrent runs of tests/fm-watcher-lock.test.sh, the load that exposed it: 29/29 green in every run. * fix(watcher): bound the TERM grace so a deferred trap cannot stall arm exit Measured HUP-to-exit latency was 5-6s against the regression's 8s budget, because the blocking wait sat through a whole FM_POLL interval: Bash defers the watcher's TERM trap until its poll sleep returns. Give TERM a 1s grace, then SIGKILL, then block to reap. The blocking wait still guarantees the exact owned child is fully reaped before any successor check, so a still-fresh dying child cannot read as a healthy successor and suppress the arm-death alarm; the bound just stops a deferred trap from dominating shutdown. Measured after the change: 1-2s across five runs, a 4-8x margin on the budget. This replaces the previous commit's unbounded wait, which traded the original fixed 2s poll for a stall of up to one poll interval - slower, not faster. * docs(audiences): classify the dashboard-service doc PR #8 added docs/dashboard-service.md, which upstream's documentation-audience inventory did not know about, so the merged tree failed its own completeness check. The doc states that it owns the architecture narrative, trust design, and verification evidence while pointing at other owners for mechanics, which is the maintainer-architecture audience rather than operator-current. * no-mistakes(review): Publish spawn metadata atomically and correct cleanup scope * no-mistakes(test): Captain: restore spawn metadata publication invariants * no-mistakes(document): Refresh merged toolbelt and harness documentation * no-mistakes: apply CI fixes --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Johans Ballestar <47162770+Ballestar@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com> Co-authored-by: Kostadin Pop-Kochev <kostadin.popkocev@gmail.com> Co-authored-by: Freudator86 <94322668+Freudator86@users.noreply.github.com> Co-authored-by: Freudator86 <tim@allesknut.de> Co-authored-by: vvizlan <steve.rule.wilson@gmail.com> Co-authored-by: jjames27th-eng <jjames27th@gmail.com> Co-authored-by: nithingm <nithingm31@gmail.com> Co-authored-by: Christopher McKay <101884182+karotkriss@users.noreply.github.com> Co-authored-by: ItsFlow <florian.eberhart.z@gmail.com>
allstargg
added a commit
to allstargg/firstmate
that referenced
this pull request
Jul 30, 2026
* fix: prevent no-mistakes gate agents from driving the fleet (#518)
* feat: contain no-mistakes gate agents from driving the fleet
Add bin/fm-gate-refuse-lib.sh, sourced at the top of fm-spawn/fm-send/
fm-teardown before any fleet mutation. It fails closed when NO_MISTAKES_GATE
is set, and via an unspoofable git-common-dir backstop when invoked from a
no-mistakes gate worktree (.no-mistakes/repos/*.git) even with the marker
unset. A normal firstmate session has neither signal and is unaffected.
Set disable_project_settings: true in the tracked .no-mistakes.yaml so the
installed pipeline neutralizes gate agents' project instructions for this repo
(trusted-only, honored from the default branch).
firstmate's own suite runs from a gate worktree during validation, so the
shared test helpers set FM_GATE_REFUSE_BYPASS=1 to exempt it; the dedicated
tests/fm-gate-refuse.test.sh strips it to verify real refusal.
* no-mistakes(review): Captain, refuse empty no-mistakes gate markers
* no-mistakes(document): Document no-mistakes gate authority boundary
* fix: guard secondmate primary sessions from blind turn ends (#505)
* fix: guard secondmate own-home turn ends
Remove the .fm-secondmate-home early-exit in fm-turnend-guard.sh so the
'no turn ends blind' backstop fires in a secondmate's own primary session,
matching the cd-guard's scope: the own home is guarded, child crew/scout
worktrees stay exempt via the retained git-dir/git-common-dir test. This
was pure scoping from the guard's primary-only origin and guarded against
no secondmate-specific hazard.
Add secondmate regression tests (blind-turn block, idle-by-default,
stop_hook_active loop guard, deferred-death recovery loop, child-worktree
exemption) and record the autonomous background-notify re-invoke
measurement (Claude Code 2.1.207, 11s) in docs/turnend-guard.md.
* no-mistakes(document): Correct secondmate guard documentation, captain
* fix: force-include marked secondmate homes in turn-end guard
The prior remove-only form (just deleting the .fm-secondmate-home check)
left the DEFAULT secondmate topology unguarded: a treehouse-leased home is
a linked git worktree (git-dir != git-common-dir), which the retained
git-dir exemption still skipped, so its own primary session could still end
a turn blind. Invert the marker: a genuinely-marked home is force-included
as a guarded primary (treehouse-leased linked OR git-cloned plain), and the
git-dir exemption applies only to UNMARKED child worktrees. Marker
validation (regular non-symlink file, non-empty id-token content) blocks a
stray or empty marker from spoofing inclusion.
Add real linked-worktree regression tests: a treehouse-leased LINKED
secondmate home is guarded, a stray/empty marker stays exempt, and the
unmarked child worktree stays exempt - the topology the plain git-init
fixtures masked. Predicates, in-flight gate, and loop guard untouched.
* fix: force ASCII collation in secondmate marker validation
Add a function-scoped local LC_ALL=C in fm_root_is_secondmate_home so the
[A-Za-z0-9._-] id allowlist matches under C collation, not the ambient
locale - a locale-crafted non-ASCII marker id can no longer slip through
the range match and spoof force-inclusion of a linked child worktree.
Add a regression test proving a non-ASCII marker id is rejected and the
linked worktree stays exempt.
* no-mistakes(test): fix backend baseline gate-refusal dependency
* no-mistakes(document): Correct secondmate turn-end guard documentation
* fix: make bootstrap diagnostics backend-aware (#519)
* fix: make bootstrap required-tool detection backend-aware
Bootstrap demanded tmux and treehouse for every backend except orca, so a
herdr/zellij/cmux home with tmux absent was wrongly told MISSING: tmux.
Required tools now follow the resolved backend via the single-owner
fm_backend_required_tools helper (bin/fm-backend.sh): each backend's own
session-provider CLI, jq for the JSON-emitting adapters (herdr/zellij/cmux),
and treehouse for session-provider-only backends (orca owns its worktree).
The treehouse lease-support check is gated to backends that use treehouse.
Adds install hints for herdr/zellij/cmux, regression tests for the full
backend dependency matrix (herdr-without-tmux repro plus each boundary),
and updates the authoritative Toolchain docs.
* no-mistakes(review): Captain, prevent executing Herdr install guidance
* no-mistakes(review): Captain, harden backend-aware bootstrap diagnostics
* no-mistakes(review): Captain, separate manual dependency remediation
* no-mistakes(review): Captain, align bootstrap diagnostic consumers
* no-mistakes(document): Align backend adapter dependency comments
* fix: preserve follow-up platform context after inbox cleanup (#520)
* fix: recover X/Discord follow-up platform after inbox cleanup
A milestone follow-up posted directly by request_id after the inbox was
drained - and with no task link, because one persistent secondmate's single
x_request slot collides across concurrent requests - resolved platform only
from the local inbox, so a >280 Discord reply silently defaulted to the X
280-char budget and threaded as (1/2).
- fm-x-poll records a durable per-request reply context
(state/x-context/<rid>.json) at stash time, keyed by request_id so
concurrent requests never overwrite each other; it survives inbox cleanup
and restart.
- fm-x-reply resolves platform/budget through registry -> inbox -> relay
(the relay lookup confined to a live follow-up), recovering the original
platform independent of task-link availability.
- Fail-safe: a follow-up whose platform/budget cannot be authoritatively
resolved and that would split is refused (exit 8) and held for retry,
never wrongly split; fm-x-followup keeps the link on that exit.
- fm-x-dismiss clears the durable context for a dismissed mention.
Refactors reply-context extraction into a single owner and adds regression
coverage for all four cases.
* no-mistakes(review): Captain, fail closed on incomplete follow-up context
* no-mistakes(review): Captain, bound X context registry retention
* no-mistakes(review): Captain, align context retention with answer binding
* no-mistakes(document): Align X follow-up context documentation
* no-mistakes(document): Align durable X follow-up documentation
* fix: preserve secondmate routing markers in terminal sends (#533)
* fix: preserve secondmate routing markers
* no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends
* no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift
* no-mistakes(document): Refresh Herdr marker documentation
* fix: align Grok effort handling with 0.2.99 (#527)
* fix: align grok effort docs and spawn with 0.2.99 ceiling
grok 0.2.99 accepts only low|medium|high for --reasoning-effort and
rejects both xhigh and max. Omit unsupported values on spawn, flag them
in crew-dispatch validation, and update harness-adapters.
* no-mistakes(test): Captain: refresh gotmp teardown fixture dependencies
* no-mistakes(document): Clarify Grok effort documentation ownership
* fix: derive bearings from authoritative secondmate state (#555)
* fix: make bearings use secondmate home state
* test: anonymize bearings fixtures
* no-mistakes(review): Bound parent activity evidence scans, captain
* no-mistakes(review): Preserve structured secondmate authority and bounds, captain
* no-mistakes(review): Preserve registry completeness and child inventory, captain
* no-mistakes(review): Reconcile parent evidence by verb and key, captain
* no-mistakes(review): Treat unkeyed parent evidence as inconclusive, captain
* no-mistakes(document): Document bearings local snapshot and PR opt-in
* no-mistakes(lint): Fix fleet snapshot ShellCheck findings
* no-mistakes: apply CI fixes
* fix: restore fleet snapshots on stock macOS Bash (#578)
* fix: restore stock macOS snapshot parsing
* no-mistakes(document): Clarify Linux gate and macOS CI coverage
* fix(afk): make Pi escalation and return catch-up reliable (#587)
* fix: close away-mode blocker supervision gap
* no-mistakes(review): Gate teardown retries and verify U+2063 dedupe
* no-mistakes(test): Fail closed on incomplete Pi composer separators
* no-mistakes(document): Document Pi composer recognition and return gating
* feat: support Pi max reasoning profiles (#537)
* support Pi max thinking profiles
* no-mistakes(review): Captain, allow Pi max dispatch profiles
* chore: no-mistakes(document): Clarify yolo response ownership (#595)
* Clarify validation response ownership
* no-mistakes(document): Clarify yolo response ownership
* feat: establish instruction ownership foundation (#619)
* Add instruction owners foundation
* no-mistakes(document): Refresh project-management owner pointers
* fix: compress Firstmate contract and enforce delivery rigor ownership (#626)
* docs: compress firstmate operating contract
* docs: make delivery rigor single-owner
PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion.
* no-mistakes(review): Honor configured merge authority across faster delivery paths
* no-mistakes(document): Align docs with compressed operating contract
* feat: add durable captain decision holds (#593)
* Add durable captain decision holds
* no-mistakes(review): Validate decision hold retries and origin paths
* no-mistakes(review): Enforce durable decision lifecycle boundaries
* no-mistakes(review): Harden decision display and partial retry recovery
* no-mistakes(test): Update scout teardown fixtures for decision inventory
* no-mistakes(document): Align decision lifecycle and scout teardown documentation
* no-mistakes: apply CI fixes
* no-mistakes(review): Reconcile terminal decision holds
* no-mistakes(document): Align captain decision-hold documentation
* fix(bin): harden PR check artifacts (#556)
* fix: harden PR check artifacts
* fix: close PR check migration gaps
* fix: close PR check retry gaps
* fix: clarify migration outcomes and ESM boundary
* fix: keep failed migrations authoritative
* test: use inert PR validation fixtures
* no-mistakes(review): Reserve noncanonical PR quarantine namespace
* no-mistakes(review): Prevalidate final PR-check teardown artifacts
* no-mistakes(review): Preserve X metadata and validate teardown IDs
* no-mistakes(review): Initialize migration state before watcher exclusion
* no-mistakes(review): Isolate failed poll migrations from bootstrap recovery
* no-mistakes(review): Allow safe polling during incomplete private repairs
* no-mistakes(review): Authenticate watcher checks at execution time
* no-mistakes(review): Preserve custom checks with hash-bound registration
* no-mistakes(review): Clean custom check snapshots on watcher signals
* no-mistakes(review): Stop watcher checks promptly on signals
* no-mistakes(review): Terminate watcher check groups before cleanup
* no-mistakes(document): Correct stale X-mode watcher documentation
* fix: drain returned watcher check groups
* no-mistakes(review): Harden quarantine links and recover validated replacement polls
* no-mistakes(review): Preserve X mode across shim version transitions
* no-mistakes(review): Refresh legacy X shims before marker short-circuits
* no-mistakes(document): Correct persisted PR-check artifact documentation
* no-mistakes(document): Correct stale PR-check documentation
* fix: bind PR poll repair provenance
* no-mistakes(review): Enforce single-link ownership for custom check artifacts
* no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs
* no-mistakes(review): Separate task creation and legacy teardown validation
* no-mistakes(review): Restore safe legacy operations and teardown validation
* no-mistakes(review): Disambiguate migration obligations and preserve legacy retries
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits
* no-mistakes(document): Document private poll artifact safety contracts
* no-mistakes(lint): Suppress intentional literal-dollar lint finding
* fix: migrate historical X poll identity
* fix: harden PR check artifacts
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* fix: migrate historical X poll identity
* no-mistakes(review): Harden X-mode artifact publication against symlink corruption
* no-mistakes(review): Guard X artifact publication
* no-mistakes(review): Enforce private X artifact reads
* no-mistakes(test): Fix backend compatibility fixture dependencies
* no-mistakes(document): Refresh PR-check documentation
* no-mistakes(lint): Remove unused x-mode test locals
* no-mistakes: apply CI fixes
* fix(bin): compact session-start backlog digest (#636)
* fix: compact session-start backlog digest
* no-mistakes(test): Fix legacy backend fixture helper
* no-mistakes(test): Fix watcher exit wait helper
* no-mistakes(document): Document compact backlog digest
* fix: dedupe stale watcher guard banners (#637)
* fix: dedupe stale watcher guard banner
* no-mistakes(review): Keep read-only guard state nonmutating
* no-mistakes(document): Clarify stale watcher docs
* fix(bin): balance bearings landed baseline (#640)
* fix: balance bearings landed defaults
* no-mistakes(document): Document balanced landed baseline
* no-mistakes: apply CI fixes
* fix: clarify captain-facing translation contract (#644)
* docs: clarify captain-facing translation contract
* no-mistakes(review): Restore runtime fallback mandate
* no-mistakes(document): Align Bearings translation wording
* fix(bin): make bootstrap output and nudges deterministic (#646)
* fix: make bootstrap nudges deterministic
* no-mistakes(review): Honor state override for bootstrap nudges
* no-mistakes(review): Update benign bootstrap documentation labels
* no-mistakes(review): Validate bootstrap nudge retry markers
* no-mistakes(document): Align bootstrap nudge documentation
* no-mistakes: apply CI fixes
* docs(secondmate-provisioning): clarify concise registry ownership (#649)
* Clarify concise secondmate registry contract
* no-mistakes(review): Expand secondmate registry boilerplate coverage
* no-mistakes(document): Point route docs to owner
* fix(bin): strip quoted blocked_by values during decision hold resolve (#654)
* fix(bin): strip quotes on blocked_by in decision-hold resolve
tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary
membership test only matched middle elements. Strip surrounding quotes
before matching so first and last hold ids resolve correctly.
* no-mistakes(document): Refresh decision-hold regression evidence
* feat(secondmate): inherit shared captain preferences (#656)
* feat(secondmate): inherit shared captain preferences
* no-mistakes(review): Honor shared captain data overrides
* no-mistakes(review): Honor bootstrap data override registry
* no-mistakes(document): Refresh shared inheritance docs
* no-mistakes(document): Clarify inherited local-material docs
* feat: gate local agent secret injection (#658)
* feat(spawn): gate local agent secret injection
* fix(spawn): align final Keychain slot
* no-mistakes: apply CI fixes
* test: isolate Herdr autodetect smoke sessions (#662)
* test: isolate herdr autodetect smoke session
* no-mistakes(review): Restored autodetect smoke gate bypass
* no-mistakes(test): Harden Herdr lab provisioning
* no-mistakes(document): Refresh Herdr lab docs
* docs: adopt under way for active work (#666)
* Revert "feat: gate local agent secret injection (#658)" (#668)
This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef.
* fix(pi): distinguish stale locks when arming watcher (#681)
* fix(pi): distinguish stale locks when arming watcher
* no-mistakes(test): Stabilize watcher extension async waits
* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate house vocabulary (#685)
* fix: accept secondmate as house vocabulary
* no-mistakes(test): Update captain vocabulary contract test
* no-mistakes(document): Align secondmate documentation vocabulary
* fix(bin): parse handoff homes after registry parentheticals (#686)
* fix: parse secondmate home after pre-field parentheses
Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.
* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges (#687)
* feat: add native session-start nudges
* no-mistakes(document): Document nudge script inventory
* docs: call built-in defaults the firstmate repo, not template (#688)
Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
* fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205)
* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn
Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(brief): harden fm-brief regression coverage for parse and scaffolds
Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the
Co-authored-by: Cursor <cursoragent@cursor.com>
#166 apostrophe regression cannot return unnoticed.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(bin): keep watcher supervision continuous across child cycles (#693)
* fix: make watcher supervision continuous
* no-mistakes(review): Bound watcher retries and log attached signals
* no-mistakes(review): Add bounded successor-recovery wake fallbacks
* no-mistakes(review): Prevent overlapping successor-arm retries
* no-mistakes(review): Resume supervision after late arm closes
* no-mistakes(review): Bind OpenCode recovery to attempted arm
* no-mistakes(test): Synchronize peer beacon regression fixture
* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures
* no-mistakes(document): Captain: document watcher successor protocol behavior
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: fetch current PR head for review diffs (#722)
* fix: always fetch PR head for review diffs
Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.
* no-mistakes(test): Isolate session-start nudge tests from gate state
* no-mistakes(document): Correct review-diff documentation
* docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736)
* docs: resolve five contract contradictions
* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): correct Grok exit guidance (#742)
* docs(harness): reverify grok exit command
* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for parked crew (#743)
* fix(watcher): bound stale wakes for exited paused crew
* no-mistakes(review): Gate pause suppression on confirmed agent death
* no-mistakes(test): Fixed stale pause cadence
* no-mistakes(document): Document dead-agent hold cadence
* fix(supervision): distinguish ordinary wakes from recovery (#744)
* fix(supervision): distinguish ordinary wakes from repair
* no-mistakes(review): Make passive guard follow-ups recovery-only
* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes (#745)
* fix(x-mode): dedupe pending mention wakes
* no-mistakes(review): fix x-poll claim error deduplication
* no-mistakes(review): separate claim diagnostics from relay recovery
* no-mistakes(document): Document X-mode once-only mention wakes
* feat(wake): enrich drained signals with bounded status context (#747)
* feat(wake): enrich drained signal context
* no-mistakes(review): Bound wake enrichment reads
* no-mistakes(document): Document wake-drain annotations
* docs(wake): explain at-least-once drain boundary
* no-mistakes(review): Prevent symlink races in wake annotations
* no-mistakes(review): Exercise wake symlink race regression
* test: document intentional AFK marker subprocesses
* fix(wake): isolate annotation marker state
* feat(herdr): add optional presentation spaces (#784)
* feat(herdr): add optional presentation spaces
* no-mistakes(review): Harden Herdr projection creation and spawn serialization
* no-mistakes(review): Captain, disarm Herdr cleanup before launch submission
* no-mistakes(test): Correct stale Orca metadata failure fixture
* no-mistakes(document): Document Herdr presentation projection accurately
* fix(send): treat opencode busy-queued composer state as submitted (#775)
* fix(send): treat opencode busy-queued composer state as submitted
When fm-send sends a message to a BUSY opencode crewmate on the tmux
backend, opencode accepts the Enter and queues the message for the next
turn, but leaves the typed text visible in the composer row. The
submit-verification loop sees a pending composer, exhausts retries, and
reports a false "Enter swallowed" failure while the message is actually
delivered.
Fix: after Enter retries are exhausted and the composer still shows
pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn,
footer shows "esc interrupt"), the harness queued the message, so
return "empty" (accepted). On an idle pane, keep returning "pending"
(genuine swallow detection preserved).
Regression tests cover four scenarios:
- busy pane + pending composer -> empty (message queued)
- idle pane + pending composer -> pending (genuine swallow)
- busy pane + composer clears on first Enter -> empty
- idle pane + composer clears on first Enter -> empty (existing path)
* docs: document busy-queued Enter exception across backend docs and skills
Add explanatory comments and backend documentation for the
busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn
but keeps typed text in composer until the turn ends):
- bin/fm-tmux-lib.sh: document the busy-aware fallback in the
file header and above fm_tmux_submit_enter_core
- .agents/skills/afk/SKILL.md: daemon-facing policy note
- .agents/skills/harness-adapters/SKILL.md: harness-specific fact
- docs/tmux-backend.md: submit-acknowledgement section with the
busy-queue exception
- docs/herdr-backend.md: record the known gap
- docs/architecture.md: cross-reference in the daemon section
* test(tmux): fix SC2181 and make busy-submit test executable
* fix(spawn): require two stable reads before accepting worktree path (#765)
* fix(spawn): require two stable reads before accepting worktree path
The treehouse-get worktree-detection loop in fm-spawn.sh accepted the
first pane_current_path read that differed from the project path, but
on some tmux/WSL setups a brand-new window transiently reports a
stale-but-real path before the pane actually settles into the
worktree. Since that stale path is itself a real, distinct git
checkout, it also passes validate_spawn_worktree's isolation check,
so the loop silently recorded the wrong worktree in state/<id>.meta
(and, for claude harness spawns, installed the turn-end hook there
too).
Require two consecutive polls to agree on the same non-project path
before accepting it, using the existing inter-poll sleep as the
confirmation gap so an already-settled pane isn't slowed down by an
extra cycle.
* fix(tests): drop unused CASE_DIR read in worktree-settle test
ShellCheck SC2034: CASE_DIR is split out of the case record but
never referenced; discard it with _ instead.
---------
Co-authored-by: Freudator86 <tim@allesknut.de>
* fix(bin): make watcher process identity immune to Linux wall-clock changes (#752)
* fix(watcher): stabilize Linux process identity
* no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale
* fix: prevent AFK idle stalls and stale run attribution (#758)
* fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state
Stop free-text tokens like "merged" from promoting nonterminal working: lines
to captain-relevant, so AFK no longer permanently suppresses idle recovery.
Defend wedge aging independently for nonterminal progress verbs, bind
no-mistakes current-state attribution to code identity (not branch alone),
and mark setup-complete as nonterminal in the ship brief scaffold.
* no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution
* no-mistakes(document): Document current-code-bound run attribution
* no-mistakes(test): Wait for stable Herdr shell readiness
* no-mistakes(test): Make Herdr and watcher readiness tests deterministic
* no-mistakes(test): Make tmux capture and watcher lifecycle deterministic
* no-mistakes(document): Document corrected supervision contracts
* fix(bin): allow safe teardown during watcher recovery (#750)
* fix: allow safe teardown during watcher recovery
* no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code
* no-mistakes(document): Sync continuity-gate docs to allow teardown recovery
* test: mark dynamic teardown fixture literal
* no-mistakes(document): docs: add teardown to continuity gate allow list
* feat(herdr): order presentation spaces while preserving focus (#790)
* feat(herdr): order presentation worker spaces
* fix(herdr): preserve focus during projected cleanup
* no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs
* no-mistakes(review): Serialize Herdr aborts with guarded focus regressions
* no-mistakes(review): Fall back flat when Herdr serialization is unavailable
* no-mistakes(test): Stabilize watcher startup and AFK handoff tests
* no-mistakes(document): Correct Herdr ordering and focus documentation
* fix(bin): send literal config reread nudges after pushes (#809)
* Send literal config reread after inherited config push
When declared inherited config changes under an already-running secondmate,
build a per-home instruction from validated destination post-write bytes and
deliver it on the routed secondmate path. Unchanged config sends nothing;
ABSENT represents removal; captain-shared is never inlined. Covers mid-session
config-push and the locked bootstrap convergence path without hardening spawn
against deliberate runtime choice.
* no-mistakes(review): Fix config reread framing, partial propagation, and respawn order
* no-mistakes(review): Send config rereads via durable single-line pointers
* no-mistakes(review): Make failed config rereads retryable
* no-mistakes(review): Make config reread retries generation-safe
* no-mistakes(review): Make config rereads durable and ordered
* no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode
* no-mistakes(review): Retain write retries and quarantine stale respawn generations
* no-mistakes(review): Preserve exact config reread retries and delivery order
* no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning
* no-mistakes(document): Consolidated config-reread documentation
* feat(watch): follow GitLab merge requests to merge (#797)
* feat(watch): follow GitLab merge requests to merge
The merge watch only understood GitHub pull requests, so a task whose
deliverable is a GitLab merge request was never followed to merge.
Generalize the stored poll identity from owner/repository to a
provider-tagged provider/url/host/path/number record. GitLab runs mostly on
self-hosted instances and its projects nest under groups at no fixed depth,
so the host and the full project path are data in the record rather than
constants, and every consumer rebuilds the URL from those parts and refuses
any record that does not reconstruct it exactly.
The GitLab state is read with plain glab, matching the GitHub path's use of
plain gh, so an upstream checkout needs no extra tooling. Two things about
glab were established by running it rather than assumed, because a wrong
invocation here fails silently into a permanent "not merged":
- glab has no field selector, and its JSON would need a JSON processor that
firstmate does not require, so the state is read from glab's own field
output. Only an exact "merged" wakes firstmate, so a changed format stays
silent instead of reporting a merge.
- glab cannot take a merge request URL the way gh can, because that form
resolves through the current git repository and the watcher has none. It
is addressed by project URL and merge request number instead.
An absent glab produces no wake rather than a false merge, and arming
refuses with a clear message since that is the one point where a missing
CLI can still be reported. A GitLab task records no pr_head, which both
consumers already treat as optional. The merge path still addresses GitHub
only and refuses a merge request URL rather than sending it to the wrong
forge.
The record version moves to v2, and the existing non-executing migration
rebuilds an already-armed watch from its recorded URL, so no watch is lost
by upgrading.
docs/gitlab-merge-watch.md records the evidence, taken against the public
fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture.
* no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation
* no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs
* fix(herdr): group projected children beneath owning parents (#821)
* feat(herdr): correct all-home child presentation topology
Inherit the presentation opt-in to secondmate homes, label new projected
spaces with the approved corner format, insert each child under its owning
parent under one session-scoped lock, and keep flat non-destructive fallback.
* no-mistakes(review): Exclude secondmates from Herdr presentation projection
* no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering
* no-mistakes(review): Use adjacency-only Herdr child ownership
* no-mistakes(review): Reject foreign legacy projections safely
* no-mistakes(review): Validate Herdr session sockets before projection
* no-mistakes(test): Fix Herdr teardown fixture session socket metadata
* fix(herdr): canonicalize presentation lock socket paths
Always resolve the session socket parent directory so symlink parents
such as /tmp -> /private/tmp cannot split the shared cross-home lock
identity. Refuse relative socket paths. Clarify lock-unavailable warnings.
* no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing
* no-mistakes(document): Document all-home Herdr child topology
* no-mistakes(lint): Quote fallback provenance string for ShellCheck
* fix: keep local no-mistakes tests intent-targeted (#823)
* fix(no-mistakes): drop full-suite local Test override
Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad
tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a
focused contract test so the override cannot silently return.
* no-mistakes(lint): Make CI contract assertion ShellCheck-clean
* feat: add canonical timed test runner (#825)
* feat(test): add canonical timed suite runner and honest CI timeout
Introduce bin/fm-test-run.sh as the single serial owner for selecting
one script, a family, a conservative changed-file set, or the explicit
complete suite, with per-script timing markers and a JSON artifact.
Wire CI Behavior through the runner, raise the hang-tripwire timeout to
25 minutes, and document entry points without restoring a full-suite
local no-mistakes Test command.
* no-mistakes(review): Captain: fix changed selection and empty summaries
* no-mistakes(review): Captain: fail closed on unmapped changed sources
* no-mistakes(document): Document canonical timed test entry points
* fix: surface main inventory gaps in Bearings (#830)
* fix: disclose main-home orphan and unstructured inventory gaps
Main Bearings could report an empty fleet while structured in-flight rows
lacked meta or current backlog rows were free-form. Emit main_inventory from
the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next
gate, and keep meta as the only live Underway source.
* no-mistakes(document): Document Bearings inventory-integrity projection
* no-mistakes: apply CI fixes
* feat: add bounded concurrent test isolation proof (#832)
* feat: add concurrent test isolation proof for Phase 2
Prove an audited portable candidate set passes under concurrent
workers with private mode-0700 temp roots, without enabling
production CI sharding or fm-test-run --jobs.
* no-mistakes(review): Pin isolation proof to audited candidate manifest
* feat: guard against missed secondmate reports (#834)
* feat(secondmate): parent-owned guards for missed status reports
Marked parent-to-secondmate requests now create a durable pending-reply
expectation with a privacy-safe correlation id before delivery. Transport
success never resolves it; only a correlated parent status or document
pointer does. After a completed turn with no report, the parent sends one
recovery repost and escalates once if that turn is also missed, without
scraping the secondmate conversation or looping.
* no-mistakes(review): Deduplicate wrong-home pending-reply sightings
* no-mistakes(review): Harden pending-reply recovery and escalation guards
* no-mistakes(review): Bound pending-reply backend polling
* no-mistakes(review): Cache pending-reply status scans
* no-mistakes(review): Protect undelivered pending-reply records from scans
* no-mistakes(review): Close pending-reply delivery durability gaps
* no-mistakes(review): Separate pending-reply transport outcomes
* no-mistakes(review): Escalate stalled pending-reply deliveries once
* no-mistakes(review): Resolve attempted deliveries from correlated reports
* no-mistakes(review): Resolve late reports after delivery escalation
* no-mistakes(document): Document pending-reply grace and ownership
* no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings
* feat: require pinned real-Herdr CI coverage (#838)
* feat: add required pinned Herdr CI lane
Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and
SHA-256 pins, run the real-herdr-gated family serially through
fm-test-run with hard-fail on herdr-not-found, and keep portable
Behavior free of claimed Herdr coverage.
* no-mistakes(document): Consolidate real-Herdr CI documentation ownership
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* feat: shard portable tests and add bounded local parallelism (#841)
* feat: shard portable CI tests after isolation proof
Balance the Phase 2 proven-isolated set into two LPT portable parallel
lanes from Phase 1 timing evidence, keep stateful work in a required
portable serial lane, exclude real Herdr to its dedicated required lane,
and prove complete inventory coverage with a deterministic guard.
Add bounded local --jobs only for the proven set, per-lane timing plus
aggregate artifacts, and reduce the interim portable hang tripwire now
that the serial remainder owns the long wall-clock path.
* no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling
* no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests
* no-mistakes(document): Document portable sharding and timing aggregation
* no-mistakes: apply CI fixes
* fix: block primary-session delegation outside the fleet (#854)
* feat: fence primary-session delegation outside the fleet
A firstmate primary that delegates through Claude Code's built-in
delegation tools creates work with no state/<id>.meta. Because
fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits
silently at zero, such work does not merely go unsupervised: it makes
the whole guard stack structurally inert, and it dies with the primary
session. On 2026-07-22 that cost two workers mid-flight and left
supervision down for 73 minutes unnoticed.
Layer 1, the primary fix: a permissions.deny list in
.claude/settings.json removes the 18 delegation, scheduling, worktree,
and task-tracking tools from the model's schema, so they are never
offered. This is removal rather than interception, so there is no call
to intercept and no fail-open path. The list is flat and in one file so
its width stays reviewable; the captain owns that width.
Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open
against tools that do not exist yet, and permissions.allow is a
pre-approval list rather than an availability list, so there is no
fail-closed allowlist to use instead. This backstop classifies the tool
NAME by shape rather than against a fixed list, so a delegation tool
that ships before the deny list is updated is still refused. It excludes
mcp__* names and observe-or-stop operations, scopes itself to a genuine
primary home via the shared fm_primary_scope_matches predicate so a
crewmate's task worktree is unaffected, and offers one deliberate
FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch.
Verified live against Claude Code 2.1.217, including a deny-key A/B with
a nonsense-name control, layer 2 denying an un-denied Workflow call, the
same call allowed in a linked worktree, and the escape hatch. Corrects a
prior finding: both Task and Agent work as deny keys, so both are
pinned. Codex 0.144.1 verified to expose no delegation tool; grok,
opencode, and pi are inspected and documented as not wired because those
binaries are absent from this host and the repo requires live validation
before trusting a harness hook. Evidence in docs/subagent-guard.md.
* no-mistakes(review): Ship scoped Claude delegation guard
* no-mistakes(test): Ship Claude delegation deny list
* no-mistakes(document): Clarify PreToolUse guard ownership
* no-mistakes(lint): Keep Claude deny list local
* fix: install tasks-axi in portable CI shards (#866)
Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged.
* feat(bin): make dispatch profiles quota aware (#867)
* feat: make dispatch profiles quota aware
* no-mistakes(review): Fix quota window and Grok product scoping
* no-mistakes(document): Document implicit quota-aware dispatch accurately
* Add built-in ahoy recap skill (#873)
* fix: preserve trustworthy Bearings data in partial snapshots (#875)
* fix: preserve mixed Bearings projections
* no-mistakes(review): Enforce strict invalidity precedence for partial snapshots
* no-mistakes(review): Enforce ownership for unknown child metadata
* no-mistakes(document): Document partial structured Bearings projections
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* feat(pi): add session-local calm mode (#884)
* Add session-local Pi calm mode
* no-mistakes(review): Preserve Pi HTML exports during calm mode
* no-mistakes(review): Preserve calm exports across submit bindings and share
* no-mistakes(document): Document calm-mode feasibility across supported harnesses
* fix(pi): prevent redundant watcher re-arms (#885)
* fix(pi): limit watcher arm tool to recovery
* no-mistakes(review): Strengthen Pi live re-arm regression coverage
* no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming
* fix(pi): clean up Calm transcript rendering (#895)
* fix(pi): clean up Calm transcript rendering
* no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs
* no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations
* no-mistakes(review): Restore Calm rows received while active
* no-mistakes(review): Preserve diagnostics during Calm restoration
* no-mistakes(document): Clarify Calm transcript behavior and injection paths
* fix: execute every PR body compliance event (#898)
* fix: execute every PR body compliance event
* no-mistakes(document): Document independent PR compliance events
* fix: exclude operational injections from ahoy boundaries (#899)
* fix: distinguish operational input in ahoy
* no-mistakes(review): Handle legacy Ahoy operational boundaries
* no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions
* no-mistakes(document): Document Ahoy operational marker ownership
* no-mistakes(lint): Suppress intentional literal fixture lint warnings
* fix: canonically classify operational inputs across harnesses (#909)
* fix: type canonical operational inputs
* no-mistakes(document): Correct canonical operational-input documentation ownership
* fix: avoid generic secondmate start acknowledgements (#926)
* fix: avoid generic secondmate acknowledgements
* no-mistakes(document): Document sparse secondmate acknowledgement behavior
* no-mistakes: apply CI fixes
* fix(pi): make calm mode persistent and gapless (#927)
* fix(pi): preserve calm presentation across sessions
* no-mistakes(review): Fix Calm home fallback persistence
* no-mistakes(document): Clarify Calm gapless and export contracts
* no-mistakes: apply CI fixes
* fix(watch): retire merged PR polls after durable notification (#932)
* fix: retire merged PR polls after notification
* no-mistakes(review): Decouple PR retirement recovery from template updates
* no-mistakes(review): Recover pending PR retirements before poll migration
* no-mistakes(document): Document merged PR poll retirement contracts
* fix: refine scout intake and parallel dispatch (#934)
* Clarify intake evidence and overlap handling
* no-mistakes(review): Align scout guard with intake classification
* no-mistakes(document): Clarify scout documentation and intake ownership
* fix(pi): prevent duplicate assistant replies in Calm (#936)
* fix(pi): preserve operational follow-up semantics in Calm
* no-mistakes(document): Correct Calm operational-row visibility documentation
* perf(bin): shrink the ShellCheck source graph (#939)
* perf(lint): shrink shell source graph
* no-mistakes(review): Ensure lint workers terminate fully on cancellation
* no-mistakes(document): Repair stale lint documentation ownership
* fix(pi): remove Calm hidden-block gaps (#942)
* fix(pi): remove Calm hidden-block gaps
* no-mistakes(review): Validate Calm geometry against current viewport
* no-mistakes(review): Synchronize Calm geometry checks with reload completion
* fix: enforce contract boundaries for ask-user findings (#945)
* fix: escalate ask-user contract expansion
* no-mistakes(document): Point project management to authority owner
* docs: prefer direct operational paths (#946)
* fix(pi): hide operational user rows in Calm mode (#948)
* fix(pi): hide Calm operational user rows
* no-mistakes(review): Narrow Calm operational input suppression
* no-mistakes(review): Avoid Calm replay classifier subprocesses
* no-mistakes(document): docs: point Pi verification to Calm owner
* fix: relaunch missing second mates at session start (#950)
* fix(session-start): relaunch missing second mates
* fix(test): detect completed parallel workers
* no-mistakes(review): Isolate session-start recovery test cleanup
* no-mistakes(review): Complete backend-safe secondmate session recovery
* no-mistakes(review): Resolve Zellij task ownership before recovery
* no-mistakes(review): Recover relocated Zellij ghost tabs safely
* no-mistakes(review): Restore conservative Zellij recovery boundary
* no-mistakes(review): Reject malformed tmux recovery targets
* no-mistakes(document): Align secondmate recovery documentation
* no-mistakes: apply CI fixes
* fix(herdr): reclaim resumed task projections after restart (#967)
* fix(herdr): reclaim resumed task projections safely
* no-mistakes(review): Enforce safe Herdr reclaim close boundaries
* no-mistakes(document): docs: clarify Herdr restart projection contract
* Teach Ahoy to surface open decisions (#968)
* Require shipshape routine acknowledgement (#969)
* docs: separate current guidance from verification evidence (#994)
* docs: separate current guides from verification
* no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence
* fix: preserve Claude watcher continuity across Stop hooks (#997)
* feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm
Claude primaries (main home and marked secondmate homes) no longer depend
on the model remembering to re-arm the watcher after each wake. A tracked
Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s)
fires on every turn end, claims one home-scoped single-flight owner,
foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and
translates an actionable close or typed watcher failure into exactly one
exit-2 rewake. The hook scopes to genuine primary checkouts, requires the
session lock to be held by its own harness ancestor, stays inert while
AFK owns triage or the home is idle, and hands AFK transitions mid-cycle
to the daemon without rewaking.
The synchronous turn-end guard gains a --claude cooperative mode: it
ignores stop_hook_active (true on every post-continuation stop, which is
what re-opened the 2026-07-21 blind window), waits briefly for a watcher
health proof, a live auto-arm owner claim, or a fresh rewake epoch, and
re-blocks only when the auto-arm genuinely failed to establish - bounded
to 3 consecutive blocks per session, safely below Claude Code's 8-block
override, then a degraded allow with a visible systemMessage. Codex
keeps the previous one-block loop guard byte-identically, and Pi,
OpenCode, and Grok adapters are untouched.
Continuity PreToolUse gate and durable wake queue are preserved; the
gate's recovery guidance now names the Stop-owned re-arm and reserves
manual background arms for auto-arm failure. Claude supervision protocol,
harness-adapters facts, architecture, configuration, and continuity docs
updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218
contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout
process-group kill, 8-block cap, interactive non-stall) and the 2.1.219
product live E2Es.
Regression matrix: hermetic tests cover scope, identity, AFK, need,
single-flight, translation, guard cooperation, budget, and registration;
the new live E2E proves two full tokenless auto-arm rewake cycles with
zero model arm commands; Pi and OpenCode Option B live E2Es pass
unchanged.
* no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop
* no-mistakes(review): Remove unsupported Claude contract-lab verification claims
* no-mistakes(document): Update Claude auto-arm continuity documentation
* fix(herdr): clean stale projections at session start (#996)
* Clean stale Herdr projections at session start
* no-mistakes(document): Document stale Herdr session-start projection cleanup
* no-mistakes(review): Enforce locked exact Herdr projection cleanup
* no-mistakes(review): Fail closed on unverified session lock ownership
* no-mistakes(review): Serialize session lock acquisition atomically
* no-mistakes(document): Align session-start and Herdr cleanup documentation
* no-mistakes(document): Generalize lock-refusal diagnostics
* no-mistakes(lint): Avoid reserved keyword in concurrency test
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: recover Claude supervision without watcher-status gate (#1001)
* fix: recover Claude supervision at session start
* fix: remove Claude watcher-status command gate
* no-mistakes(document): docs: remove stale continuity gate references
* fix: make quota-aware profile selection agent-owned (#1018)
* Replace quota dispatch selector instructions
* no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection
* fix(bin): remove vestigial dispatch selector (#1026)
* remove vestigial dispatch selector
* no-mistakes(review): Synchronize isolation proof and portable shard evidence
* no-mistakes(review): Correct shard history and proof archive date
* no-mistakes(review): Remove reintroduced selector documentation reference
* no-mistakes(document): Remove stale dispatch strategy documentation
* docs(agents): drop superseded interim quota-window rule (#1039)
quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per
provider, so the successor named in the interim rule has landed and the
rule's own removal condition is satisfied.
Keep the ownership clause so quota-axi remains the single owner of how
model or product windows relate to bounding account windows, and drop
the interim weakest-headroom instruction. The unknown-semantics case is
already covered by the existing requirement to stop and report a
candidate whose applicable quota data or interpretation cannot be
established.
Drop the matching assertion phrase from
tests/fm-instruction-owners.test.sh; the retained ownership phrase still
asserts.
* fix(tmux): scope busy detection and recognize current Claude turns (#1049)
* fix(tmux): scope Claude busy detection by harness
* no-mistakes(review): Separate verified and fallback busy signatures
* no-mistakes(test): Scope busy signatures to supplied harnesses
* no-mistakes(document): Document harness-scoped busy detection
* feat: add verified Kimi crewmate adapter (#1047)
* Add verified Kimi crewmate harness adapter
* no-mistakes(review): Scope Kimi moon detection to spinner lines
* no-mistakes(review): Match only complete Kimi spinner rows
* no-mistakes(review): Resolve Kimi binary portably before pane creation
* no-mistakes(document): Align Kimi adapter documentation
* no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override
* Fix Kimi busy spinner detection
* no-mistakes(review): Recognize Kimi session-lock ancestry and holders
* no-mistakes(review): Scope pending-reply Kimi busy detection by harness
* no-mistakes(document): Correct Kimi spinner capture documentation
* no-mistakes(document): Clarify optional Kimi spinner whitespace
* no-mistakes(lint): Silence intentional pending-reply test stub warnings
* test: align rebased Kimi busy fixtures
* no-mistakes: apply CI fixes
* Reconcile Kimi busy detection after per-harness scoping
* no-mistakes(review): Clarify observed Kimi spinner whitespace contract
* no-mistakes(document): Clarify Kimi harness documentation
* fix: harden Kimi submission and spinner matching (#1058)
* fix kimi pointer submission and spinner conformance
* no-mistakes(review): Preserve Kimi submit target ownership guard
* feat(bin): add guarded Kimi turn-end wake (#1059)
* Add guarded Kimi turn-end hook
* no-mistakes(review): Require jq before installing Kimi turn-end hook
* no-mistakes(review): Expose jq inside isolated Kimi test fixtures
* no-mistakes(review): Preserve Kimi config boundaries during hook removal
* no-mistakes(review): Document Kimi removal newline safeguard
* no-mistakes(document): Document Kimi shared-home preservation
* fix(tmux): classify bordered composers across all rows (#1066)
* Fix structural tmux composer reading
* Verify Calm compatibility with Pi 0.82
* no-mistakes(review): Harden structural composer classification boundaries
* no-mistakes(review): Refresh composer and Kimi regression fixtures
* no-mistakes(review): Fail closed on unbounded composer edges
* no-mistakes(review): Enforce aligned composer geometry safely
* no-mistakes(review): Make composer ambiguity locale-safe
* no-mistakes(review): Preserve ambiguity through composer submission
* no-mistakes(review): Carry composer proof through retries
* no-mistakes(document): Document structural tmux composer delivery guarantees
* no-mistakes: apply CI fixes
* feat(bin): add verified pi-signed runtime adapter (#1145)
* feat: add verified pi-signed adapter
* no-mistakes(review): Correct pi-signed maintainer verification date
* no-mistakes(review): Correct remaining pi-signed verification dates
* no-mistakes(review): Preserve authoritative pi-signed runtime identity
* no-mistakes(document): Document pi-signed shared adapter semantics
* no-mistakes: apply CI fixes
* fix(pi): rearm watcher across session transitions (#1166)
* fix(pi): rearm watcher across same-process session transitions
Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement
as well as terminal quit. The primary watcher extension latched a module-level
stopping flag on every shutdown, so a replacement session in the same process
could not arm monitoring until Pi restarted.
Own arm authority per session generation so only the active live generation
may start, stop, or rearm the child. Replacement sessions can arm again without
restarting Pi, stale prior-generation callbacks cannot mutate the active cycle,
and real quit still blocks late rearm.
* no-mistakes(review): Preserve Pi generation isolation and exit cleanup
* no-mistakes(document): Correct Pi watcher transition documentation
* feat: route crew dispatch using quota-window pace (#1172)
* Consume quota-axi pace signals in dispatch profile array selection.
Add quota-array-dispatch as the single owner of the pace-aware candidate
choice, keep AGENTS.md to the intake boundary and load trigger, and cover
the acceptance cases with sanitized schemaVersion 3 fixtures.
* no-mistakes(review): Stop and report genuine quota dispatch ties
* no-mistakes(document): Document quota pace freshness and uncertainty
* fix: adapt Grok Stop continuation and harden endpoint cleanup (#1171)
* fix(grok): adapt Stop continuation to runtime capability
* no-mistakes(review): Reject ambiguous Grok Stop payloads
* no-mistakes(review): Reject duplicate Grok fields and accept spaced tmux sessions
* no-mistakes(review): Enforce exact tmux cleanup selectors
* no-mistakes(test): Fix historical tmux fixture and validate Grok Stop
* no-mistakes: apply CI fixes
* fix: restore stock macOS Bash 3.2 brief scaffolding (#1093)
* fix(brief): make DOD scaffolding parse-safe on stock macOS Bash 3.2
fm-brief.sh built each Definition-of-done block and the not-enabled
Herdr declaration with `VAR=$(cat <<EOF ... EOF)`. On Bash 3.2 (macOS
/bin/bash) the lexer scans for the command substitution's closing `)`
textually and tracks quote state through the heredoc body, so a single
apostrophe, unbalanced quote, or unbalanced paren in that prose breaks
parsing of the whole script. Every ship-brief scaffold (no-mistakes,
direct-PR, local-only) failed with `unexpected EOF while looking for
matching )`. Bash 4+ parses it fine, so the breakage stayed invisible
everywhere except stock macOS.
Replace all four command-substitution heredocs with
`IFS= read -r -d '' VAR <<EOF || true`. That removes the `$(...)`
wrapper and the entire defect class regardless of future prose, and
preserves the variable expansion the direct-PR and local-only bodies
need. `read` keeps the heredoc's trailing newline that `$(...)` used to
strip, so trim one newline to keep every generated brief byte-identical
to prior output.
Guard the structure, not one historical phrase: a new test rejects any
heredoc nested in a command substitution anywhere in fm-brief.sh, where
the old assertion pinned a single apostrophe phrase and so missed the
reintroduction. Extend the stock-macOS Bash CI job from parsing one
script to the whole maintained shell surface (bin/*.sh,
bin/backends/*.sh, tests/*.sh), matching bin/fm-lint.sh's canonical file
set so parse scope and lint scope cannot drift apart.
* no-mistakes(review): Captain: harden Bash structure and inventory guards
* no-mistakes(document): Align stock macOS Bash contributor checks
* no-mistakes(lint): Suppress deliberate SC2016 literal fixture warnings
* test: stabilize tmux teardown conformance baseline (#1209)
* fix(test): pin teardown tmux baseline to historical kill selectors
merge-base HEAD main collapses to HEAD after the exact-selector change
lands on the default branch, so the old teardown fixture was accidentally
exercising current exact targets. Resolve a content-historical permissive
tmux adapter from first-parent history and force that post-squash topology
inside the conformance case so main and feature branches keep the same
old-vs-new contract.
* no-mistakes(lint): Suppress intentional literal-pattern ShellCheck warnings
* docs: slim quota-array-dispatch to the pace selection core (#1197)
Cut the runtime skill to the compact pace-aware selection procedure plus
minimum owner pointers. Keep every distinct decision rule and move expanded
acceptance scenarios to deterministic fixture ownership assertions.
Size: 170/1374/10187 -> 63/544/4068 (about 63%/60%/60% reduction).
* feat(bin): inherit backend config into secondmate homes (#1219)
* Inherit config/backend into secondmate homes with deliberate-override preservation
Add backend to the shared inheritable config allowlist so launch, locked
bootstrap, and config-push converge a primary pin into secondmate homes as each
home local future-spawn default. Track last-inherited bytes in a private state
provenance marker so deliberate per-home overrides survive present and absent
primary convergence, keep --backend and FM_BACKEND stronger, and extend the
existing inheritance tests plus docs and skill claims.
* no-mistakes(review): Preserve equal unprovenanced backend overrides
* no-mistakes(review): Preserve symlink overrides and verify spawn precedence
* no-mistakes(review): Snapshot backend inheritance for consistent provenance
* no-mistakes(review): Simplify backend inheritance to primary-authoritative convergence
* no-mistakes(document): Document inherited backend override preservation
* fix: restore primary-authoritative backend inheritance after document regression
The document step reintroduced provenance and deliberate per-home override
semantics after review had simplified config/backend to plain primary-authoritative
allowlist membership. Restore the primary-always-wins path: present overwrites,
absent removes, no provenance marker, and docs/tests match that contract.
* no-mistakes(review): Add divergent backend precedence regression fixtures
* no-mistakes(document): Document backend inheritance contract
* fix(pi): remove Calm's upper version ceiling (#1226)
* fix(pi): remove Calm's exclusive Pi upper-version ceiling
tests/fm-calm-pi-extension.test.sh gated on a closed PI_COMPAT_VERSIONS
allowlist ("0.81.1 0.82.0") that refused any other installed Pi, and docs
described that range as "supported" rather than verified evidence. The
Calm CHANGELOG shows no API introduced at either version, so there is no
evidence for a real minimum; the presentation adapters already probe the
exact method they patch rather than checking a version.
Replace the allowlist with dated version evidence that never rejects a
newer Pi, and make each presentation adapter degrade independently with
a diagnostic if a future Pi removes its API, instead of the whole Calm
extension failing to load. Rewrite the feasibility doc's "Pi 0.81.1
through 0.82.0" phrasing to state it as verified evidence, not a
ceiling.
* no-mistakes(review): Probe missing Calm adapter exports safely
* no-mistakes(document): Document Calm's unbounded Pi compatibility
* fix(bin): allow session-local todo tools in the subagent guard (#1204)
* fix(guard): allow session-local todo tools in the primary
The delegation-shape guard denied TaskCreate and TaskUpdate because their
normalized names contain the `task` stem. Those tools write only the harness's
session-local todo list, which has no executor: it spawns no agent, allocates
no worktree, registers no schedule, and starts nothing that outlives the
session. That is not the unaccounted work the guard exists to stop, so the stem
match was a false positive, and the deny text told the primary to run
bin/fm-brief.sh and bin/fm-spawn.sh to create a todo entry.
Add a separately-reasoned PLAN_ONLY_TOOLS exact-name exclusion rather than
widening OBSERVE_ONLY_TOOLS, whose documented contract is tools that only
observe or stop existing work. Both lists stay exact-name so neither can widen
by substring.
Tests cover the two allowed names and six near-miss names that a substring or
shortened-stem widening would release; both mutations were watched red.
* no-mistakes(review): drop session-local todo tools from recommended deny list
* no-mistakes: apply CI fixes
* fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid (#1206)
* fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid
fm_harness_ancestry_pid() previously returned the first ancestor process
whose command matched a verified harness name. Claude Code's Stop hook
fires as a bg-spare worker several levels below the session's actual
lock-owning claude process (hook shell -> claude bg-spare ->
claude bg-pty-host -> claude -> claude(lock)), so the first match was
the bg-spare worker, not the lock owner. fm_session_lock_owned_by_self()
then never matched state/.lock, and the Claude Stop auto-arm silently
treated its own primary session as an unrelated live owner and never
armed the watcher.
The walk now keeps going past a claude-named match, looking for a still
more ancestral claude-named match, and stops the instant a non-match
follows an already-found match (bounding it to a contiguous run rather
than the literal ancestry top, so an unrelated claude-named process
further up the real process tree is never mistaken for part of this
session's own nested chain). Every other harness keeps the original
first-match-wins behavior, since e.g. Pi's shared signed-wrapper
ancestry actually holds the session at the inner engine pid, not an
outer wrapper pid. Hop limit raised from 8 to 16 to cover the deeper
bg-spare chain.
* no-mistakes(review): Add nested-claude-ancestry regression test; fix nudge doc depth claim
* no-mistakes: apply CI fixes
* fix: conferma l'avvio del watcher su Windows/MSYS (#1212)
* fix: confirm watcher startup on MSYS
* no-mistakes(review): gate MSYS arm ready timeout, cache uname, harden locale test
* no-mistakes(review): validate OpenCode ready timeout, make uname cache internal
* fix(spawn): forward CLAUDE_CONFIG_DIR to claude crewmates (#1195)
* fix(spawn): forward firstmate's CLAUDE_CONFIG_DIR to claude crewmates
Crewmate panes are created by a long-lived tmux/herdr daemon that does not
inherit firstmate's current environment. When firstmate runs under a non-default
CLAUDE_CONFIG_DIR (for example a work-vs-personal subscription split), a bare
`claude` in the crewmate pane fell back to the default ~/.claude store and
launched unauthenticated, blocking the crewmate before it could do any work.
fm-spawn now prefixes the claude launch with firstmate's own resolved
CLAUDE_CONFIG_DIR when set, so the crewmate uses the same credential/config
store firstmate is authenticated with. An unset value is the single-store
default and adds no prefix; non-claude harnesses are unaffected.
Adds three tests in fm-spawn-dispatch-profile.test.sh (forwarded-when-set,
omitted-when-unset, non-claude-ignored) and pins CLAUDE_CONFIG_DIR in the test
helper so launch assertions no longer depend on the developer's environment.
* no-mistakes: apply CI fixes
* fix: preserve dispatch identity across authentication checks (#1233)
* fix: preserve dispatch harness identity
* no-mistakes(review): Fix Grok counterfactual tuple validation
* no-mistakes(document): Scope dispatch authentication to selected tuple
* fix: restore dispatch instruction budget
* no-mistakes(review): Scope dispatch authentication after candidate selection
* fix(bin): normalize relative durable paths (#1256)
* fix(bin): handle dash-leading harness process names (#2)
* fix: handle dash-leading harness process names
* no-mistakes(review): Make dash-leading harness regression hermetic
* fix: preserve secondmate reply routes across relative homes
Resolve relative home, data, and state inputs before durable ch…
ammar00sheikh
added a commit
to ammar00sheikh/firstmate
that referenced
this pull request
Jul 31, 2026
…es (#1) * fix(afk): make Pi escalation and return catch-up reliable (#587) * fix: close away-mode blocker supervision gap * no-mistakes(review): Gate teardown retries and verify U+2063 dedupe * no-mistakes(test): Fail closed on incomplete Pi composer separators * no-mistakes(document): Document Pi composer recognition and return gating * feat: support Pi max reasoning profiles (#537) * support Pi max thinking profiles * no-mistakes(review): Captain, allow Pi max dispatch profiles * chore: no-mistakes(document): Clarify yolo response ownership (#595) * Clarify validation response ownership * no-mistakes(document): Clarify yolo response ownership * feat: establish instruction ownership foundation (#619) * Add instruction owners foundation * no-mistakes(document): Refresh project-management owner pointers * fix: compress Firstmate contract and enforce delivery rigor ownership (#626) * docs: compress firstmate operating contract * docs: make delivery rigor single-owner PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion. * no-mistakes(review): Honor configured merge authority across faster delivery paths * no-mistakes(document): Align docs with compressed operating contract * feat: add durable captain decision holds (#593) * Add durable captain decision holds * no-mistakes(review): Validate decision hold retries and origin paths * no-mistakes(review): Enforce durable decision lifecycle boundaries * no-mistakes(review): Harden decision display and partial retry recovery * no-mistakes(test): Update scout teardown fixtures for decision inventory * no-mistakes(document): Align decision lifecycle and scout teardown documentation * no-mistakes: apply CI fixes * no-mistakes(review): Reconcile terminal decision holds * no-mistakes(document): Align captain decision-hold documentation * fix(bin): harden PR check artifacts (#556) * fix: harden PR check artifacts * fix: close PR check migration gaps * fix: close PR check retry gaps * fix: clarify migration outcomes and ESM boundary * fix: keep failed migrations authoritative * test: use inert PR validation fixtures * no-mistakes(review): Reserve noncanonical PR quarantine namespace * no-mistakes(review): Prevalidate final PR-check teardown artifacts * no-mistakes(review): Preserve X metadata and validate teardown IDs * no-mistakes(review): Initialize migration state before watcher exclusion * no-mistakes(review): Isolate failed poll migrations from bootstrap recovery * no-mistakes(review): Allow safe polling during incomplete private repairs * no-mistakes(review): Authenticate watcher checks at execution time * no-mistakes(review): Preserve custom checks with hash-bound registration * no-mistakes(review): Clean custom check snapshots on watcher signals * no-mistakes(review): Stop watcher checks promptly on signals * no-mistakes(review): Terminate watcher check groups before cleanup * no-mistakes(document): Correct stale X-mode watcher documentation * fix: drain returned watcher check groups * no-mistakes(review): Harden quarantine links and recover validated replacement polls * no-mistakes(review): Preserve X mode across shim version transitions * no-mistakes(review): Refresh legacy X shims before marker short-circuits * no-mistakes(document): Correct persisted PR-check artifact documentation * no-mistakes(document): Correct stale PR-check documentation * fix: bind PR poll repair provenance * no-mistakes(review): Enforce single-link ownership for custom check artifacts * no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs * no-mistakes(review): Separate task creation and legacy teardown validation * no-mistakes(review): Restore safe legacy operations and teardown validation * no-mistakes(review): Disambiguate migration obligations and preserve legacy retries * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits * no-mistakes(document): Document private poll artifact safety contracts * no-mistakes(lint): Suppress intentional literal-dollar lint finding * fix: migrate historical X poll identity * fix: harden PR check artifacts * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * fix: migrate historical X poll identity * no-mistakes(review): Harden X-mode artifact publication against symlink corruption * no-mistakes(review): Guard X artifact publication * no-mistakes(review): Enforce private X artifact reads * no-mistakes(test): Fix backend compatibility fixture dependencies * no-mistakes(document): Refresh PR-check documentation * no-mistakes(lint): Remove unused x-mode test locals * no-mistakes: apply CI fixes * fix(bin): compact session-start backlog digest (#636) * fix: compact session-start backlog digest * no-mistakes(test): Fix legacy backend fixture helper * no-mistakes(test): Fix watcher exit wait helper * no-mistakes(document): Document compact backlog digest * fix: dedupe stale watcher guard banners (#637) * fix: dedupe stale watcher guard banner * no-mistakes(review): Keep read-only guard state nonmutating * no-mistakes(document): Clarify stale watcher docs * fix(bin): balance bearings landed baseline (#640) * fix: balance bearings landed defaults * no-mistakes(document): Document balanced landed baseline * no-mistakes: apply CI fixes * fix: clarify captain-facing translation contract (#644) * docs: clarify captain-facing translation contract * no-mistakes(review): Restore runtime fallback mandate * no-mistakes(document): Align Bearings translation wording * fix(bin): make bootstrap output and nudges deterministic (#646) * fix: make bootstrap nudges deterministic * no-mistakes(review): Honor state override for bootstrap nudges * no-mistakes(review): Update benign bootstrap documentation labels * no-mistakes(review): Validate bootstrap nudge retry markers * no-mistakes(document): Align bootstrap nudge documentation * no-mistakes: apply CI fixes * docs(secondmate-provisioning): clarify concise registry ownership (#649) * Clarify concise secondmate registry contract * no-mistakes(review): Expand secondmate registry boilerplate coverage * no-mistakes(document): Point route docs to owner * fix(bin): strip quoted blocked_by values during decision hold resolve (#654) * fix(bin): strip quotes on blocked_by in decision-hold resolve tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary membership test only matched middle elements. Strip surrounding quotes before matching so first and last hold ids resolve correctly. * no-mistakes(document): Refresh decision-hold regression evidence * feat(secondmate): inherit shared captain preferences (#656) * feat(secondmate): inherit shared captain preferences * no-mistakes(review): Honor shared captain data overrides * no-mistakes(review): Honor bootstrap data override registry * no-mistakes(document): Refresh shared inheritance docs * no-mistakes(document): Clarify inherited local-material docs * feat: gate local agent secret injection (#658) * feat(spawn): gate local agent secret injection * fix(spawn): align final Keychain slot * no-mistakes: apply CI fixes * test: isolate Herdr autodetect smoke sessions (#662) * test: isolate herdr autodetect smoke session * no-mistakes(review): Restored autodetect smoke gate bypass * no-mistakes(test): Harden Herdr lab provisioning * no-mistakes(document): Refresh Herdr lab docs * docs: adopt under way for active work (#666) * Revert "feat: gate local agent secret injection (#658)" (#668) This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef. * fix(pi): distinguish stale locks when arming watcher (#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> #166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * feat(herdr): add optional presentation spaces (#784) * feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately * fix(send): treat opencode busy-queued composer state as submitted (#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable * fix(spawn): require two stable reads before accepting worktree path (#765) * fix(spawn): require two stable reads before accepting worktree path The treehouse-get worktree-detection loop in fm-spawn.sh accepted the first pane_current_path read that differed from the project path, but on some tmux/WSL setups a brand-new window transiently reports a stale-but-real path before the pane actually settles into the worktree. Since that stale path is itself a real, distinct git checkout, it also passes validate_spawn_worktree's isolation check, so the loop silently recorded the wrong worktree in state/<id>.meta (and, for claude harness spawns, installed the turn-end hook there too). Require two consecutive polls to agree on the same non-project path before accepting it, using the existing inter-poll sleep as the confirmation gap so an already-settled pane isn't slowed down by an extra cycle. * fix(tests): drop unused CASE_DIR read in worktree-settle test ShellCheck SC2034: CASE_DIR is split out of the case record but never referenced; discard it with _ instead. --------- Co-authored-by: Freudator86 <tim@allesknut.de> * fix(bin): make watcher process identity immune to Linux wall-clock changes (#752) * fix(watcher): stabilize Linux process identity * no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale * fix: prevent AFK idle stalls and stale run attribution (#758) * fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts * fix(bin): allow safe teardown during watcher recovery (#750) * fix: allow safe teardown during watcher recovery * no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code * no-mistakes(document): Sync continuity-gate docs to allow teardown recovery * test: mark dynamic teardown fixture literal * no-mistakes(document): docs: add teardown to continuity gate allow list * feat(herdr): order presentation spaces while preserving focus (#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation * fix(bin): send literal config reread nudges after pushes (#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation * feat(watch): follow GitLab merge requests to merge (#797) * feat(watch): follow GitLab merge requests to merge The merge watch only understood GitHub pull requests, so a task whose deliverable is a GitLab merge request was never followed to merge. Generalize the stored poll identity from owner/repository to a provider-tagged provider/url/host/path/number record. GitLab runs mostly on self-hosted instances and its projects nest under groups at no fixed depth, so the host and the full project path are data in the record rather than constants, and every consumer rebuilds the URL from those parts and refuses any record that does not reconstruct it exactly. The GitLab state is read with plain glab, matching the GitHub path's use of plain gh, so an upstream checkout needs no extra tooling. Two things about glab were established by running it rather than assumed, because a wrong invocation here fails silently into a permanent "not merged": - glab has no field selector, and its JSON would need a JSON processor that firstmate does not require, so the state is read from glab's own field output. Only an exact "merged" wakes firstmate, so a changed format stays silent instead of reporting a merge. - glab cannot take a merge request URL the way gh can, because that form resolves through the current git repository and the watcher has none. It is addressed by project URL and merge request number instead. An absent glab produces no wake rather than a false merge, and arming refuses with a clear message since that is the one point where a missing CLI can still be reported. A GitLab task records no pr_head, which both consumers already treat as optional. The merge path still addresses GitHub only and refuses a merge request URL rather than sending it to the wrong forge. The record version moves to v2, and the existing non-executing migration rebuilds an already-armed watch from its recorded URL, so no watch is lost by upgrading. docs/gitlab-merge-watch.md records the evidence, taken against the public fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture. * no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation * no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs * fix(herdr): group projected children beneath owning parents (#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck * fix: keep local no-mistakes tests intent-targeted (#823) * fix(no-mistakes): drop full-suite local Test override Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a focused contract test so the override cannot silently return. * no-mistakes(lint): Make CI contract assertion ShellCheck-clean * feat: add canonical timed test runner (#825) * feat(test): add canonical timed suite runner and honest CI timeout Introduce bin/fm-test-run.sh as the single serial owner for selecting one script, a family, a conservative changed-file set, or the explicit complete suite, with per-script timing markers and a JSON artifact. Wire CI Behavior through the runner, raise the hang-tripwire timeout to 25 minutes, and document entry points without restoring a full-suite local no-mistakes Test command. * no-mistakes(review): Captain: fix changed selection and empty summaries * no-mistakes(review): Captain: fail closed on unmapped changed sources * no-mistakes(document): Document canonical timed test entry points * fix: surface main inventory gaps in Bearings (#830) * fix: disclose main-home orphan and unstructured inventory gaps Main Bearings could report an empty fleet while structured in-flight rows lacked meta or current backlog rows were free-form. Emit main_inventory from the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next gate, and keep meta as the only live Underway source. * no-mistakes(document): Document Bearings inventory-integrity projection * no-mistakes: apply CI fixes * feat: add bounded concurrent test isolation proof (#832) * feat: add concurrent test isolation proof for Phase 2 Prove an audited portable candidate set passes under concurrent workers with private mode-0700 temp roots, without enabling production CI sharding or fm-test-run --jobs. * no-mistakes(review): Pin isolation proof to audited candidate manifest * feat: guard against missed secondmate reports (#834) * feat(secondmate): parent-owned guards for missed status reports Marked parent-to-secondmate requests now create a durable pending-reply expectation with a privacy-safe correlation id before delivery. Transport success never resolves it; only a correlated parent status or document pointer does. After a completed turn with no report, the parent sends one recovery repost and escalates once if that turn is also missed, without scraping the secondmate conversation or looping. * no-mistakes(review): Deduplicate wrong-home pending-reply sightings * no-mistakes(review): Harden pending-reply recovery and escalation guards * no-mistakes(review): Bound pending-reply backend polling * no-mistakes(review): Cache pending-reply status scans * no-mistakes(review): Protect undelivered pending-reply records from scans * no-mistakes(review): Close pending-reply delivery durability gaps * no-mistakes(review): Separate pending-reply transport outcomes * no-mistakes(review): Escalate stalled pending-reply deliveries once * no-mistakes(review): Resolve attempted deliveries from correlated reports * no-mistakes(review): Resolve late reports after delivery escalation * no-mistakes(document): Document pending-reply grace and ownership * no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings * feat: require pinned real-Herdr CI coverage (#838) * feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat: shard portable tests and add bounded local parallelism (#841) * feat: shard portable CI tests after isolation proof Balance the Phase 2 proven-isolated set into two LPT portable parallel lanes from Phase 1 timing evidence, keep stateful work in a required portable serial lane, exclude real Herdr to its dedicated required lane, and prove complete inventory coverage with a deterministic guard. Add bounded local --jobs only for the proven set, per-lane timing plus aggregate artifacts, and reduce the interim portable hang tripwire now that the serial remainder owns the long wall-clock path. * no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling * no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests * no-mistakes(document): Document portable sharding and timing aggregation * no-mistakes: apply CI fixes * fix: block primary-session delegation outside the fleet (#854) * feat: fence primary-session delegation outside the fleet A firstmate primary that delegates through Claude Code's built-in delegation tools creates work with no state/<id>.meta. Because fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits silently at zero, such work does not merely go unsupervised: it makes the whole guard stack structurally inert, and it dies with the primary session. On 2026-07-22 that cost two workers mid-flight and left supervision down for 73 minutes unnoticed. Layer 1, the primary fix: a permissions.deny list in .claude/settings.json removes the 18 delegation, scheduling, worktree, and task-tracking tools from the model's schema, so they are never offered. This is removal rather than interception, so there is no call to intercept and no fail-open path. The list is flat and in one file so its width stays reviewable; the captain owns that width. Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open against tools that do not exist yet, and permissions.allow is a pre-approval list rather than an availability list, so there is no fail-closed allowlist to use instead. This backstop classifies the tool NAME by shape rather than against a fixed list, so a delegation tool that ships before the deny list is updated is still refused. It excludes mcp__* names and observe-or-stop operations, scopes itself to a genuine primary home via the shared fm_primary_scope_matches predicate so a crewmate's task worktree is unaffected, and offers one deliberate FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch. Verified live against Claude Code 2.1.217, including a deny-key A/B with a nonsense-name control, layer 2 denying an un-denied Workflow call, the same call allowed in a linked worktree, and the escape hatch. Corrects a prior finding: both Task and Agent work as deny keys, so both are pinned. Codex 0.144.1 verified to expose no delegation tool; grok, opencode, and pi are inspected and documented as not wired because those binaries are absent from this host and the repo requires live validation before trusting a harness hook. Evidence in docs/subagent-guard.md. * no-mistakes(review): Ship scoped Claude delegation guard * no-mistakes(test): Ship Claude delegation deny list * no-mistakes(document): Clarify PreToolUse guard ownership * no-mistakes(lint): Keep Claude deny list local * fix: install tasks-axi in portable CI shards (#866) Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged. * feat(bin): make dispatch profiles quota aware (#867) * feat: make dispatch profiles quota aware * no-mistakes(review): Fix quota window and Grok product scoping * no-mistakes(document): Document implicit quota-aware dispatch accurately * Add built-in ahoy recap skill (#873) * fix: preserve trustworthy Bearings data in partial snapshots (#875) * fix: preserve mixed Bearings projections * no-mistakes(review): Enforce strict invalidity precedence for partial snapshots * no-mistakes(review): Enforce ownership for unknown child metadata * no-mistakes(document): Document partial structured Bearings projections * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat(pi): add session-local calm mode (#884) * Add session-local Pi calm mode * no-mistakes(review): Preserve Pi HTML exports during calm mode * no-mistakes(review): Preserve calm exports across submit bindings and share * no-mistakes(document): Document calm-mode feasibility across supported harnesses * fix(pi): prevent redundant watcher re-arms (#885) * fix(pi): limit watcher arm tool to recovery * no-mistakes(review): Strengthen Pi live re-arm regression coverage * no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming * fix(pi): clean up Calm transcript rendering (#895) * fix(pi): clean up Calm transcript rendering * no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs * no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations * no-mistakes(review): Restore Calm rows received while active * no-mistakes(review): Preserve diagnostics during Calm restoration * no-mistakes(document): Clarify Calm transcript behavior and injection paths * fix: execute every PR body compliance event (#898) * fix: execute every PR body compliance event * no-mistakes(document): Document independent PR compliance events * fix: exclude operational injections from ahoy boundaries (#899) * fix: distinguish operational input in ahoy * no-mistakes(review): Handle legacy Ahoy operational boundaries * no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions * no-mistakes(document): Document Ahoy operational marker ownership * no-mistakes(lint): Suppress intentional literal fixture lint warnings * fix: canonically classify operational inputs across harnesses (#909) * fix: type canonical operational inputs * no-mistakes(document): Correct canonical operational-input documentation ownership * fix: avoid generic secondmate start acknowledgements (#926) * fix: avoid generic secondmate acknowledgements * no-mistakes(document): Document sparse secondmate acknowledgement behavior * no-mistakes: apply CI fixes * fix(pi): make calm mode persistent and gapless (#927) * fix(pi): preserve calm presentation across sessions * no-mistakes(review): Fix Calm home fallback persistence * no-mistakes(document): Clarify Calm gapless and export contracts * no-mistakes: apply CI fixes * fix(watch): retire merged PR polls after durable notification (#932) * fix: retire merged PR polls after notification * no-mistakes(review): Decouple PR retirement recovery from template updates * no-mistakes(review): Recover pending PR retirements before poll migration * no-mistakes(document): Document merged PR poll retirement contracts * fix: refine scout intake and parallel dispatch (#934) * Clarify intake evidence and overlap handling * no-mistakes(review): Align scout guard with intake classification * no-mistakes(document): Clarify scout documentation and intake ownership * fix(pi): prevent duplicate assistant replies in Calm (#936) * fix(pi): preserve operational follow-up semantics in Calm * no-mistakes(document): Correct Calm operational-row visibility documentation * perf(bin): shrink the ShellCheck source graph (#939) * perf(lint): shrink shell source graph * no-mistakes(review): Ensure lint workers terminate fully on cancellation * no-mistakes(document): Repair stale lint documentation ownership * fix(pi): remove Calm hidden-block gaps (#942) * fix(pi): remove Calm hidden-block gaps * no-mistakes(review): Validate Calm geometry against current viewport * no-mistakes(review): Synchronize Calm geometry checks with reload completion * fix: enforce contract boundaries for ask-user findings (#945) * fix: escalate ask-user contract expansion * no-mistakes(document): Point project management to authority owner * docs: prefer direct operational paths (#946) * fix(pi): hide operational user rows in Calm mode (#948) * fix(pi): hide Calm operational user rows * no-mistakes(review): Narrow Calm operational input suppression * no-mistakes(review): Avoid Calm replay classifier subprocesses * no-mistakes(document): docs: point Pi verification to Calm owner * fix: relaunch missing second mates at session start (#950) * fix(session-start): relaunch missing second mates * fix(test): detect completed parallel workers * no-mistakes(review): Isolate session-start recovery test cleanup * no-mistakes(review): Complete backend-safe secondmate session recovery * no-mistakes(review): Resolve Zellij task ownership before recovery * no-mistakes(review): Recover relocated Zellij ghost tabs safely * no-mistakes(review): Restore conservative Zellij recovery boundary * no-mistakes(review): Reject malformed tmux recovery targets * no-mistakes(document): Align secondmate recovery documentation * no-mistakes: apply CI fixes * fix(herdr): reclaim resumed task projections after restart (#967) * fix(herdr): reclaim resumed task projections safely * no-mistakes(review): Enforce safe Herdr reclaim close boundaries * no-mistakes(document): docs: clarify Herdr restart projection contract * Teach Ahoy to surface open decisions (#968) * Require shipshape routine acknowledgement (#969) * docs: separate current guidance from verification evidence (#994) * docs: separate current guides from verification * no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence * fix: preserve Claude watcher continuity across Stop hooks (#997) * feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm Claude primaries (main home and marked secondmate homes) no longer depend on the model remembering to re-arm the watcher after each wake. A tracked Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s) fires on every turn end, claims one home-scoped single-flight owner, foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and translates an actionable close or typed watcher failure into exactly one exit-2 rewake. The hook scopes to genuine primary checkouts, requires the session lock to be held by its own harness ancestor, stays inert while AFK owns triage or the home is idle, and hands AFK transitions mid-cycle to the daemon without rewaking. The synchronous turn-end guard gains a --claude cooperative mode: it ignores stop_hook_active (true on every post-continuation stop, which is what re-opened the 2026-07-21 blind window), waits briefly for a watcher health proof, a live auto-arm owner claim, or a fresh rewake epoch, and re-blocks only when the auto-arm genuinely failed to establish - bounded to 3 consecutive blocks per session, safely below Claude Code's 8-block override, then a degraded allow with a visible systemMessage. Codex keeps the previous one-block loop guard byte-identically, and Pi, OpenCode, and Grok adapters are untouched. Continuity PreToolUse gate and durable wake queue are preserved; the gate's recovery guidance now names the Stop-owned re-arm and reserves manual background arms for auto-arm failure. Claude supervision protocol, harness-adapters facts, architecture, configuration, and continuity docs updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218 contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout process-group kill, 8-block cap, interactive non-stall) and the 2.1.219 product live E2Es. Regression matrix: hermetic tests cover scope, identity, AFK, need, single-flight, translation, guard cooperation, budget, and registration; the new live E2E proves two full tokenless auto-arm rewake cycles with zero model arm commands; Pi and OpenCode Option B live E2Es pass unchanged. * no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop * no-mistakes(review): Remove unsupported Claude contract-lab verification claims * no-mistakes(document): Update Claude auto-arm continuity documentation * fix(herdr): clean stale projections at session start (#996) * Clean stale Herdr projections at session start * no-mistakes(document): Document stale Herdr session-start projection cleanup * no-mistakes(review): Enforce locked exact Herdr projection cleanup * no-mistakes(review): Fail closed on unverified session lock ownership * no-mistakes(review): Serialize session lock acquisition atomically * no-mistakes(document): Align session-start and Herdr cleanup documentation * no-mistakes(document): Generalize lock-refusal diagnostics * no-mistakes(lint): Avoid reserved keyword in concurrency test * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: recover Claude supervision without watcher-status gate (#1001) * fix: recover Claude supervision at session start * fix: remove Claude watcher-status command gate * no-mistakes(document): docs: remove stale continuity gate references * fix: make quota-aware profile selection agent-owned (#1018) * Replace quota dispatch selector instructions * no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection * fix(bin): remove vestigial dispatch selector (#1026) * remove vestigial dispatch selector * no-mistakes(review): Synchronize isolation proof and portable shard evidence * no-mistakes(review): Correct shard history and proof archive date * no-mistakes(review): Remove reintroduced selector documentation reference * no-mistakes(document): Remove stale dispatch strategy documentation * docs(agents): drop superseded interim quota-window rule (#1039) quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per provider, so the successor named in the interim rule has landed and the rule's own removal condition is satisfied. Keep the ownership clause so quota-axi remains the single owner of how model or product windows relate to bounding account windows, and drop the interim weakest-headroom instruction. The unknown-semantics case is already covered by the existing requirement to stop and report a candidate whose applicable quota data or interpretation cannot be established. Drop the matching assertion phrase from tests/fm-instruction-owners.test.sh; the retained ownership phrase still asserts. * fix(tmux): scope busy detection and recognize current Claude turns (#1049) * fix(tmux): scope Claude busy detection by harness * no-mistakes(review): Separate verified and fallback busy signatures * no-mistakes(test): Scope busy signatures to supplied harnesses * no-mistakes(document): Document harness-scoped busy detection * feat: add verified Kimi crewmate adapter (#1047) * Add verified Kimi crewmate harness adapter * no-mistakes(review): Scope Kimi moon detection to spinner lines * no-mistakes(review): Match only complete Kimi spinner rows * no-mistakes(review): Resolve Kimi binary portably before pane creation * no-mistakes(document): Align Kimi adapter documentation * no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override * Fix Kimi busy spinner detection * no-mistakes(review): Recognize Kimi session-lock ancestry and holders * no-mistakes(review): Scope pending-reply Kimi busy detection by harness * no-mistakes(document): Correct Kimi spinner capture documentation * no-mistakes(document): Clarify optional Kimi spinner whitespace * no-mistakes(lint): Silence intentional pending-reply test stub warnings * test: align rebased Kimi busy fixtures * no-mistakes: apply CI fixes * Reconcile Kimi busy detection after per-harness scoping * no-mistakes(review): Clarify observed Kimi spinner whitespace contract * no-mistakes(document): Clarify Kimi harness documentation * fix: harden Kimi submission and spinner matching (#1058) * fix kimi pointer submission and spinner conformance * no-mistakes(review): Preserve Kimi submit target ownership guard * feat(bin): add guarded Kimi turn-end wake (#1059) * Add guarded Kimi turn-end hook * no-mistakes(review): Require jq before installing Kimi turn-end hook * no-mistakes(review): Expose jq inside isolated Kimi test fixtures * no-mistakes(review): Preserve Kimi config boundaries during hook removal * no-mistakes(review): Document Kimi removal newline safeguard * no-mistakes(document): Document Kimi shared-home preservation * fix(tmux): classify bordered composers across all rows (#1066) * Fix structural tmux composer reading * Verify Calm compatibility with Pi 0.82 * no-mistakes(review): Harden structural composer classification boundaries * no-mistakes(review): Refresh composer and Kimi regression fixtures * no-mistakes(review): Fail closed on unbounded composer edges * no-mistakes(review): Enforce aligned composer geometry safely * no-mistakes(review): Make composer ambiguity locale-safe * no-mistakes(review): Preserve ambiguity through composer submission * no-mistakes(review): Carry composer proof through retries * no-mistakes(document): Document structural tmux composer delivery guarantees * no-mistakes: apply CI fixes * feat(bin): add verified pi-signed runtime adapter (#1145) * feat: add verified pi-signed adapter * no-mistakes(review): Correct pi-signed maintainer verification date * no-mistakes(review): Correct remaining pi-signed verification dates * no-mistakes(review): Preserve authoritative pi-signed runtime identity * no-mistakes(document): Document pi-signed shared adapter semantics * no-mistakes: apply CI fixes * fix(pi): rearm watcher across session transitions (#1166) * fix(pi): rearm watcher across same-process session transitions Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement as well as terminal quit. The primary watcher extension latched a module-level stopping flag on every shutdown, so a replacement session in the same process could not arm monitoring until Pi restarted. Own arm authority per session generation so only the active live generation may start, stop, or rearm the child. Replacement sessions can arm again without restarting Pi, stale prior-generation callbacks cannot mutate the active cycle, and real quit still blocks late rearm. * no-mistakes(review): Preserve Pi generation isolation and exit cleanup * no-mistakes(document): Correct Pi watcher transition documentation * feat: route crew dispatch using quota-window pace (#1172) * Consume quota-axi pace signals in dispatch profile array selection. Add quota-array-dispatch as the single owner of the pace-aware candidate choice, keep AGENTS.md to the intake boundary and load trigger, and cover the acceptance cases with sanitized schemaVersion 3 fixtures. * no-mistakes(review): Stop and report genuine quota dispatch ties * no-mistakes(document): Document quota pace freshness and uncertainty * fix: adapt Grok Stop continuation and harden endpoint cleanup (#1171) * fix(grok): adapt Stop continuation to runtime capability * no-mistakes(review): Reject ambiguous Grok Stop payloads * no-mistakes(review): Reject duplicate Grok fields and accept spaced tmux sessions * no-mistakes(review): Enforce exact tmux cleanup selectors * no-mistakes(test): Fix historical tmux fixture and validate Grok Stop * no-mistakes: apply CI fixes * fix: restore stock macOS Bash 3.2 brief scaffolding (#1093) * fix(brief): make DOD scaffolding parse-safe on stock macOS Bash 3.2 fm-brief.sh built each Definition-of-done block and the not-enabled Herdr declaration with `VAR=$(cat <<EOF ... EOF)`. On Bash 3.2 (macOS /bin/bash) the lexer scans for the command substitution's closing `)` textually and tracks quote state through the heredoc body, so a single apostrophe, unbalanced quote, or unbalanced paren in that prose breaks parsing of the whole script. Every ship-brief scaffold (no-mistakes, direct-PR, local-only) failed with `unexpected EOF while looking for matching )`. Bash 4+ parses it fine, so the breakage stayed invisible everywhere except stock macOS. Replace all four command-substitution heredocs with `IFS= read -r -d '' VAR <<EOF || true`. That removes the `$(...)` wrapper and the entire defect class regardless of future prose, and preserves the variable expansion the direct-PR and local-only bodies need. `read` keeps the heredoc's trailing newline that `$(...)` used to strip, so trim one newline to keep every generated brief byte-identical to prior output. Guard the structure, not one historical phrase: a new test rejects any heredoc nested in a command substitution anywhere in fm-brief.sh, where the old assertion pinned a single apostrophe phrase and so missed the reintroduction. Extend the stock-macOS Bash CI job from parsing one script to the whole maintained shell surface (bin/*.sh, bin/backends/*.sh, tests/*.sh), matching bin/fm-lint.sh's canonical file set so parse scope and lint scope cannot drift apart. * no-mistakes(review): Captain: harden Bash structure and inventory guards * no-mistakes(document): Align stock macOS Bash contributor checks * no-mistakes(lint): Suppress deliberate SC2016 literal fixture warnings * test: stabilize tmux teardown conformance baseline (#1209) * fix(test): pin teardown tmux baseline to historical kill selectors merge-base HEAD main collapses to HEAD after the exact-selector change lands on the default branch, so the old teardown fixture was accidentally exercising current exact targets. Resolve a content-historical permissive tmux adapter from first-parent history and force that post-squash topology inside the conformance case so main and feature branches keep the same old-vs-new contract. * no-mistakes(lint): Suppress intentional literal-pattern ShellCheck warnings * docs: slim quota-array-dispatch to the pace selection core (#1197) Cut the runtime skill to the compact pace-aware selection procedure plus minimum owner pointers. Keep every distinct decision rule and move expanded acceptance scenarios to deterministic fixture ownership assertions. Size: 170/1374/10187 -> 63/544/4068 (about 63%/60%/60% reduction). * feat(bin): inherit backend config into secondmate homes (#1219) * Inherit config/backend into secondmate homes with deliberate-override preservation Add backend to the shared inheritable config allowlist so launch, locked bootstrap, and config-push converge a primary pin into secondmate homes as each home local future-spawn default. Track last-inherited bytes in a private state provenance marker so deliberate per-home overrides survive present and absent primary convergence, keep --backend and FM_BACKEND stronger, and extend the existing inheritance tests plus docs and skill claims. * no-mistakes(review): Preserve equal unprovenanced backend overrides * no-mistakes(review): Preserve symlink overrides and verify spawn precedence * no-mistakes(review): Snapshot backend inheritance for consistent provenance * no-mistakes(review): Simplify backend inheritance to primary-authoritative convergence * no-mistakes(document): Document inherited backend override preservation * fix: restore primary-authoritative backend inheritance after document regression The document step reintroduced provenance and deliberate per-home override semantics after review had simplified config/backend to plain primary-authoritative allowlist membership. Restore the primary-always-wins path: present overwrites, absent removes, no provenance marker, and docs/tests match that contract. * no-mistakes(review): Add divergent backend precedence regression fixtures * no-mistakes(document): Document backend inheritance contract * fix(pi): remove Calm's upper version ceiling (#1226) * fix(pi): remove Calm's exclusive Pi upper-version ceiling tests/fm-calm-pi-extension.test.sh gated on a closed PI_COMPAT_VERSIONS allowlist ("0.81.1 0.82.0") that refused any other installed Pi, and docs described that range as "supported" rather than verified evidence. The Calm CHANGELOG shows no API introduced at either version, so there is no evidence for a real minimum; the presentation adapters already probe the exact method they patch rather than checking a version. Replace the allowlist with dated version evidence that never rejects a newer Pi, and make each presentation adapter degrade independently with a diagnostic if a future Pi removes its API, instead of the whole Calm extension failing to load. Rewrite the feasibility doc's "Pi 0.81.1 through 0.82.0" phrasing to state it as verified evidence, not a ceiling. * no-mistakes(review): Probe missing Calm adapter exports safely * no-mistakes(document): Document Calm's unbounded Pi compatibility * fix(bin): allow session-local todo tools in the subagent guard (#1204) * fix(guard): allow session-local todo tools in the primary The delegation-shape guard denied TaskCreate and TaskUpdate because their normalized names contain the `task` stem. Those tools write only the harness's session-local todo list, which has no executor: it spawns no agent, allocates no worktree, registers no schedule, and starts nothing that outlives the session. That is not the unaccounted work the guard exists to stop, so the stem match was a false positive, and the deny text told the primary to run bin/fm-brief.sh and bin/fm-spawn.sh to create a todo entry. Add a separately-reasoned PLAN_ONLY_TOOLS exact-name exclusion rather than widening OBSERVE_ONLY_TOOLS, whose documented contract is tools that only observe or stop existing work. Both lists stay exact-name so neither can widen by substring. Tests cover the two allowed names and six near-miss names that a substring or shortened-stem widening would release; both mutations were watched red. * no-mistakes(review): drop session-local todo tools from recommended deny list * no-mistakes: apply CI fixes * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid (#1206) * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid fm_harness_ancestry_pid() previously returned the first ancestor process whose command matched a verified harness name. Claude Code's Stop hook fires as a bg-spare worker several levels below the session's actual lock-owning claude process (hook shell -> claude bg-spare -> claude bg-pty-host -> claude -> claude(lock)), so the first match was the bg-spare worker, not the lock owner. fm_session_lock_owned_by_self() then never matched state/.lock, and the Claude Stop auto-arm silently treated its own primary session as an unrelated live owner and never armed the watcher. The walk now keeps going past a claude-named match, looking for a still more ancestral claude-named match, and stops the instant a non-match follows an already-found match (bounding it to a contiguous run rather than the literal ancestry top, so an unrelated claude-named process further up the real process tree is never mistaken for part of this session's own nested chain). Every other harness keeps the original first-match-wins behavior, since e.g. Pi's shared signed-wrapper ancestry actually holds the session at the inner engine pid, not an outer wrapper pid. Hop limit raised from 8 to 16 to cover the deeper bg-spare chain. * no-mistakes(review): Add nested-claude-ancestry regression test; fix nudge doc depth claim * no-mistakes: apply CI fixes * fix: conferma l'avvio del watcher su Windows/MSYS (#1212) * fix: confirm watcher startup on MSYS * no-mistakes(review): gate MSYS arm ready timeout, cache uname, harden locale test * no-mistakes(review): validate OpenCode ready timeout, make uname cache internal * fix(spawn): forward CLAUDE_CONFIG_DIR to claude crewmates (#1195) * fix(spawn): forward firstmate's CLAUDE_CONFIG_DIR to claude crewmates Crewmate panes are created by a long-lived tmux/herdr daemon that does not inherit firstmate's current environment. When firstmate runs under a non-default CLAUDE_CONFIG_DIR (for example a work-vs-personal subscription split), a bare `claude` in the crewmate pane fell back to the default ~/.claude store and launched unauthenticated, blocking the crewmate before it could do any work. fm-spawn now prefixes the claude launch with firstmate's own resolved CLAUDE_CONFIG_DIR when set, so the crewmate uses the same credential/config store firstmate is authenticated with. An unset value is the single-store default and adds no prefix; non-claude harnesses are unaffected. Adds three tests in fm-spawn-dispatch-profile.test.sh (forwarded-when-set, omitted-when-unset, non-claude-ignored) and pins CLAUDE_CONFIG_DIR in the test helper so launch assertions no longer depend on the developer's environment. * no-mistakes: apply CI fixes * fix: preserve dispatch identity across authentication checks (#1233) * fix: preserve dispatch harness identity * no-mistakes(review): Fix Grok counterfactual tuple validation * no-mistakes(document): Scope dispatch authentication to selected tuple * fix: restore dispatch instruction budget * no-mistakes(review): Scope dispatch authentication after candidate selection * fix(bin): normalize relative durable paths (#1256) * fix(bin): handle dash-leading harness process names (#2) * fix: handle dash-leading harness process names * no-mistakes(review): Make dash-leading harness regression hermetic * fix: preserve secondmate reply routes across relative homes Resolve relative home, data, and state inputs before durable charter generation, and fail when caller-relative directories cannot be resolved. Use absolute paths at the related spawn, AFK daemon, and X-mode cross-process handoffs so later processes cannot reinterpret them from another working directory. * no-mistakes(review): Preserve absolute overrides and normalize relative durable paths * no-mistakes(review): Normalize relative home before deriving durable paths * no-mistakes(document): Document relative durable-path normalization * no-mistakes(review): Captain: Ignore inherited CDPATH during relative path normalization * no-mistakes(lint): Fix empty CDPATH assignments for ShellCheck * refactor(skills): make Bearings chat-only by default (#1136) * Add internal status skill * no-mistakes(document): register /status skill in documentation-audiences inventory * no-mistakes(lint): replace grep|wc -l with grep -c in status skill test * test: silence literal status skill patterns * Refactor bearings default to chat-only --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> * Clarify follow-up routing during validation (#1277) * fix: honor concrete approval for project operations (#1272) * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * no-mistakes(review): Align project removal preflight with approved exception * no-mistakes(document): Align project removal documentation with approved exception * fix: restore removal test byte-for-byte and preserve the default sentence tests/fm-instruction-owners.test.sh had been changed to assert different text; restore it byte-for-byte to origin/main. project-management SKILL.md's Remove section now keeps the exact default "Never issue a raw removal command from Firstmate." sentence that test still asserts, immediately followed by the already-approved captain-operation-or-scope exception, so the default and the exception both stay explicit and consistent. * no-mistakes(document): Align project-write boundary documentation * fix(skills): route new project intake through secondmate scopes (#1275) * Route project intake through secondmate scopes * no-mistakes(test): Guard all main-home project registry mutations * no-mistakes(document): Consolidate secondmate routing documentation * no-mistakes: apply CI fixes * Restore new-project routing scope * no-mistakes(document): Clarify secondmate routing for new-project intake * no-mistakes: apply CI fixes * fix: scope validation corrections by accepted behavior (#1281) * fix: scope validation corrections by accepted behavior * no-mistakes(review): Classify stale delivery evidence as an autonomous correction * test: replace source assertions with behavioral coverage (#1282) * test: remove source-content assertions * no-mistakes(review): Replace source assertions with runtime behavior coverage * no-mistakes(review): Isolate Kimi task temp runtime coverage * no-mistakes(document): Refresh test cleanup documentation * no-mistakes: apply CI fixes * fix(watch): escalate busy workers with no completed turn (#1286) * fix(watch): bound how long a busy pane may run with no completed turn A busy pane (backend busy state or the harness's rendered footer) was unconditional, unbounded proof of liveness in every escalation path, so a hung foreground tool call behind a busy signature could run for hours undetected (2026-07 hibit-agent-focus-nonsteal-r1 incident: a catastrophic- backtracking regex hung one bash call for 25h behind an unchanging "Working..." footer). FM_BUSY_TURN_MAX_SECS (default 3600s) now bounds how long a busy pane may run with no completed turn (state/<id>.turn-ended, or its spawn record before any turn has completed). Past the bound, busy_turn_over_age routes the pane through the existing wedge_timer_check, reusing the identical stale reason, escalation counter, and demand-deep-inspection marker for human inspection only - never an automatic interrupt, signal, or restart of the worker or its tool process. A completed turn resets the age. Reproduced end-to-end against the real installed Pi TUI: a foreground `sleep 999999` bash call with no timeout renders the actual busy footer, and two captures ~15s apart show the elapsed counter changing the pane hash while the same turn stays unfinished. Running the pre-fix watcher against the real captures showed it never starts a wedge timer no matter how long the pane stays busy; the fixed watcher starts and escalates the timer through the same mechanism, while the real hung process remained untouched and alive throughout. * no-mistakes(review): fix: parse enriched AFK stale reasons * no-mistakes(review): fix: preserve enriched wedges during AFK supervision * no-mistakes(review): fix: route all enriched AFK wedges * no-mistakes(document): Clarify busy-turn age supervision documentation * fix(gitignore): ignore config/ as a directory, not by exact filename (#1261) A name-by-name list of config/ entries silently stops ignoring any new or home-local file placed there, which makes the working tree read as dirty and blocks guarded sync paths that refuse to touch a dirty home. AGENTS.md already documents config/ as captain-private and gitignored as a category; this makes .gitignore match that contract. * fix(tests): replace source-content .gitignore assertion w…
kirangathani
added a commit
to kirangathani/firstmate
that referenced
this pull request
Aug 2, 2026
* feat: establish instruction ownership foundation (kunchenguid#619) * Add instruction owners foundation * no-mistakes(document): Refresh project-management owner pointers * fix: compress Firstmate contract and enforce delivery rigor ownership (kunchenguid#626) * docs: compress firstmate operating contract * docs: make delivery rigor single-owner PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion. * no-mistakes(review): Honor configured merge authority across faster delivery paths * no-mistakes(document): Align docs with compressed operating contract * feat: add durable captain decision holds (kunchenguid#593) * Add durable captain decision holds * no-mistakes(review): Validate decision hold retries and origin paths * no-mistakes(review): Enforce durable decision lifecycle boundaries * no-mistakes(review): Harden decision display and partial retry recovery * no-mistakes(test): Update scout teardown fixtures for decision inventory * no-mistakes(document): Align decision lifecycle and scout teardown documentation * no-mistakes: apply CI fixes * no-mistakes(review): Reconcile terminal decision holds * no-mistakes(document): Align captain decision-hold documentation * fix(bin): harden PR check artifacts (kunchenguid#556) * fix: harden PR check artifacts * fix: close PR check migration gaps * fix: close PR check retry gaps * fix: clarify migration outcomes and ESM boundary * fix: keep failed migrations authoritative * test: use inert PR validation fixtures * no-mistakes(review): Reserve noncanonical PR quarantine namespace * no-mistakes(review): Prevalidate final PR-check teardown artifacts * no-mistakes(review): Preserve X metadata and validate teardown IDs * no-mistakes(review): Initialize migration state before watcher exclusion * no-mistakes(review): Isolate failed poll migrations from bootstrap recovery * no-mistakes(review): Allow safe polling during incomplete private repairs * no-mistakes(review): Authenticate watcher checks at execution time * no-mistakes(review): Preserve custom checks with hash-bound registration * no-mistakes(review): Clean custom check snapshots on watcher signals * no-mistakes(review): Stop watcher checks promptly on signals * no-mistakes(review): Terminate watcher check groups before cleanup * no-mistakes(document): Correct stale X-mode watcher documentation * fix: drain returned watcher check groups * no-mistakes(review): Harden quarantine links and recover validated replacement polls * no-mistakes(review): Preserve X mode across shim version transitions * no-mistakes(review): Refresh legacy X shims before marker short-circuits * no-mistakes(document): Correct persisted PR-check artifact documentation * no-mistakes(document): Correct stale PR-check documentation * fix: bind PR poll repair provenance * no-mistakes(review): Enforce single-link ownership for custom check artifacts * no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs * no-mistakes(review): Separate task creation and legacy teardown validation * no-mistakes(review): Restore safe legacy operations and teardown validation * no-mistakes(review): Disambiguate migration obligations and preserve legacy retries * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits * no-mistakes(document): Document private poll artifact safety contracts * no-mistakes(lint): Suppress intentional literal-dollar lint finding * fix: migrate historical X poll identity * fix: harden PR check artifacts * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * fix: migrate historical X poll identity * no-mistakes(review): Harden X-mode artifact publication against symlink corruption * no-mistakes(review): Guard X artifact publication * no-mistakes(review): Enforce private X artifact reads * no-mistakes(test): Fix backend compatibility fixture dependencies * no-mistakes(document): Refresh PR-check documentation * no-mistakes(lint): Remove unused x-mode test locals * no-mistakes: apply CI fixes * fix(bin): compact session-start backlog digest (kunchenguid#636) * fix: compact session-start backlog digest * no-mistakes(test): Fix legacy backend fixture helper * no-mistakes(test): Fix watcher exit wait helper * no-mistakes(document): Document compact backlog digest * fix: dedupe stale watcher guard banners (kunchenguid#637) * fix: dedupe stale watcher guard banner * no-mistakes(review): Keep read-only guard state nonmutating * no-mistakes(document): Clarify stale watcher docs * fix(bin): balance bearings landed baseline (kunchenguid#640) * fix: balance bearings landed defaults * no-mistakes(document): Document balanced landed baseline * no-mistakes: apply CI fixes * fix: clarify captain-facing translation contract (kunchenguid#644) * docs: clarify captain-facing translation contract * no-mistakes(review): Restore runtime fallback mandate * no-mistakes(document): Align Bearings translation wording * fix(bin): make bootstrap output and nudges deterministic (kunchenguid#646) * fix: make bootstrap nudges deterministic * no-mistakes(review): Honor state override for bootstrap nudges * no-mistakes(review): Update benign bootstrap documentation labels * no-mistakes(review): Validate bootstrap nudge retry markers * no-mistakes(document): Align bootstrap nudge documentation * no-mistakes: apply CI fixes * docs(secondmate-provisioning): clarify concise registry ownership (kunchenguid#649) * Clarify concise secondmate registry contract * no-mistakes(review): Expand secondmate registry boilerplate coverage * no-mistakes(document): Point route docs to owner * fix(bin): strip quoted blocked_by values during decision hold resolve (kunchenguid#654) * fix(bin): strip quotes on blocked_by in decision-hold resolve tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary membership test only matched middle elements. Strip surrounding quotes before matching so first and last hold ids resolve correctly. * no-mistakes(document): Refresh decision-hold regression evidence * feat(secondmate): inherit shared captain preferences (kunchenguid#656) * feat(secondmate): inherit shared captain preferences * no-mistakes(review): Honor shared captain data overrides * no-mistakes(review): Honor bootstrap data override registry * no-mistakes(document): Refresh shared inheritance docs * no-mistakes(document): Clarify inherited local-material docs * feat: gate local agent secret injection (kunchenguid#658) * feat(spawn): gate local agent secret injection * fix(spawn): align final Keychain slot * no-mistakes: apply CI fixes * test: isolate Herdr autodetect smoke sessions (kunchenguid#662) * test: isolate herdr autodetect smoke session * no-mistakes(review): Restored autodetect smoke gate bypass * no-mistakes(test): Harden Herdr lab provisioning * no-mistakes(document): Refresh Herdr lab docs * docs: adopt under way for active work (kunchenguid#666) * Revert "feat: gate local agent secret injection (kunchenguid#658)" (kunchenguid#668) This reverts commit c27135c. * fix(pi): distinguish stale locks when arming watcher (kunchenguid#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (kunchenguid#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (kunchenguid#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (kunchenguid#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (kunchenguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (kunchenguid#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> kunchenguid#166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (kunchenguid#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (kunchenguid#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (kunchenguid#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (kunchenguid#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (kunchenguid#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (kunchenguid#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (kunchenguid#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (kunchenguid#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * test: give merge-success security fixtures a gate-verifiable project fm-pr-merge.sh gates merges on fm-assert-tests-kept.sh, which resolves a real project repo and task worktree from the task meta. The upstream security fixtures predate the gate and used bare or missing paths, so every expected-successful merge was refused with 'could not verify'. Add write_gate_project and scope the legacy-loop gate worktree to the merge step so both teardown invocations still exercise the missing-worktree path. * test: mask node beyond fakebin so MISSING-node tests survive system node test_output_ordering_diagnostics_lead and test_composition_invokes_real_scripts forced a MISSING: node diagnostic only by deleting the fakebin node stub, which silently assumed node is absent from the fallback BASE_PATH (/usr/bin:/bin:/usr/sbin:/sbin). That holds on GitHub runners but breaks on any host where apt/nodesource installed /usr/bin/node: command -v node succeeds, bootstrap correctly reports nothing missing, and both assertions fail. Reuse the existing tmux masking idiom from test_herdr_backend_diagnostics_follow_real_session_start: a shared write_node_mask helper emits a BASH_ENV file overriding command -v node to fail regardless of PATH, and both tests pass it on their run_session_start call while keeping the fakebin removal. The assertions themselves are unchanged; only how node is made to look absent is. * fix(tests): pin fixture git identity in two tests that made bare commits tests/fm-pr-check-security.test.sh's write_gate_project and tests/fm-continuity-pretool-check.test.sh's primary-checkout fixture both ran bare git commit without fm_git_identity or an inline -c identity, so they passed on any machine with a global git config and failed exit 128 (empty ident) on a clean CI runner. Call fm_git_identity after sourcing lib.sh, matching the convention the other nineteen callers use. Audited all 86 test files for the same latent defect; these two were the only instances. Full suite passes under a neutralized-identity environment (GIT_CONFIG_GLOBAL=/dev/null, identity vars unset) and normally. --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Johans Ballestar <47162770+Ballestar@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com>
This was referenced Aug 3, 2026
levelupself
added a commit
to levelupself/firstmate
that referenced
this pull request
Aug 3, 2026
* fix: prevent no-mistakes gate agents from driving the fleet (#518)
* feat: contain no-mistakes gate agents from driving the fleet
Add bin/fm-gate-refuse-lib.sh, sourced at the top of fm-spawn/fm-send/
fm-teardown before any fleet mutation. It fails closed when NO_MISTAKES_GATE
is set, and via an unspoofable git-common-dir backstop when invoked from a
no-mistakes gate worktree (.no-mistakes/repos/*.git) even with the marker
unset. A normal firstmate session has neither signal and is unaffected.
Set disable_project_settings: true in the tracked .no-mistakes.yaml so the
installed pipeline neutralizes gate agents' project instructions for this repo
(trusted-only, honored from the default branch).
firstmate's own suite runs from a gate worktree during validation, so the
shared test helpers set FM_GATE_REFUSE_BYPASS=1 to exempt it; the dedicated
tests/fm-gate-refuse.test.sh strips it to verify real refusal.
* no-mistakes(review): Captain, refuse empty no-mistakes gate markers
* no-mistakes(document): Document no-mistakes gate authority boundary
* fix: guard secondmate primary sessions from blind turn ends (#505)
* fix: guard secondmate own-home turn ends
Remove the .fm-secondmate-home early-exit in fm-turnend-guard.sh so the
'no turn ends blind' backstop fires in a secondmate's own primary session,
matching the cd-guard's scope: the own home is guarded, child crew/scout
worktrees stay exempt via the retained git-dir/git-common-dir test. This
was pure scoping from the guard's primary-only origin and guarded against
no secondmate-specific hazard.
Add secondmate regression tests (blind-turn block, idle-by-default,
stop_hook_active loop guard, deferred-death recovery loop, child-worktree
exemption) and record the autonomous background-notify re-invoke
measurement (Claude Code 2.1.207, 11s) in docs/turnend-guard.md.
* no-mistakes(document): Correct secondmate guard documentation, captain
* fix: force-include marked secondmate homes in turn-end guard
The prior remove-only form (just deleting the .fm-secondmate-home check)
left the DEFAULT secondmate topology unguarded: a treehouse-leased home is
a linked git worktree (git-dir != git-common-dir), which the retained
git-dir exemption still skipped, so its own primary session could still end
a turn blind. Invert the marker: a genuinely-marked home is force-included
as a guarded primary (treehouse-leased linked OR git-cloned plain), and the
git-dir exemption applies only to UNMARKED child worktrees. Marker
validation (regular non-symlink file, non-empty id-token content) blocks a
stray or empty marker from spoofing inclusion.
Add real linked-worktree regression tests: a treehouse-leased LINKED
secondmate home is guarded, a stray/empty marker stays exempt, and the
unmarked child worktree stays exempt - the topology the plain git-init
fixtures masked. Predicates, in-flight gate, and loop guard untouched.
* fix: force ASCII collation in secondmate marker validation
Add a function-scoped local LC_ALL=C in fm_root_is_secondmate_home so the
[A-Za-z0-9._-] id allowlist matches under C collation, not the ambient
locale - a locale-crafted non-ASCII marker id can no longer slip through
the range match and spoof force-inclusion of a linked child worktree.
Add a regression test proving a non-ASCII marker id is rejected and the
linked worktree stays exempt.
* no-mistakes(test): fix backend baseline gate-refusal dependency
* no-mistakes(document): Correct secondmate turn-end guard documentation
* fix: make bootstrap diagnostics backend-aware (#519)
* fix: make bootstrap required-tool detection backend-aware
Bootstrap demanded tmux and treehouse for every backend except orca, so a
herdr/zellij/cmux home with tmux absent was wrongly told MISSING: tmux.
Required tools now follow the resolved backend via the single-owner
fm_backend_required_tools helper (bin/fm-backend.sh): each backend's own
session-provider CLI, jq for the JSON-emitting adapters (herdr/zellij/cmux),
and treehouse for session-provider-only backends (orca owns its worktree).
The treehouse lease-support check is gated to backends that use treehouse.
Adds install hints for herdr/zellij/cmux, regression tests for the full
backend dependency matrix (herdr-without-tmux repro plus each boundary),
and updates the authoritative Toolchain docs.
* no-mistakes(review): Captain, prevent executing Herdr install guidance
* no-mistakes(review): Captain, harden backend-aware bootstrap diagnostics
* no-mistakes(review): Captain, separate manual dependency remediation
* no-mistakes(review): Captain, align bootstrap diagnostic consumers
* no-mistakes(document): Align backend adapter dependency comments
* fix: preserve follow-up platform context after inbox cleanup (#520)
* fix: recover X/Discord follow-up platform after inbox cleanup
A milestone follow-up posted directly by request_id after the inbox was
drained - and with no task link, because one persistent secondmate's single
x_request slot collides across concurrent requests - resolved platform only
from the local inbox, so a >280 Discord reply silently defaulted to the X
280-char budget and threaded as (1/2).
- fm-x-poll records a durable per-request reply context
(state/x-context/<rid>.json) at stash time, keyed by request_id so
concurrent requests never overwrite each other; it survives inbox cleanup
and restart.
- fm-x-reply resolves platform/budget through registry -> inbox -> relay
(the relay lookup confined to a live follow-up), recovering the original
platform independent of task-link availability.
- Fail-safe: a follow-up whose platform/budget cannot be authoritatively
resolved and that would split is refused (exit 8) and held for retry,
never wrongly split; fm-x-followup keeps the link on that exit.
- fm-x-dismiss clears the durable context for a dismissed mention.
Refactors reply-context extraction into a single owner and adds regression
coverage for all four cases.
* no-mistakes(review): Captain, fail closed on incomplete follow-up context
* no-mistakes(review): Captain, bound X context registry retention
* no-mistakes(review): Captain, align context retention with answer binding
* no-mistakes(document): Align X follow-up context documentation
* no-mistakes(document): Align durable X follow-up documentation
* fix: preserve secondmate routing markers in terminal sends (#533)
* fix: preserve secondmate routing markers
* no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends
* no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift
* no-mistakes(document): Refresh Herdr marker documentation
* fix: align Grok effort handling with 0.2.99 (#527)
* fix: align grok effort docs and spawn with 0.2.99 ceiling
grok 0.2.99 accepts only low|medium|high for --reasoning-effort and
rejects both xhigh and max. Omit unsupported values on spawn, flag them
in crew-dispatch validation, and update harness-adapters.
* no-mistakes(test): Captain: refresh gotmp teardown fixture dependencies
* no-mistakes(document): Clarify Grok effort documentation ownership
* fix: derive bearings from authoritative secondmate state (#555)
* fix: make bearings use secondmate home state
* test: anonymize bearings fixtures
* no-mistakes(review): Bound parent activity evidence scans, captain
* no-mistakes(review): Preserve structured secondmate authority and bounds, captain
* no-mistakes(review): Preserve registry completeness and child inventory, captain
* no-mistakes(review): Reconcile parent evidence by verb and key, captain
* no-mistakes(review): Treat unkeyed parent evidence as inconclusive, captain
* no-mistakes(document): Document bearings local snapshot and PR opt-in
* no-mistakes(lint): Fix fleet snapshot ShellCheck findings
* no-mistakes: apply CI fixes
* fix: restore fleet snapshots on stock macOS Bash (#578)
* fix: restore stock macOS snapshot parsing
* no-mistakes(document): Clarify Linux gate and macOS CI coverage
* fix(afk): make Pi escalation and return catch-up reliable (#587)
* fix: close away-mode blocker supervision gap
* no-mistakes(review): Gate teardown retries and verify U+2063 dedupe
* no-mistakes(test): Fail closed on incomplete Pi composer separators
* no-mistakes(document): Document Pi composer recognition and return gating
* feat: support Pi max reasoning profiles (#537)
* support Pi max thinking profiles
* no-mistakes(review): Captain, allow Pi max dispatch profiles
* chore: no-mistakes(document): Clarify yolo response ownership (#595)
* Clarify validation response ownership
* no-mistakes(document): Clarify yolo response ownership
* feat: establish instruction ownership foundation (#619)
* Add instruction owners foundation
* no-mistakes(document): Refresh project-management owner pointers
* fix: compress Firstmate contract and enforce delivery rigor ownership (#626)
* docs: compress firstmate operating contract
* docs: make delivery rigor single-owner
PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion.
* no-mistakes(review): Honor configured merge authority across faster delivery paths
* no-mistakes(document): Align docs with compressed operating contract
* feat: add durable captain decision holds (#593)
* Add durable captain decision holds
* no-mistakes(review): Validate decision hold retries and origin paths
* no-mistakes(review): Enforce durable decision lifecycle boundaries
* no-mistakes(review): Harden decision display and partial retry recovery
* no-mistakes(test): Update scout teardown fixtures for decision inventory
* no-mistakes(document): Align decision lifecycle and scout teardown documentation
* no-mistakes: apply CI fixes
* no-mistakes(review): Reconcile terminal decision holds
* no-mistakes(document): Align captain decision-hold documentation
* fix(bin): harden PR check artifacts (#556)
* fix: harden PR check artifacts
* fix: close PR check migration gaps
* fix: close PR check retry gaps
* fix: clarify migration outcomes and ESM boundary
* fix: keep failed migrations authoritative
* test: use inert PR validation fixtures
* no-mistakes(review): Reserve noncanonical PR quarantine namespace
* no-mistakes(review): Prevalidate final PR-check teardown artifacts
* no-mistakes(review): Preserve X metadata and validate teardown IDs
* no-mistakes(review): Initialize migration state before watcher exclusion
* no-mistakes(review): Isolate failed poll migrations from bootstrap recovery
* no-mistakes(review): Allow safe polling during incomplete private repairs
* no-mistakes(review): Authenticate watcher checks at execution time
* no-mistakes(review): Preserve custom checks with hash-bound registration
* no-mistakes(review): Clean custom check snapshots on watcher signals
* no-mistakes(review): Stop watcher checks promptly on signals
* no-mistakes(review): Terminate watcher check groups before cleanup
* no-mistakes(document): Correct stale X-mode watcher documentation
* fix: drain returned watcher check groups
* no-mistakes(review): Harden quarantine links and recover validated replacement polls
* no-mistakes(review): Preserve X mode across shim version transitions
* no-mistakes(review): Refresh legacy X shims before marker short-circuits
* no-mistakes(document): Correct persisted PR-check artifact documentation
* no-mistakes(document): Correct stale PR-check documentation
* fix: bind PR poll repair provenance
* no-mistakes(review): Enforce single-link ownership for custom check artifacts
* no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs
* no-mistakes(review): Separate task creation and legacy teardown validation
* no-mistakes(review): Restore safe legacy operations and teardown validation
* no-mistakes(review): Disambiguate migration obligations and preserve legacy retries
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits
* no-mistakes(document): Document private poll artifact safety contracts
* no-mistakes(lint): Suppress intentional literal-dollar lint finding
* fix: migrate historical X poll identity
* fix: harden PR check artifacts
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* fix: migrate historical X poll identity
* no-mistakes(review): Harden X-mode artifact publication against symlink corruption
* no-mistakes(review): Guard X artifact publication
* no-mistakes(review): Enforce private X artifact reads
* no-mistakes(test): Fix backend compatibility fixture dependencies
* no-mistakes(document): Refresh PR-check documentation
* no-mistakes(lint): Remove unused x-mode test locals
* no-mistakes: apply CI fixes
* fix(bin): compact session-start backlog digest (#636)
* fix: compact session-start backlog digest
* no-mistakes(test): Fix legacy backend fixture helper
* no-mistakes(test): Fix watcher exit wait helper
* no-mistakes(document): Document compact backlog digest
* fix: dedupe stale watcher guard banners (#637)
* fix: dedupe stale watcher guard banner
* no-mistakes(review): Keep read-only guard state nonmutating
* no-mistakes(document): Clarify stale watcher docs
* fix(bin): balance bearings landed baseline (#640)
* fix: balance bearings landed defaults
* no-mistakes(document): Document balanced landed baseline
* no-mistakes: apply CI fixes
* fix: clarify captain-facing translation contract (#644)
* docs: clarify captain-facing translation contract
* no-mistakes(review): Restore runtime fallback mandate
* no-mistakes(document): Align Bearings translation wording
* fix(bin): make bootstrap output and nudges deterministic (#646)
* fix: make bootstrap nudges deterministic
* no-mistakes(review): Honor state override for bootstrap nudges
* no-mistakes(review): Update benign bootstrap documentation labels
* no-mistakes(review): Validate bootstrap nudge retry markers
* no-mistakes(document): Align bootstrap nudge documentation
* no-mistakes: apply CI fixes
* docs(secondmate-provisioning): clarify concise registry ownership (#649)
* Clarify concise secondmate registry contract
* no-mistakes(review): Expand secondmate registry boilerplate coverage
* no-mistakes(document): Point route docs to owner
* fix(bin): strip quoted blocked_by values during decision hold resolve (#654)
* fix(bin): strip quotes on blocked_by in decision-hold resolve
tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary
membership test only matched middle elements. Strip surrounding quotes
before matching so first and last hold ids resolve correctly.
* no-mistakes(document): Refresh decision-hold regression evidence
* feat(secondmate): inherit shared captain preferences (#656)
* feat(secondmate): inherit shared captain preferences
* no-mistakes(review): Honor shared captain data overrides
* no-mistakes(review): Honor bootstrap data override registry
* no-mistakes(document): Refresh shared inheritance docs
* no-mistakes(document): Clarify inherited local-material docs
* feat: gate local agent secret injection (#658)
* feat(spawn): gate local agent secret injection
* fix(spawn): align final Keychain slot
* no-mistakes: apply CI fixes
* test: isolate Herdr autodetect smoke sessions (#662)
* test: isolate herdr autodetect smoke session
* no-mistakes(review): Restored autodetect smoke gate bypass
* no-mistakes(test): Harden Herdr lab provisioning
* no-mistakes(document): Refresh Herdr lab docs
* docs: adopt under way for active work (#666)
* Revert "feat: gate local agent secret injection (#658)" (#668)
This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef.
* fix(pi): distinguish stale locks when arming watcher (#681)
* fix(pi): distinguish stale locks when arming watcher
* no-mistakes(test): Stabilize watcher extension async waits
* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate house vocabulary (#685)
* fix: accept secondmate as house vocabulary
* no-mistakes(test): Update captain vocabulary contract test
* no-mistakes(document): Align secondmate documentation vocabulary
* fix(bin): parse handoff homes after registry parentheticals (#686)
* fix: parse secondmate home after pre-field parentheses
Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.
* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges (#687)
* feat: add native session-start nudges
* no-mistakes(document): Document nudge script inventory
* docs: call built-in defaults the firstmate repo, not template (#688)
Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
* fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205)
* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn
Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(brief): harden fm-brief regression coverage for parse and scaffolds
Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the
Co-authored-by: Cursor <cursoragent@cursor.com>
#166 apostrophe regression cannot return unnoticed.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(bin): keep watcher supervision continuous across child cycles (#693)
* fix: make watcher supervision continuous
* no-mistakes(review): Bound watcher retries and log attached signals
* no-mistakes(review): Add bounded successor-recovery wake fallbacks
* no-mistakes(review): Prevent overlapping successor-arm retries
* no-mistakes(review): Resume supervision after late arm closes
* no-mistakes(review): Bind OpenCode recovery to attempted arm
* no-mistakes(test): Synchronize peer beacon regression fixture
* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures
* no-mistakes(document): Captain: document watcher successor protocol behavior
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: fetch current PR head for review diffs (#722)
* fix: always fetch PR head for review diffs
Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.
* no-mistakes(test): Isolate session-start nudge tests from gate state
* no-mistakes(document): Correct review-diff documentation
* docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736)
* docs: resolve five contract contradictions
* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): correct Grok exit guidance (#742)
* docs(harness): reverify grok exit command
* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for parked crew (#743)
* fix(watcher): bound stale wakes for exited paused crew
* no-mistakes(review): Gate pause suppression on confirmed agent death
* no-mistakes(test): Fixed stale pause cadence
* no-mistakes(document): Document dead-agent hold cadence
* fix(supervision): distinguish ordinary wakes from recovery (#744)
* fix(supervision): distinguish ordinary wakes from repair
* no-mistakes(review): Make passive guard follow-ups recovery-only
* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes (#745)
* fix(x-mode): dedupe pending mention wakes
* no-mistakes(review): fix x-poll claim error deduplication
* no-mistakes(review): separate claim diagnostics from relay recovery
* no-mistakes(document): Document X-mode once-only mention wakes
* feat(wake): enrich drained signals with bounded status context (#747)
* feat(wake): enrich drained signal context
* no-mistakes(review): Bound wake enrichment reads
* no-mistakes(document): Document wake-drain annotations
* docs(wake): explain at-least-once drain boundary
* no-mistakes(review): Prevent symlink races in wake annotations
* no-mistakes(review): Exercise wake symlink race regression
* test: document intentional AFK marker subprocesses
* fix(wake): isolate annotation marker state
* feat(herdr): add optional presentation spaces (#784)
* feat(herdr): add optional presentation spaces
* no-mistakes(review): Harden Herdr projection creation and spawn serialization
* no-mistakes(review): Captain, disarm Herdr cleanup before launch submission
* no-mistakes(test): Correct stale Orca metadata failure fixture
* no-mistakes(document): Document Herdr presentation projection accurately
* fix(send): treat opencode busy-queued composer state as submitted (#775)
* fix(send): treat opencode busy-queued composer state as submitted
When fm-send sends a message to a BUSY opencode crewmate on the tmux
backend, opencode accepts the Enter and queues the message for the next
turn, but leaves the typed text visible in the composer row. The
submit-verification loop sees a pending composer, exhausts retries, and
reports a false "Enter swallowed" failure while the message is actually
delivered.
Fix: after Enter retries are exhausted and the composer still shows
pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn,
footer shows "esc interrupt"), the harness queued the message, so
return "empty" (accepted). On an idle pane, keep returning "pending"
(genuine swallow detection preserved).
Regression tests cover four scenarios:
- busy pane + pending composer -> empty (message queued)
- idle pane + pending composer -> pending (genuine swallow)
- busy pane + composer clears on first Enter -> empty
- idle pane + composer clears on first Enter -> empty (existing path)
* docs: document busy-queued Enter exception across backend docs and skills
Add explanatory comments and backend documentation for the
busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn
but keeps typed text in composer until the turn ends):
- bin/fm-tmux-lib.sh: document the busy-aware fallback in the
file header and above fm_tmux_submit_enter_core
- .agents/skills/afk/SKILL.md: daemon-facing policy note
- .agents/skills/harness-adapters/SKILL.md: harness-specific fact
- docs/tmux-backend.md: submit-acknowledgement section with the
busy-queue exception
- docs/herdr-backend.md: record the known gap
- docs/architecture.md: cross-reference in the daemon section
* test(tmux): fix SC2181 and make busy-submit test executable
* fix(spawn): require two stable reads before accepting worktree path (#765)
* fix(spawn): require two stable reads before accepting worktree path
The treehouse-get worktree-detection loop in fm-spawn.sh accepted the
first pane_current_path read that differed from the project path, but
on some tmux/WSL setups a brand-new window transiently reports a
stale-but-real path before the pane actually settles into the
worktree. Since that stale path is itself a real, distinct git
checkout, it also passes validate_spawn_worktree's isolation check,
so the loop silently recorded the wrong worktree in state/<id>.meta
(and, for claude harness spawns, installed the turn-end hook there
too).
Require two consecutive polls to agree on the same non-project path
before accepting it, using the existing inter-poll sleep as the
confirmation gap so an already-settled pane isn't slowed down by an
extra cycle.
* fix(tests): drop unused CASE_DIR read in worktree-settle test
ShellCheck SC2034: CASE_DIR is split out of the case record but
never referenced; discard it with _ instead.
---------
Co-authored-by: Freudator86 <tim@allesknut.de>
* fix(bin): make watcher process identity immune to Linux wall-clock changes (#752)
* fix(watcher): stabilize Linux process identity
* no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale
* fix: prevent AFK idle stalls and stale run attribution (#758)
* fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state
Stop free-text tokens like "merged" from promoting nonterminal working: lines
to captain-relevant, so AFK no longer permanently suppresses idle recovery.
Defend wedge aging independently for nonterminal progress verbs, bind
no-mistakes current-state attribution to code identity (not branch alone),
and mark setup-complete as nonterminal in the ship brief scaffold.
* no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution
* no-mistakes(document): Document current-code-bound run attribution
* no-mistakes(test): Wait for stable Herdr shell readiness
* no-mistakes(test): Make Herdr and watcher readiness tests deterministic
* no-mistakes(test): Make tmux capture and watcher lifecycle deterministic
* no-mistakes(document): Document corrected supervision contracts
* fix(bin): allow safe teardown during watcher recovery (#750)
* fix: allow safe teardown during watcher recovery
* no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code
* no-mistakes(document): Sync continuity-gate docs to allow teardown recovery
* test: mark dynamic teardown fixture literal
* no-mistakes(document): docs: add teardown to continuity gate allow list
* feat(herdr): order presentation spaces while preserving focus (#790)
* feat(herdr): order presentation worker spaces
* fix(herdr): preserve focus during projected cleanup
* no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs
* no-mistakes(review): Serialize Herdr aborts with guarded focus regressions
* no-mistakes(review): Fall back flat when Herdr serialization is unavailable
* no-mistakes(test): Stabilize watcher startup and AFK handoff tests
* no-mistakes(document): Correct Herdr ordering and focus documentation
* fix(bin): send literal config reread nudges after pushes (#809)
* Send literal config reread after inherited config push
When declared inherited config changes under an already-running secondmate,
build a per-home instruction from validated destination post-write bytes and
deliver it on the routed secondmate path. Unchanged config sends nothing;
ABSENT represents removal; captain-shared is never inlined. Covers mid-session
config-push and the locked bootstrap convergence path without hardening spawn
against deliberate runtime choice.
* no-mistakes(review): Fix config reread framing, partial propagation, and respawn order
* no-mistakes(review): Send config rereads via durable single-line pointers
* no-mistakes(review): Make failed config rereads retryable
* no-mistakes(review): Make config reread retries generation-safe
* no-mistakes(review): Make config rereads durable and ordered
* no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode
* no-mistakes(review): Retain write retries and quarantine stale respawn generations
* no-mistakes(review): Preserve exact config reread retries and delivery order
* no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning
* no-mistakes(document): Consolidated config-reread documentation
* feat(watch): follow GitLab merge requests to merge (#797)
* feat(watch): follow GitLab merge requests to merge
The merge watch only understood GitHub pull requests, so a task whose
deliverable is a GitLab merge request was never followed to merge.
Generalize the stored poll identity from owner/repository to a
provider-tagged provider/url/host/path/number record. GitLab runs mostly on
self-hosted instances and its projects nest under groups at no fixed depth,
so the host and the full project path are data in the record rather than
constants, and every consumer rebuilds the URL from those parts and refuses
any record that does not reconstruct it exactly.
The GitLab state is read with plain glab, matching the GitHub path's use of
plain gh, so an upstream checkout needs no extra tooling. Two things about
glab were established by running it rather than assumed, because a wrong
invocation here fails silently into a permanent "not merged":
- glab has no field selector, and its JSON would need a JSON processor that
firstmate does not require, so the state is read from glab's own field
output. Only an exact "merged" wakes firstmate, so a changed format stays
silent instead of reporting a merge.
- glab cannot take a merge request URL the way gh can, because that form
resolves through the current git repository and the watcher has none. It
is addressed by project URL and merge request number instead.
An absent glab produces no wake rather than a false merge, and arming
refuses with a clear message since that is the one point where a missing
CLI can still be reported. A GitLab task records no pr_head, which both
consumers already treat as optional. The merge path still addresses GitHub
only and refuses a merge request URL rather than sending it to the wrong
forge.
The record version moves to v2, and the existing non-executing migration
rebuilds an already-armed watch from its recorded URL, so no watch is lost
by upgrading.
docs/gitlab-merge-watch.md records the evidence, taken against the public
fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture.
* no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation
* no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs
* fix(herdr): group projected children beneath owning parents (#821)
* feat(herdr): correct all-home child presentation topology
Inherit the presentation opt-in to secondmate homes, label new projected
spaces with the approved corner format, insert each child under its owning
parent under one session-scoped lock, and keep flat non-destructive fallback.
* no-mistakes(review): Exclude secondmates from Herdr presentation projection
* no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering
* no-mistakes(review): Use adjacency-only Herdr child ownership
* no-mistakes(review): Reject foreign legacy projections safely
* no-mistakes(review): Validate Herdr session sockets before projection
* no-mistakes(test): Fix Herdr teardown fixture session socket metadata
* fix(herdr): canonicalize presentation lock socket paths
Always resolve the session socket parent directory so symlink parents
such as /tmp -> /private/tmp cannot split the shared cross-home lock
identity. Refuse relative socket paths. Clarify lock-unavailable warnings.
* no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing
* no-mistakes(document): Document all-home Herdr child topology
* no-mistakes(lint): Quote fallback provenance string for ShellCheck
* fix: keep local no-mistakes tests intent-targeted (#823)
* fix(no-mistakes): drop full-suite local Test override
Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad
tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a
focused contract test so the override cannot silently return.
* no-mistakes(lint): Make CI contract assertion ShellCheck-clean
* feat: add canonical timed test runner (#825)
* feat(test): add canonical timed suite runner and honest CI timeout
Introduce bin/fm-test-run.sh as the single serial owner for selecting
one script, a family, a conservative changed-file set, or the explicit
complete suite, with per-script timing markers and a JSON artifact.
Wire CI Behavior through the runner, raise the hang-tripwire timeout to
25 minutes, and document entry points without restoring a full-suite
local no-mistakes Test command.
* no-mistakes(review): Captain: fix changed selection and empty summaries
* no-mistakes(review): Captain: fail closed on unmapped changed sources
* no-mistakes(document): Document canonical timed test entry points
* fix: surface main inventory gaps in Bearings (#830)
* fix: disclose main-home orphan and unstructured inventory gaps
Main Bearings could report an empty fleet while structured in-flight rows
lacked meta or current backlog rows were free-form. Emit main_inventory from
the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next
gate, and keep meta as the only live Underway source.
* no-mistakes(document): Document Bearings inventory-integrity projection
* no-mistakes: apply CI fixes
* feat: add bounded concurrent test isolation proof (#832)
* feat: add concurrent test isolation proof for Phase 2
Prove an audited portable candidate set passes under concurrent
workers with private mode-0700 temp roots, without enabling
production CI sharding or fm-test-run --jobs.
* no-mistakes(review): Pin isolation proof to audited candidate manifest
* feat: guard against missed secondmate reports (#834)
* feat(secondmate): parent-owned guards for missed status reports
Marked parent-to-secondmate requests now create a durable pending-reply
expectation with a privacy-safe correlation id before delivery. Transport
success never resolves it; only a correlated parent status or document
pointer does. After a completed turn with no report, the parent sends one
recovery repost and escalates once if that turn is also missed, without
scraping the secondmate conversation or looping.
* no-mistakes(review): Deduplicate wrong-home pending-reply sightings
* no-mistakes(review): Harden pending-reply recovery and escalation guards
* no-mistakes(review): Bound pending-reply backend polling
* no-mistakes(review): Cache pending-reply status scans
* no-mistakes(review): Protect undelivered pending-reply records from scans
* no-mistakes(review): Close pending-reply delivery durability gaps
* no-mistakes(review): Separate pending-reply transport outcomes
* no-mistakes(review): Escalate stalled pending-reply deliveries once
* no-mistakes(review): Resolve attempted deliveries from correlated reports
* no-mistakes(review): Resolve late reports after delivery escalation
* no-mistakes(document): Document pending-reply grace and ownership
* no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings
* feat: require pinned real-Herdr CI coverage (#838)
* feat: add required pinned Herdr CI lane
Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and
SHA-256 pins, run the real-herdr-gated family serially through
fm-test-run with hard-fail on herdr-not-found, and keep portable
Behavior free of claimed Herdr coverage.
* no-mistakes(document): Consolidate real-Herdr CI documentation ownership
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* feat: shard portable tests and add bounded local parallelism (#841)
* feat: shard portable CI tests after isolation proof
Balance the Phase 2 proven-isolated set into two LPT portable parallel
lanes from Phase 1 timing evidence, keep stateful work in a required
portable serial lane, exclude real Herdr to its dedicated required lane,
and prove complete inventory coverage with a deterministic guard.
Add bounded local --jobs only for the proven set, per-lane timing plus
aggregate artifacts, and reduce the interim portable hang tripwire now
that the serial remainder owns the long wall-clock path.
* no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling
* no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests
* no-mistakes(document): Document portable sharding and timing aggregation
* no-mistakes: apply CI fixes
* fix: block primary-session delegation outside the fleet (#854)
* feat: fence primary-session delegation outside the fleet
A firstmate primary that delegates through Claude Code's built-in
delegation tools creates work with no state/<id>.meta. Because
fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits
silently at zero, such work does not merely go unsupervised: it makes
the whole guard stack structurally inert, and it dies with the primary
session. On 2026-07-22 that cost two workers mid-flight and left
supervision down for 73 minutes unnoticed.
Layer 1, the primary fix: a permissions.deny list in
.claude/settings.json removes the 18 delegation, scheduling, worktree,
and task-tracking tools from the model's schema, so they are never
offered. This is removal rather than interception, so there is no call
to intercept and no fail-open path. The list is flat and in one file so
its width stays reviewable; the captain owns that width.
Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open
against tools that do not exist yet, and permissions.allow is a
pre-approval list rather than an availability list, so there is no
fail-closed allowlist to use instead. This backstop classifies the tool
NAME by shape rather than against a fixed list, so a delegation tool
that ships before the deny list is updated is still refused. It excludes
mcp__* names and observe-or-stop operations, scopes itself to a genuine
primary home via the shared fm_primary_scope_matches predicate so a
crewmate's task worktree is unaffected, and offers one deliberate
FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch.
Verified live against Claude Code 2.1.217, including a deny-key A/B with
a nonsense-name control, layer 2 denying an un-denied Workflow call, the
same call allowed in a linked worktree, and the escape hatch. Corrects a
prior finding: both Task and Agent work as deny keys, so both are
pinned. Codex 0.144.1 verified to expose no delegation tool; grok,
opencode, and pi are inspected and documented as not wired because those
binaries are absent from this host and the repo requires live validation
before trusting a harness hook. Evidence in docs/subagent-guard.md.
* no-mistakes(review): Ship scoped Claude delegation guard
* no-mistakes(test): Ship Claude delegation deny list
* no-mistakes(document): Clarify PreToolUse guard ownership
* no-mistakes(lint): Keep Claude deny list local
* fix: install tasks-axi in portable CI shards (#866)
Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged.
* feat(bin): make dispatch profiles quota aware (#867)
* feat: make dispatch profiles quota aware
* no-mistakes(review): Fix quota window and Grok product scoping
* no-mistakes(document): Document implicit quota-aware dispatch accurately
* Add built-in ahoy recap skill (#873)
* fix: preserve trustworthy Bearings data in partial snapshots (#875)
* fix: preserve mixed Bearings projections
* no-mistakes(review): Enforce strict invalidity precedence for partial snapshots
* no-mistakes(review): Enforce ownership for unknown child metadata
* no-mistakes(document): Document partial structured Bearings projections
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* feat(pi): add session-local calm mode (#884)
* Add session-local Pi calm mode
* no-mistakes(review): Preserve Pi HTML exports during calm mode
* no-mistakes(review): Preserve calm exports across submit bindings and share
* no-mistakes(document): Document calm-mode feasibility across supported harnesses
* fix(pi): prevent redundant watcher re-arms (#885)
* fix(pi): limit watcher arm tool to recovery
* no-mistakes(review): Strengthen Pi live re-arm regression coverage
* no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming
* fix(pi): clean up Calm transcript rendering (#895)
* fix(pi): clean up Calm transcript rendering
* no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs
* no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations
* no-mistakes(review): Restore Calm rows received while active
* no-mistakes(review): Preserve diagnostics during Calm restoration
* no-mistakes(document): Clarify Calm transcript behavior and injection paths
* fix: execute every PR body compliance event (#898)
* fix: execute every PR body compliance event
* no-mistakes(document): Document independent PR compliance events
* fix: exclude operational injections from ahoy boundaries (#899)
* fix: distinguish operational input in ahoy
* no-mistakes(review): Handle legacy Ahoy operational boundaries
* no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions
* no-mistakes(document): Document Ahoy operational marker ownership
* no-mistakes(lint): Suppress intentional literal fixture lint warnings
* fix: canonically classify operational inputs across harnesses (#909)
* fix: type canonical operational inputs
* no-mistakes(document): Correct canonical operational-input documentation ownership
* fix: avoid generic secondmate start acknowledgements (#926)
* fix: avoid generic secondmate acknowledgements
* no-mistakes(document): Document sparse secondmate acknowledgement behavior
* no-mistakes: apply CI fixes
* fix(pi): make calm mode persistent and gapless (#927)
* fix(pi): preserve calm presentation across sessions
* no-mistakes(review): Fix Calm home fallback persistence
* no-mistakes(document): Clarify Calm gapless and export contracts
* no-mistakes: apply CI fixes
* fix(watch): retire merged PR polls after durable notification (#932)
* fix: retire merged PR polls after notification
* no-mistakes(review): Decouple PR retirement recovery from template updates
* no-mistakes(review): Recover pending PR retirements before poll migration
* no-mistakes(document): Document merged PR poll retirement contracts
* fix: refine scout intake and parallel dispatch (#934)
* Clarify intake evidence and overlap handling
* no-mistakes(review): Align scout guard with intake classification
* no-mistakes(document): Clarify scout documentation and intake ownership
* fix(pi): prevent duplicate assistant replies in Calm (#936)
* fix(pi): preserve operational follow-up semantics in Calm
* no-mistakes(document): Correct Calm operational-row visibility documentation
* perf(bin): shrink the ShellCheck source graph (#939)
* perf(lint): shrink shell source graph
* no-mistakes(review): Ensure lint workers terminate fully on cancellation
* no-mistakes(document): Repair stale lint documentation ownership
* fix(pi): remove Calm hidden-block gaps (#942)
* fix(pi): remove Calm hidden-block gaps
* no-mistakes(review): Validate Calm geometry against current viewport
* no-mistakes(review): Synchronize Calm geometry checks with reload completion
* fix: enforce contract boundaries for ask-user findings (#945)
* fix: escalate ask-user contract expansion
* no-mistakes(document): Point project management to authority owner
* docs: prefer direct operational paths (#946)
* fix(pi): hide operational user rows in Calm mode (#948)
* fix(pi): hide Calm operational user rows
* no-mistakes(review): Narrow Calm operational input suppression
* no-mistakes(review): Avoid Calm replay classifier subprocesses
* no-mistakes(document): docs: point Pi verification to Calm owner
* fix: relaunch missing second mates at session start (#950)
* fix(session-start): relaunch missing second mates
* fix(test): detect completed parallel workers
* no-mistakes(review): Isolate session-start recovery test cleanup
* no-mistakes(review): Complete backend-safe secondmate session recovery
* no-mistakes(review): Resolve Zellij task ownership before recovery
* no-mistakes(review): Recover relocated Zellij ghost tabs safely
* no-mistakes(review): Restore conservative Zellij recovery boundary
* no-mistakes(review): Reject malformed tmux recovery targets
* no-mistakes(document): Align secondmate recovery documentation
* no-mistakes: apply CI fixes
* fix(herdr): reclaim resumed task projections after restart (#967)
* fix(herdr): reclaim resumed task projections safely
* no-mistakes(review): Enforce safe Herdr reclaim close boundaries
* no-mistakes(document): docs: clarify Herdr restart projection contract
* Teach Ahoy to surface open decisions (#968)
* Require shipshape routine acknowledgement (#969)
* docs: separate current guidance from verification evidence (#994)
* docs: separate current guides from verification
* no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence
* fix: preserve Claude watcher continuity across Stop hooks (#997)
* feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm
Claude primaries (main home and marked secondmate homes) no longer depend
on the model remembering to re-arm the watcher after each wake. A tracked
Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s)
fires on every turn end, claims one home-scoped single-flight owner,
foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and
translates an actionable close or typed watcher failure into exactly one
exit-2 rewake. The hook scopes to genuine primary checkouts, requires the
session lock to be held by its own harness ancestor, stays inert while
AFK owns triage or the home is idle, and hands AFK transitions mid-cycle
to the daemon without rewaking.
The synchronous turn-end guard gains a --claude cooperative mode: it
ignores stop_hook_active (true on every post-continuation stop, which is
what re-opened the 2026-07-21 blind window), waits briefly for a watcher
health proof, a live auto-arm owner claim, or a fresh rewake epoch, and
re-blocks only when the auto-arm genuinely failed to establish - bounded
to 3 consecutive blocks per session, safely below Claude Code's 8-block
override, then a degraded allow with a visible systemMessage. Codex
keeps the previous one-block loop guard byte-identically, and Pi,
OpenCode, and Grok adapters are untouched.
Continuity PreToolUse gate and durable wake queue are preserved; the
gate's recovery guidance now names the Stop-owned re-arm and reserves
manual background arms for auto-arm failure. Claude supervision protocol,
harness-adapters facts, architecture, configuration, and continuity docs
updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218
contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout
process-group kill, 8-block cap, interactive non-stall) and the 2.1.219
product live E2Es.
Regression matrix: hermetic tests cover scope, identity, AFK, need,
single-flight, translation, guard cooperation, budget, and registration;
the new live E2E proves two full tokenless auto-arm rewake cycles with
zero model arm commands; Pi and OpenCode Option B live E2Es pass
unchanged.
* no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop
* no-mistakes(review): Remove unsupported Claude contract-lab verification claims
* no-mistakes(document): Update Claude auto-arm continuity documentation
* fix(herdr): clean stale projections at session start (#996)
* Clean stale Herdr projections at session start
* no-mistakes(document): Document stale Herdr session-start projection cleanup
* no-mistakes(review): Enforce locked exact Herdr projection cleanup
* no-mistakes(review): Fail closed on unverified session lock ownership
* no-mistakes(review): Serialize session lock acquisition atomically
* no-mistakes(document): Align session-start and Herdr cleanup documentation
* no-mistakes(document): Generalize lock-refusal diagnostics
* no-mistakes(lint): Avoid reserved keyword in concurrency test
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: recover Claude supervision without watcher-status gate (#1001)
* fix: recover Claude supervision at session start
* fix: remove Claude watcher-status command gate
* no-mistakes(document): docs: remove stale continuity gate references
* fix: make quota-aware profile selection agent-owned (#1018)
* Replace quota dispatch selector instructions
* no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection
* fix(bin): remove vestigial dispatch selector (#1026)
* remove vestigial dispatch selector
* no-mistakes(review): Synchronize isolation proof and portable shard evidence
* no-mistakes(review): Correct shard history and proof archive date
* no-mistakes(review): Remove reintroduced selector documentation reference
* no-mistakes(document): Remove stale dispatch strategy documentation
* docs(agents): drop superseded interim quota-window rule (#1039)
quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per
provider, so the successor named in the interim rule has landed and the
rule's own removal condition is satisfied.
Keep the ownership clause so quota-axi remains the single owner of how
model or product windows relate to bounding account windows, and drop
the interim weakest-headroom instruction. The unknown-semantics case is
already covered by the existing requirement to stop and report a
candidate whose applicable quota data or interpretation cannot be
established.
Drop the matching assertion phrase from
tests/fm-instruction-owners.test.sh; the retained ownership phrase still
asserts.
* fix(tmux): scope busy detection and recognize current Claude turns (#1049)
* fix(tmux): scope Claude busy detection by harness
* no-mistakes(review): Separate verified and fallback busy signatures
* no-mistakes(test): Scope busy signatures to supplied harnesses
* no-mistakes(document): Document harness-scoped busy detection
* feat: add verified Kimi crewmate adapter (#1047)
* Add verified Kimi crewmate harness adapter
* no-mistakes(review): Scope Kimi moon detection to spinner lines
* no-mistakes(review): Match only complete Kimi spinner rows
* no-mistakes(review): Resolve Kimi binary portably before pane creation
* no-mistakes(document): Align Kimi adapter documentation
* no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override
* Fix Kimi busy spinner detection
* no-mistakes(review): Recognize Kimi session-lock ancestry and holders
* no-mistakes(review): Scope pending-reply Kimi busy detection by harness
* no-mistakes(document): Correct Kimi spinner capture documentation
* no-mistakes(document): Clarify optional Kimi spinner whitespace
* no-mistakes(lint): Silence intentional pending-reply test stub warnings
* test: align rebased Kimi busy fixtures
* no-mistakes: apply CI fixes
* Reconcile Kimi busy detection after per-harness scoping
* no-mistakes(review): Clarify observed Kimi spinner whitespace contract
* no-mistakes(document): Clarify Kimi harness documentation
* fix: harden Kimi submission and spinner matching (#1058)
* fix kimi pointer submission and spinner conformance
* no-mistakes(review): Preserve Kimi submit target ownership guard
* feat(bin): add guarded Kimi turn-end wake (#1059)
* Add guarded Kimi turn-end hook
* no-mistakes(review): Require jq before installing Kimi turn-end hook
* no-mistakes(review): Expose jq inside isolated Kimi test fixtures
* no-mistakes(review): Preserve Kimi config boundaries during hook removal
* no-mistakes(review): Document Kimi removal newline safeguard
* no-mistakes(document): Document Kimi shared-home preservation
* fix(tmux): classify bordered composers across all rows (#1066)
* Fix structural tmux composer reading
* Verify Calm compatibility with Pi 0.82
* no-mistakes(review): Harden structural composer classification boundaries
* no-mistakes(review): Refresh composer and Kimi regression fixtures
* no-mistakes(review): Fail closed on unbounded composer edges
* no-mistakes(review): Enforce aligned composer geometry safely
* no-mistakes(review): Make composer ambiguity locale-safe
* no-mistakes(review): Preserve ambiguity through composer submission
* no-mistakes(review): Carry composer proof through retries
* no-mistakes(document): Document structural tmux composer delivery guarantees
* no-mistakes: apply CI fixes
* feat(bin): add verified pi-signed runtime adapter (#1145)
* feat: add verified pi-signed adapter
* no-mistakes(review): Correct pi-signed maintainer verification date
* no-mistakes(review): Correct remaining pi-signed verification dates
* no-mistakes(review): Preserve authoritative pi-signed runtime identity
* no-mistakes(document): Document pi-signed shared adapter semantics
* no-mistakes: apply CI fixes
* fix(pi): rearm watcher across session transitions (#1166)
* fix(pi): rearm watcher across same-process session transitions
Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement
as well as terminal quit. The primary watcher extension latched a module-level
stopping flag on every shutdown, so a replacement session in the same process
could not arm monitoring until Pi restarted.
Own arm authority per session generation so only the active live generation
may start, stop, or rearm the child. Replacement sessions can arm again without
restarting Pi, stale prior-generation callbacks cannot mutate the active cycle,
and real quit still blocks late rearm.
* no-mistakes(review): Preserve Pi generation isolation and exit cleanup
* no-mistakes(document): Correct Pi watcher transition documentation
* feat: route crew dispatch using quota-window pace (#1172)
* Consume quota-axi pace signals in dispatch profile array selection.
Add quota-array-dispatch as the single owner of the pace-aware candidate
choice, keep AGENTS.md to the intake boundary and load trigger, and cover
the acceptance cases with sanitized schemaVersion 3 fixtures.
* no-mistakes(review): Stop and report genuine quota dispatch ties
* no-mistakes(document): Document quota pace freshness and uncertainty
* fix: adapt Grok Stop continuation and harden endpoint cleanup (#1171)
* fix(grok): adapt Stop continuation to runtime capability
* no-mistakes(review): Reject ambiguous Grok Stop payloads
* no-mistakes(review): Reject duplicate Grok fields and accept spaced tmux sessions
* no-mistakes(review): Enforce exact tmux cleanup selectors
* no-mistakes(test): Fix historical tmux fixture and validate Grok Stop
* no-mistakes: apply CI fixes
* fix: restore stock macOS Bash 3.2 brief scaffolding (#1093)
* fix(brief): make DOD scaffolding parse-safe on stock macOS Bash 3.2
fm-brief.sh built each Definition-of-done block and the not-enabled
Herdr declaration with `VAR=$(cat <<EOF ... EOF)`. On Bash 3.2 (macOS
/bin/bash) the lexer scans for the command substitution's closing `)`
textually and tracks quote state through the heredoc body, so a single
apostrophe, unbalanced quote, or unbalanced paren in that prose breaks
parsing of the whole script. Every ship-brief scaffold (no-mistakes,
direct-PR, local-only) failed with `unexpected EOF while looking for
matching )`. Bash 4+ parses it fine, so the breakage stayed invisible
everywhere except stock macOS.
Replace all four command-substitution heredocs with
`IFS= read -r -d '' VAR <<EOF || true`. That removes the `$(...)`
wrapper and the entire defect class regardless of future prose, and
preserves the variable expansion the direct-PR and local-only bodies
need. `read` keeps the heredoc's trailing newline that `$(...)` used to
strip, so trim one newline to keep every generated brief byte-identical
to prior output.
Guard the structure, not one historical phrase: a new test rejects any
heredoc nested in a command substitution anywhere in fm-brief.sh, where
the old assertion pinned a single apostrophe phrase and so missed the
reintroduction. Extend the stock-macOS Bash CI job from parsing one
script to the whole maintained shell surface (bin/*.sh,
bin/backends/*.sh, tests/*.sh), matching bin/fm-lint.sh's canonical file
set so parse scope and lint scope cannot drift apart.
* no-mistakes(review): Captain: harden Bash structure and inventory guards
* no-mistakes(document): Align stock macOS Bash contributor checks
* no-mistakes(lint): Suppress deliberate SC2016 literal fixture warnings
* test: stabilize tmux teardown conformance baseline (#1209)
* fix(test): pin teardown tmux baseline to historical kill selectors
merge-base HEAD main collapses to HEAD after the exact-selector change
lands on the default branch, so the old teardown fixture was accidentally
exercising current exact targets. Resolve a content-historical permissive
tmux adapter from first-parent history and force that post-squash topology
inside the conformance case so main and feature branches keep the same
old-vs-new contract.
* no-mistakes(lint): Suppress intentional literal-pattern ShellCheck warnings
* docs: slim quota-array-dispatch to the pace selection core (#1197)
Cut the runtime skill to the compact pace-aware selection procedure plus
minimum owner pointers. Keep every distinct decision rule and move expanded
acceptance scenarios to deterministic fixture ownership assertions.
Size: 170/1374/10187 -> 63/544/4068 (about 63%/60%/60% reduction).
* feat(bin): inherit backend config into secondmate homes (#1219)
* Inherit config/backend into secondmate homes with deliberate-override preservation
Add backend to the shared inheritable config allowlist so launch, locked
bootstrap, and config-push converge a primary pin into secondmate homes as each
home local future-spawn default. Track last-inherited bytes in a private state
provenance marker so deliberate per-home overrides survive present and absent
primary convergence, keep --backend and FM_BACKEND stronger, and extend the
existing inheritance tests plus docs and skill claims.
* no-mistakes(review): Preserve equal unprovenanced backend overrides
* no-mistakes(review): Preserve symlink overrides and verify spawn precedence
* no-mistakes(review): Snapshot backend inheritance for consistent provenance
* no-mistakes(review): Simplify backend inheritance to primary-authoritative convergence
* no-mistakes(document): Document inherited backend override preservation
* fix: restore primary-authoritative backend inheritance after document regression
The document step reintroduced provenance and deliberate per-home override
semantics after review had simplified config/backend to plain primary-authoritative
allowlist membership. Restore the primary-always-wins path: present overwrites,
absent removes, no provenance marker, and docs/tests match that contract.
* no-mistakes(review): Add divergent backend precedence regression fixtures
* no-mistakes(document): Document backend inheritance contract
* fix(pi): remove Calm's upper version ceiling (#1226)
* fix(pi): remove Calm's exclusive Pi upper-version ceiling
tests/fm-calm-pi-extension.test.sh gated on a closed PI_COMPAT_VERSIONS
allowlist ("0.81.1 0.82.0") that refused any other installed Pi, and docs
described that range as "supported" rather than verified evidence. The
Calm CHANGELOG shows no API introduced at either version, so there is no
evidence for a real minimum; the presentation adapters already probe the
exact method they patch rather than checking a version.
Replace the allowlist with dated version evidence that never rejects a
newer Pi, and make each presentation adapter degrade independently with
a diagnostic if a future Pi removes its API, instead of the whole Calm
extension failing to load. Rewrite the feasibility doc's "Pi 0.81.1
through 0.82.0" phrasing to state it as verified evidence, not a
ceiling.
* no-mistakes(review): Probe missing Calm adapter exports safely
* no-mistakes(document): Document Calm's unbounded Pi compatibility
* fix(bin): allow session-local todo tools in the subagent guard (#1204)
* fix(guard): allow session-local todo tools in the primary
The delegation-shape guard denied TaskCreate and TaskUpdate because their
normalized names contain the `task` stem. Those tools write only the harness's
session-local todo list, which has no executor: it spawns no agent, allocates
no worktree, registers no schedule, and starts nothing that outlives the
session. That is not the unaccounted work the guard exists to stop, so the stem
match was a false positive, and the deny text told the primary to run
bin/fm-brief.sh and bin/fm-spawn.sh to create a todo entry.
Add a separately-reasoned PLAN_ONLY_TOOLS exact-name exclusion rather than
widening OBSERVE_ONLY_TOOLS, whose documented contract is tools that only
observe or stop existing work. Both lists stay exact-name so neither can widen
by substring.
Tests cover the two allowed names and six near-miss names that a substring or
shortened-stem widening would release; both mutations were watched red.
* no-mistakes(review): drop session-local todo tools from recommended deny list
* no-mistakes: apply CI fixes
* fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid (#1206)
* fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid
fm_harness_ancestry_pid() previously returned the first ancestor process
whose command matched a verified harness name. Claude Code's Stop hook
fires as a bg-spare worker several levels below the session's actual
lock-owning claude process (hook shell -> claude bg-spare ->
claude bg-pty-host -> claude -> claude(lock)), so the first match was
the bg-spare worker, not the lock owner. fm_session_lock_owned_by_self()
then never matched state/.lock, and the Claude Stop auto-arm silently
treated its own primary session as an unrelated live owner and never
armed the watcher.
The walk now keeps going past a claude-named match, looking for a still
more ancestral claude-named match, and stops the instant a non-match
follows an already-found match (bounding it to a contiguous run rather
than the literal ancestry top, so an unrelated claude-named process
further up the real process tree is never mistaken for part of this
session's own nested chain). Every other harness keeps the original
first-match-wins behavior, since e.g. Pi's shared signed-wrapper
ancestry actually holds the session at the inner engine pid, not an
outer wrapper pid. Hop limit raised from 8 to 16 to cover the deeper
bg-spare chain.
* no-mistakes(review): Add nested-claude-ancestry regression test; fix nudge doc depth claim
* no-mistakes: apply CI fixes
* fix: conferma l'avvio del watcher su Windows/MSYS (#1212)
* fix: confirm watcher startup on MSYS
* no-mistakes(review): gate MSYS arm ready timeout, cache uname, harden locale test
* no-mistakes(review): validate OpenCode ready timeout, make uname cache internal
* fix(spawn): forward CLAUDE_CONFIG_DIR to claude crewmates (#1195)
* fix(spawn): forward firstmate's CLAUDE_CONFIG_DIR to claude crewmates
Crewmate panes are created by a long-lived tmux/herdr daemon that does not
inherit firstmate's current environment. When firstmate runs under a non-default
CLAUDE_CONFIG_DIR (for example a work-vs-personal subscription split), a bare
`claude` in the crewmate pane fell back to the default ~/.claude store and
launched unauthenticated, blocking the crewmate before it could do any work.
fm-spawn now prefixes the claude launch with firstmate's own resolved
CLAUDE_CONFIG_DIR when set, so the crewmate uses the same credential/config
store firstmate is authenticated with. An unset value is the single-store
default and adds no prefix; non-claude harnesses are unaffected.
Adds three tests in fm-spawn-dispatch-profile.test.sh (forwarded-when-set,
omitted-when-unset, non-claude-ignored) and pins CLAUDE_CONFIG_DIR in the test
helper so launch assertions no longer depend on the developer's environment.
* no-mistakes: apply CI fixes
* fix: preserve dispatch identity across authentication checks (#1233)
* fix: preserve dispatch harness identity
* no-mistakes(review): Fix Grok counterfactual tuple validation
* no-mistakes(document): Scope dispatch authentication to selected tuple
* fix: restore dispatch instruction budget
* no-mistakes(review): Scope dispatch authentication after candidate selection
* fix(bin): normalize relative durable paths (#1256)
* fix(bin): handle dash-leading harness process names (#2)
* fix: handle dash-leading harness process names
* no-mistakes(review): Make dash-leading harness regression hermetic
* fix: preserve secondmate reply routes across relative homes
Resolve relative home, data, and state inputs before …
vipentti
pushed a commit
to vipentti/firstmate
that referenced
this pull request
Aug 5, 2026
…nguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged.
elixlabssolutions
added a commit
to xLabs-OS/firstmate
that referenced
this pull request
Aug 6, 2026
…ing both fork commits (#4) * fix: compress Firstmate contract and enforce delivery rigor ownership (#626) * docs: compress firstmate operating contract * docs: make delivery rigor single-owner PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion. * no-mistakes(review): Honor configured merge authority across faster delivery paths * no-mistakes(document): Align docs with compressed operating contract * feat: add durable captain decision holds (#593) * Add durable captain decision holds * no-mistakes(review): Validate decision hold retries and origin paths * no-mistakes(review): Enforce durable decision lifecycle boundaries * no-mistakes(review): Harden decision display and partial retry recovery * no-mistakes(test): Update scout teardown fixtures for decision inventory * no-mistakes(document): Align decision lifecycle and scout teardown documentation * no-mistakes: apply CI fixes * no-mistakes(review): Reconcile terminal decision holds * no-mistakes(document): Align captain decision-hold documentation * fix(bin): harden PR check artifacts (#556) * fix: harden PR check artifacts * fix: close PR check migration gaps * fix: close PR check retry gaps * fix: clarify migration outcomes and ESM boundary * fix: keep failed migrations authoritative * test: use inert PR validation fixtures * no-mistakes(review): Reserve noncanonical PR quarantine namespace * no-mistakes(review): Prevalidate final PR-check teardown artifacts * no-mistakes(review): Preserve X metadata and validate teardown IDs * no-mistakes(review): Initialize migration state before watcher exclusion * no-mistakes(review): Isolate failed poll migrations from bootstrap recovery * no-mistakes(review): Allow safe polling during incomplete private repairs * no-mistakes(review): Authenticate watcher checks at execution time * no-mistakes(review): Preserve custom checks with hash-bound registration * no-mistakes(review): Clean custom check snapshots on watcher signals * no-mistakes(review): Stop watcher checks promptly on signals * no-mistakes(review): Terminate watcher check groups before cleanup * no-mistakes(document): Correct stale X-mode watcher documentation * fix: drain returned watcher check groups * no-mistakes(review): Harden quarantine links and recover validated replacement polls * no-mistakes(review): Preserve X mode across shim version transitions * no-mistakes(review): Refresh legacy X shims before marker short-circuits * no-mistakes(document): Correct persisted PR-check artifact documentation * no-mistakes(document): Correct stale PR-check documentation * fix: bind PR poll repair provenance * no-mistakes(review): Enforce single-link ownership for custom check artifacts * no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs * no-mistakes(review): Separate task creation and legacy teardown validation * no-mistakes(review): Restore safe legacy operations and teardown validation * no-mistakes(review): Disambiguate migration obligations and preserve legacy retries * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits * no-mistakes(document): Document private poll artifact safety contracts * no-mistakes(lint): Suppress intentional literal-dollar lint finding * fix: migrate historical X poll identity * fix: harden PR check artifacts * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * fix: migrate historical X poll identity * no-mistakes(review): Harden X-mode artifact publication against symlink corruption * no-mistakes(review): Guard X artifact publication * no-mistakes(review): Enforce private X artifact reads * no-mistakes(test): Fix backend compatibility fixture dependencies * no-mistakes(document): Refresh PR-check documentation * no-mistakes(lint): Remove unused x-mode test locals * no-mistakes: apply CI fixes * fix(bin): compact session-start backlog digest (#636) * fix: compact session-start backlog digest * no-mistakes(test): Fix legacy backend fixture helper * no-mistakes(test): Fix watcher exit wait helper * no-mistakes(document): Document compact backlog digest * fix: dedupe stale watcher guard banners (#637) * fix: dedupe stale watcher guard banner * no-mistakes(review): Keep read-only guard state nonmutating * no-mistakes(document): Clarify stale watcher docs * fix(bin): balance bearings landed baseline (#640) * fix: balance bearings landed defaults * no-mistakes(document): Document balanced landed baseline * no-mistakes: apply CI fixes * fix: clarify captain-facing translation contract (#644) * docs: clarify captain-facing translation contract * no-mistakes(review): Restore runtime fallback mandate * no-mistakes(document): Align Bearings translation wording * fix(bin): make bootstrap output and nudges deterministic (#646) * fix: make bootstrap nudges deterministic * no-mistakes(review): Honor state override for bootstrap nudges * no-mistakes(review): Update benign bootstrap documentation labels * no-mistakes(review): Validate bootstrap nudge retry markers * no-mistakes(document): Align bootstrap nudge documentation * no-mistakes: apply CI fixes * docs(secondmate-provisioning): clarify concise registry ownership (#649) * Clarify concise secondmate registry contract * no-mistakes(review): Expand secondmate registry boilerplate coverage * no-mistakes(document): Point route docs to owner * fix(bin): strip quoted blocked_by values during decision hold resolve (#654) * fix(bin): strip quotes on blocked_by in decision-hold resolve tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary membership test only matched middle elements. Strip surrounding quotes before matching so first and last hold ids resolve correctly. * no-mistakes(document): Refresh decision-hold regression evidence * feat(secondmate): inherit shared captain preferences (#656) * feat(secondmate): inherit shared captain preferences * no-mistakes(review): Honor shared captain data overrides * no-mistakes(review): Honor bootstrap data override registry * no-mistakes(document): Refresh shared inheritance docs * no-mistakes(document): Clarify inherited local-material docs * feat: gate local agent secret injection (#658) * feat(spawn): gate local agent secret injection * fix(spawn): align final Keychain slot * no-mistakes: apply CI fixes * test: isolate Herdr autodetect smoke sessions (#662) * test: isolate herdr autodetect smoke session * no-mistakes(review): Restored autodetect smoke gate bypass * no-mistakes(test): Harden Herdr lab provisioning * no-mistakes(document): Refresh Herdr lab docs * docs: adopt under way for active work (#666) * Revert "feat: gate local agent secret injection (#658)" (#668) This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef. * fix(pi): distinguish stale locks when arming watcher (#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> #166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * feat(herdr): add optional presentation spaces (#784) * feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately * fix(send): treat opencode busy-queued composer state as submitted (#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable * fix(spawn): require two stable reads before accepting worktree path (#765) * fix(spawn): require two stable reads before accepting worktree path The treehouse-get worktree-detection loop in fm-spawn.sh accepted the first pane_current_path read that differed from the project path, but on some tmux/WSL setups a brand-new window transiently reports a stale-but-real path before the pane actually settles into the worktree. Since that stale path is itself a real, distinct git checkout, it also passes validate_spawn_worktree's isolation check, so the loop silently recorded the wrong worktree in state/<id>.meta (and, for claude harness spawns, installed the turn-end hook there too). Require two consecutive polls to agree on the same non-project path before accepting it, using the existing inter-poll sleep as the confirmation gap so an already-settled pane isn't slowed down by an extra cycle. * fix(tests): drop unused CASE_DIR read in worktree-settle test ShellCheck SC2034: CASE_DIR is split out of the case record but never referenced; discard it with _ instead. --------- Co-authored-by: Freudator86 <tim@allesknut.de> * fix(bin): make watcher process identity immune to Linux wall-clock changes (#752) * fix(watcher): stabilize Linux process identity * no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale * fix: prevent AFK idle stalls and stale run attribution (#758) * fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts * fix(bin): allow safe teardown during watcher recovery (#750) * fix: allow safe teardown during watcher recovery * no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code * no-mistakes(document): Sync continuity-gate docs to allow teardown recovery * test: mark dynamic teardown fixture literal * no-mistakes(document): docs: add teardown to continuity gate allow list * feat(herdr): order presentation spaces while preserving focus (#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation * fix(bin): send literal config reread nudges after pushes (#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation * feat(watch): follow GitLab merge requests to merge (#797) * feat(watch): follow GitLab merge requests to merge The merge watch only understood GitHub pull requests, so a task whose deliverable is a GitLab merge request was never followed to merge. Generalize the stored poll identity from owner/repository to a provider-tagged provider/url/host/path/number record. GitLab runs mostly on self-hosted instances and its projects nest under groups at no fixed depth, so the host and the full project path are data in the record rather than constants, and every consumer rebuilds the URL from those parts and refuses any record that does not reconstruct it exactly. The GitLab state is read with plain glab, matching the GitHub path's use of plain gh, so an upstream checkout needs no extra tooling. Two things about glab were established by running it rather than assumed, because a wrong invocation here fails silently into a permanent "not merged": - glab has no field selector, and its JSON would need a JSON processor that firstmate does not require, so the state is read from glab's own field output. Only an exact "merged" wakes firstmate, so a changed format stays silent instead of reporting a merge. - glab cannot take a merge request URL the way gh can, because that form resolves through the current git repository and the watcher has none. It is addressed by project URL and merge request number instead. An absent glab produces no wake rather than a false merge, and arming refuses with a clear message since that is the one point where a missing CLI can still be reported. A GitLab task records no pr_head, which both consumers already treat as optional. The merge path still addresses GitHub only and refuses a merge request URL rather than sending it to the wrong forge. The record version moves to v2, and the existing non-executing migration rebuilds an already-armed watch from its recorded URL, so no watch is lost by upgrading. docs/gitlab-merge-watch.md records the evidence, taken against the public fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture. * no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation * no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs * fix(herdr): group projected children beneath owning parents (#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck * fix: keep local no-mistakes tests intent-targeted (#823) * fix(no-mistakes): drop full-suite local Test override Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a focused contract test so the override cannot silently return. * no-mistakes(lint): Make CI contract assertion ShellCheck-clean * feat: add canonical timed test runner (#825) * feat(test): add canonical timed suite runner and honest CI timeout Introduce bin/fm-test-run.sh as the single serial owner for selecting one script, a family, a conservative changed-file set, or the explicit complete suite, with per-script timing markers and a JSON artifact. Wire CI Behavior through the runner, raise the hang-tripwire timeout to 25 minutes, and document entry points without restoring a full-suite local no-mistakes Test command. * no-mistakes(review): Captain: fix changed selection and empty summaries * no-mistakes(review): Captain: fail closed on unmapped changed sources * no-mistakes(document): Document canonical timed test entry points * fix: surface main inventory gaps in Bearings (#830) * fix: disclose main-home orphan and unstructured inventory gaps Main Bearings could report an empty fleet while structured in-flight rows lacked meta or current backlog rows were free-form. Emit main_inventory from the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next gate, and keep meta as the only live Underway source. * no-mistakes(document): Document Bearings inventory-integrity projection * no-mistakes: apply CI fixes * feat: add bounded concurrent test isolation proof (#832) * feat: add concurrent test isolation proof for Phase 2 Prove an audited portable candidate set passes under concurrent workers with private mode-0700 temp roots, without enabling production CI sharding or fm-test-run --jobs. * no-mistakes(review): Pin isolation proof to audited candidate manifest * feat: guard against missed secondmate reports (#834) * feat(secondmate): parent-owned guards for missed status reports Marked parent-to-secondmate requests now create a durable pending-reply expectation with a privacy-safe correlation id before delivery. Transport success never resolves it; only a correlated parent status or document pointer does. After a completed turn with no report, the parent sends one recovery repost and escalates once if that turn is also missed, without scraping the secondmate conversation or looping. * no-mistakes(review): Deduplicate wrong-home pending-reply sightings * no-mistakes(review): Harden pending-reply recovery and escalation guards * no-mistakes(review): Bound pending-reply backend polling * no-mistakes(review): Cache pending-reply status scans * no-mistakes(review): Protect undelivered pending-reply records from scans * no-mistakes(review): Close pending-reply delivery durability gaps * no-mistakes(review): Separate pending-reply transport outcomes * no-mistakes(review): Escalate stalled pending-reply deliveries once * no-mistakes(review): Resolve attempted deliveries from correlated reports * no-mistakes(review): Resolve late reports after delivery escalation * no-mistakes(document): Document pending-reply grace and ownership * no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings * feat: require pinned real-Herdr CI coverage (#838) * feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat: shard portable tests and add bounded local parallelism (#841) * feat: shard portable CI tests after isolation proof Balance the Phase 2 proven-isolated set into two LPT portable parallel lanes from Phase 1 timing evidence, keep stateful work in a required portable serial lane, exclude real Herdr to its dedicated required lane, and prove complete inventory coverage with a deterministic guard. Add bounded local --jobs only for the proven set, per-lane timing plus aggregate artifacts, and reduce the interim portable hang tripwire now that the serial remainder owns the long wall-clock path. * no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling * no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests * no-mistakes(document): Document portable sharding and timing aggregation * no-mistakes: apply CI fixes * fix: block primary-session delegation outside the fleet (#854) * feat: fence primary-session delegation outside the fleet A firstmate primary that delegates through Claude Code's built-in delegation tools creates work with no state/<id>.meta. Because fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits silently at zero, such work does not merely go unsupervised: it makes the whole guard stack structurally inert, and it dies with the primary session. On 2026-07-22 that cost two workers mid-flight and left supervision down for 73 minutes unnoticed. Layer 1, the primary fix: a permissions.deny list in .claude/settings.json removes the 18 delegation, scheduling, worktree, and task-tracking tools from the model's schema, so they are never offered. This is removal rather than interception, so there is no call to intercept and no fail-open path. The list is flat and in one file so its width stays reviewable; the captain owns that width. Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open against tools that do not exist yet, and permissions.allow is a pre-approval list rather than an availability list, so there is no fail-closed allowlist to use instead. This backstop classifies the tool NAME by shape rather than against a fixed list, so a delegation tool that ships before the deny list is updated is still refused. It excludes mcp__* names and observe-or-stop operations, scopes itself to a genuine primary home via the shared fm_primary_scope_matches predicate so a crewmate's task worktree is unaffected, and offers one deliberate FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch. Verified live against Claude Code 2.1.217, including a deny-key A/B with a nonsense-name control, layer 2 denying an un-denied Workflow call, the same call allowed in a linked worktree, and the escape hatch. Corrects a prior finding: both Task and Agent work as deny keys, so both are pinned. Codex 0.144.1 verified to expose no delegation tool; grok, opencode, and pi are inspected and documented as not wired because those binaries are absent from this host and the repo requires live validation before trusting a harness hook. Evidence in docs/subagent-guard.md. * no-mistakes(review): Ship scoped Claude delegation guard * no-mistakes(test): Ship Claude delegation deny list * no-mistakes(document): Clarify PreToolUse guard ownership * no-mistakes(lint): Keep Claude deny list local * fix: install tasks-axi in portable CI shards (#866) Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged. * feat(bin): make dispatch profiles quota aware (#867) * feat: make dispatch profiles quota aware * no-mistakes(review): Fix quota window and Grok product scoping * no-mistakes(document): Document implicit quota-aware dispatch accurately * Add built-in ahoy recap skill (#873) * fix: preserve trustworthy Bearings data in partial snapshots (#875) * fix: preserve mixed Bearings projections * no-mistakes(review): Enforce strict invalidity precedence for partial snapshots * no-mistakes(review): Enforce ownership for unknown child metadata * no-mistakes(document): Document partial structured Bearings projections * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat(pi): add session-local calm mode (#884) * Add session-local Pi calm mode * no-mistakes(review): Preserve Pi HTML exports during calm mode * no-mistakes(review): Preserve calm exports across submit bindings and share * no-mistakes(document): Document calm-mode feasibility across supported harnesses * fix(pi): prevent redundant watcher re-arms (#885) * fix(pi): limit watcher arm tool to recovery * no-mistakes(review): Strengthen Pi live re-arm regression coverage * no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming * fix(pi): clean up Calm transcript rendering (#895) * fix(pi): clean up Calm transcript rendering * no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs * no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations * no-mistakes(review): Restore Calm rows received while active * no-mistakes(review): Preserve diagnostics during Calm restoration * no-mistakes(document): Clarify Calm transcript behavior and injection paths * fix: execute every PR body compliance event (#898) * fix: execute every PR body compliance event * no-mistakes(document): Document independent PR compliance events * fix: exclude operational injections from ahoy boundaries (#899) * fix: distinguish operational input in ahoy * no-mistakes(review): Handle legacy Ahoy operational boundaries * no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions * no-mistakes(document): Document Ahoy operational marker ownership * no-mistakes(lint): Suppress intentional literal fixture lint warnings * fix: canonically classify operational inputs across harnesses (#909) * fix: type canonical operational inputs * no-mistakes(document): Correct canonical operational-input documentation ownership * fix: avoid generic secondmate start acknowledgements (#926) * fix: avoid generic secondmate acknowledgements * no-mistakes(document): Document sparse secondmate acknowledgement behavior * no-mistakes: apply CI fixes * fix(pi): make calm mode persistent and gapless (#927) * fix(pi): preserve calm presentation across sessions * no-mistakes(review): Fix Calm home fallback persistence * no-mistakes(document): Clarify Calm gapless and export contracts * no-mistakes: apply CI fixes * fix(watch): retire merged PR polls after durable notification (#932) * fix: retire merged PR polls after notification * no-mistakes(review): Decouple PR retirement recovery from template updates * no-mistakes(review): Recover pending PR retirements before poll migration * no-mistakes(document): Document merged PR poll retirement contracts * fix: refine scout intake and parallel dispatch (#934) * Clarify intake evidence and overlap handling * no-mistakes(review): Align scout guard with intake classification * no-mistakes(document): Clarify scout documentation and intake ownership * fix(pi): prevent duplicate assistant replies in Calm (#936) * fix(pi): preserve operational follow-up semantics in Calm * no-mistakes(document): Correct Calm operational-row visibility documentation * perf(bin): shrink the ShellCheck source graph (#939) * perf(lint): shrink shell source graph * no-mistakes(review): Ensure lint workers terminate fully on cancellation * no-mistakes(document): Repair stale lint documentation ownership * fix(pi): remove Calm hidden-block gaps (#942) * fix(pi): remove Calm hidden-block gaps * no-mistakes(review): Validate Calm geometry against current viewport * no-mistakes(review): Synchronize Calm geometry checks with reload completion * fix: enforce contract boundaries for ask-user findings (#945) * fix: escalate ask-user contract expansion * no-mistakes(document): Point project management to authority owner * docs: prefer direct operational paths (#946) * fix(pi): hide operational user rows in Calm mode (#948) * fix(pi): hide Calm operational user rows * no-mistakes(review): Narrow Calm operational input suppression * no-mistakes(review): Avoid Calm replay classifier subprocesses * no-mistakes(document): docs: point Pi verification to Calm owner * fix: relaunch missing second mates at session start (#950) * fix(session-start): relaunch missing second mates * fix(test): detect completed parallel workers * no-mistakes(review): Isolate session-start recovery test cleanup * no-mistakes(review): Complete backend-safe secondmate session recovery * no-mistakes(review): Resolve Zellij task ownership before recovery * no-mistakes(review): Recover relocated Zellij ghost tabs safely * no-mistakes(review): Restore conservative Zellij recovery boundary * no-mistakes(review): Reject malformed tmux recovery targets * no-mistakes(document): Align secondmate recovery documentation * no-mistakes: apply CI fixes * fix(herdr): reclaim resumed task projections after restart (#967) * fix(herdr): reclaim resumed task projections safely * no-mistakes(review): Enforce safe Herdr reclaim close boundaries * no-mistakes(document): docs: clarify Herdr restart projection contract * Teach Ahoy to surface open decisions (#968) * Require shipshape routine acknowledgement (#969) * docs: separate current guidance from verification evidence (#994) * docs: separate current guides from verification * no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence * fix: preserve Claude watcher continuity across Stop hooks (#997) * feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm Claude primaries (main home and marked secondmate homes) no longer depend on the model remembering to re-arm the watcher after each wake. A tracked Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s) fires on every turn end, claims one home-scoped single-flight owner, foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and translates an actionable close or typed watcher failure into exactly one exit-2 rewake. The hook scopes to genuine primary checkouts, requires the session lock to be held by its own harness ancestor, stays inert while AFK owns triage or the home is idle, and hands AFK transitions mid-cycle to the daemon without rewaking. The synchronous turn-end guard gains a --claude cooperative mode: it ignores stop_hook_active (true on every post-continuation stop, which is what re-opened the 2026-07-21 blind window), waits briefly for a watcher health proof, a live auto-arm owner claim, or a fresh rewake epoch, and re-blocks only when the auto-arm genuinely failed to establish - bounded to 3 consecutive blocks per session, safely below Claude Code's 8-block override, then a degraded allow with a visible systemMessage. Codex keeps the previous one-block loop guard byte-identically, and Pi, OpenCode, and Grok adapters are untouched. Continuity PreToolUse gate and durable wake queue are preserved; the gate's recovery guidance now names the Stop-owned re-arm and reserves manual background arms for auto-arm failure. Claude supervision protocol, harness-adapters facts, architecture, configuration, and continuity docs updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218 contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout process-group kill, 8-block cap, interactive non-stall) and the 2.1.219 product live E2Es. Regression matrix: hermetic tests cover scope, identity, AFK, need, single-flight, translation, guard cooperation, budget, and registration; the new live E2E proves two full tokenless auto-arm rewake cycles with zero model arm commands; Pi and OpenCode Option B live E2Es pass unchanged. * no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop * no-mistakes(review): Remove unsupported Claude contract-lab verification claims * no-mistakes(document): Update Claude auto-arm continuity documentation * fix(herdr): clean stale projections at session start (#996) * Clean stale Herdr projections at session start * no-mistakes(document): Document stale Herdr session-start projection cleanup * no-mistakes(review): Enforce locked exact Herdr projection cleanup * no-mistakes(review): Fail closed on unverified session lock ownership * no-mistakes(review): Serialize session lock acquisition atomically * no-mistakes(document): Align session-start and Herdr cleanup documentation * no-mistakes(document): Generalize lock-refusal diagnostics * no-mistakes(lint): Avoid reserved keyword in concurrency test * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: recover Claude supervision without watcher-status gate (#1001) * fix: recover Claude supervision at session start * fix: remove Claude watcher-status command gate * no-mistakes(document): docs: remove stale continuity gate references * fix: make quota-aware profile selection agent-owned (#1018) * Replace quota dispatch selector instructions * no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection * fix(bin): remove vestigial dispatch selector (#1026) * remove vestigial dispatch selector * no-mistakes(review): Synchronize isolation proof and portable shard evidence * no-mistakes(review): Correct shard history and proof archive date * no-mistakes(review): Remove reintroduced selector documentation reference * no-mistakes(document): Remove stale dispatch strategy documentation * docs(agents): drop superseded interim quota-window rule (#1039) quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per provider, so the successor named in the interim rule has landed and the rule's own removal condition is satisfied. Keep the ownership clause so quota-axi remains the single owner of how model or product windows relate to bounding account windows, and drop the interim weakest-headroom instruction. The unknown-semantics case is already covered by the existing requirement to stop and report a candidate whose applicable quota data or interpretation cannot be established. Drop the matching assertion phrase from tests/fm-instruction-owners.test.sh; the retained ownership phrase still asserts. * fix(tmux): scope busy detection and recognize current Claude turns (#1049) * fix(tmux): scope Claude busy detection by harness * no-mistakes(review): Separate verified and fallback busy signatures * no-mistakes(test): Scope busy signatures to supplied harnesses * no-mistakes(document): Document harness-scoped busy detection * feat: add verified Kimi crewmate adapter (#1047) * Add verified Kimi crewmate harness adapter * no-mistakes(review): Scope Kimi moon detection to spinner lines * no-mistakes(review): Match only complete Kimi spinner rows * no-mistakes(review): Resolve Kimi binary portably before pane creation * no-mistakes(document): Align Kimi adapter documentation * no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override * Fix Kimi busy spinner detection * no-mistakes(review): Recognize Kimi session-lock ancestry and holders * no-mistakes(review): Scope pending-reply Kimi busy detection by harness * no-mistakes(document): Correct Kimi spinner capture documentation * no-mistakes(document): Clarify optional Kimi spinner whitespace * no-mistakes(lint): Silence intentional pending-reply test stub warnings * test: align rebased Kimi busy fixtures * no-mistakes: apply CI fixes * Reconcile Kimi busy detection after per-harness scoping * no-mistakes(review): Clarify observed Kimi spinner whitespace contract * no-mistakes(document): Clarify Kimi harness documentation * fix: harden Kimi submission and spinner matching (#1058) * fix kimi pointer submission and spinner conformance * no-mistakes(review): Preserve Kimi submit target ownership guard * feat(bin): add guarded Kimi turn-end wake (#1059) * Add guarded Kimi turn-end hook * no-mistakes(review): Require jq before installing Kimi turn-end hook * no-mistakes(review): Expose jq inside isolated Kimi test fixtures * no-mistakes(review): Preserve Kimi config boundaries during hook removal * no-mistakes(review): Document Kimi removal newline safeguard * no-mistakes(document): Document Kimi shared-home preservation * fix(tmux): classify bordered composers across all rows (#1066) * Fix structural tmux composer reading * Verify Calm compatibility with Pi 0.82 * no-mistakes(review): Harden structural composer classification boundaries * no-mistakes(review): Refresh composer and Kimi regression fixtures * no-mistakes(review): Fail closed on unbounded composer edges * no-mistakes(review): Enforce aligned composer geometry safely * no-mistakes(review): Make composer ambiguity locale-safe * no-mistakes(review): Preserve ambiguity through composer submission * no-mistakes(review): Carry composer proof through retries * no-mistakes(document): Document structural tmux composer delivery guarantees * no-mistakes: apply CI fixes * feat(bin): add verified pi-signed runtime adapter (#1145) * feat: add verified pi-signed adapter * no-mistakes(review): Correct pi-signed maintainer verification date * no-mistakes(review): Correct remaining pi-signed verification dates * no-mistakes(review): Preserve authoritative pi-signed runtime identity * no-mistakes(document): Document pi-signed shared adapter semantics * no-mistakes: apply CI fixes * fix(pi): rearm watcher across session transitions (#1166) * fix(pi): rearm watcher across same-process session transitions Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement as well as terminal quit. The primary watcher extension latched a module-level stopping flag on every shutdown, so a replacement session in the same process could not arm monitoring until Pi restarted. Own arm authority per session generation so only the active live generation may start, stop, or rearm the child. Replacement sessions can arm again without restarting Pi, stale prior-generation callbacks cannot mutate the active cycle, and real quit still blocks late rearm. * no-mistakes(review): Preserve Pi generation isolation and exit cleanup * no-mistakes(document): Correct Pi watcher transition documentation * feat: route crew dispatch using quota-window pace (#1172) * Consume quota-axi pace signals in dispatch profile array selection. Add quota-array-dispatch as the single owner of the pace-aware candidate choice, keep AGENTS.md to the intake boundary and load trigger, and cover the acceptance cases with sanitized schemaVersion 3 fixtures. * no-mistakes(review): Stop and report genuine quota dispatch ties * no-mistakes(document): Document quota pace freshness and uncertainty * fix: adapt Grok Stop continuation and harden endpoint cleanup (#1171) * fix(grok): adapt Stop continuation to runtime capability * no-mistakes(review): Reject ambiguous Grok Stop payloads * no-mistakes(review): Reject duplicate Grok fields and accept spaced tmux sessions * no-mistakes(review): Enforce exact tmux cleanup selectors * no-mistakes(test): Fix historical tmux fixture and validate Grok Stop * no-mistakes: apply CI fixes * fix: restore stock macOS Bash 3.2 brief scaffolding (#1093) * fix(brief): make DOD scaffolding parse-safe on stock macOS Bash 3.2 fm-brief.sh built each Definition-of-done block and the not-enabled Herdr declaration with `VAR=$(cat <<EOF ... EOF)`. On Bash 3.2 (macOS /bin/bash) the lexer scans for the command substitution's closing `)` textually and tracks quote state through the heredoc body, so a single apostrophe, unbalanced quote, or unbalanced paren in that prose breaks parsing of the whole script. Every ship-brief scaffold (no-mistakes, direct-PR, local-only) failed with `unexpected EOF while looking for matching )`. Bash 4+ parses it fine, so the breakage stayed invisible everywhere except stock macOS. Replace all four command-substitution heredocs with `IFS= read -r -d '' VAR <<EOF || true`. That removes the `$(...)` wrapper and the entire defect class regardless of future prose, and preserves the variable expansion the direct-PR and local-only bodies need. `read` keeps the heredoc's trailing newline that `$(...)` used to strip, so trim one newline to keep every generated brief byte-identical to prior output. Guard the structure, not one historical phrase: a new test rejects any heredoc nested in a command substitution anywhere in fm-brief.sh, where the old assertion pinned a single apostrophe phrase and so missed the reintroduction. Extend the stock-macOS Bash CI job from parsing one script to the whole maintained shell surface (bin/*.sh, bin/backends/*.sh, tests/*.sh), matching bin/fm-lint.sh's canonical file set so parse scope and lint scope cannot drift apart. * no-mistakes(review): Captain: harden Bash structure and inventory guards * no-mistakes(document): Align stock macOS Bash contributor checks * no-mistakes(lint): Suppress deliberate SC2016 literal fixture warnings * test: stabilize tmux teardown conformance baseline (#1209) * fix(test): pin teardown tmux baseline to historical kill selectors merge-base HEAD main collapses to HEAD after the exact-selector change lands on the default branch, so the old teardown fixture was accidentally exercising current exact targets. Resolve a content-historical permissive tmux adapter from first-parent history and force that post-squash topology inside the conformance case so main and feature branches keep the same old-vs-new contract. * no-mistakes(lint): Suppress intentional literal-pattern ShellCheck warnings * docs: slim quota-array-dispatch to the pace selection core (#1197) Cut the runtime skill to the compact pace-aware selection procedure plus minimum owner pointers. Keep every distinct decision rule and move expanded acceptance scenarios to deterministic fixture ownership assertions. Size: 170/1374/10187 -> 63/544/4068 (about 63%/60%/60% reduction). * feat(bin): inherit backend config into secondmate homes (#1219) * Inherit config/backend into secondmate homes with deliberate-override preservation Add backend to the shared inheritable config allowlist so launch, locked bootstrap, and config-push converge a primary pin into secondmate homes as each home local future-spawn default. Track last-inherited bytes in a private state provenance marker so deliberate per-home overrides survive present and absent primary convergence, keep --backend and FM_BACKEND stronger, and extend the existing inheritance tests plus docs and skill claims. * no-mistakes(review): Preserve equal unprovenanced backend overrides * no-mistakes(review): Preserve symlink overrides and verify spawn precedence * no-mistakes(review): Snapshot backend inheritance for consistent provenance * no-mistakes(review): Simplify backend inheritance to primary-authoritative convergence * no-mistakes(document): Document inherited backend override preservation * fix: restore primary-authoritative backend inheritance after document regression The document step reintroduced provenance and deliberate per-home override semantics after review had simplified config/backend to plain primary-authoritative allowlist membership. Restore the primary-always-wins path: present overwrites, absent removes, no provenance marker, and docs/tests match that contract. * no-mistakes(review): Add divergent backend precedence regression fixtures * no-mistakes(document): Document backend inheritance contract * fix(pi): remove Calm's upper version ceiling (#1226) * fix(pi): remove Calm's exclusive Pi upper-version ceiling tests/fm-calm-pi-extension.test.sh gated on a closed PI_COMPAT_VERSIONS allowlist ("0.81.1 0.82.0") that refused any other installed Pi, and docs described that range as "supported" rather than verified evidence. The Calm CHANGELOG shows no API introduced at either version, so there is no evidence for a real minimum; the presentation adapters already probe the exact method they patch rather than checking a version. Replace the allowlist with dated version evidence that never rejects a newer Pi, and make each presentation adapter degrade independently with a diagnostic if a future Pi removes its API, instead of the whole Calm extension failing to load. Rewrite the feasibility doc's "Pi 0.81.1 through 0.82.0" phrasing to state it as verified evidence, not a ceiling. * no-mistakes(review): Probe missing Calm adapter exports safely * no-mistakes(document): Document Calm's unbounded Pi compatibility * fix(bin): allow session-local todo tools in the subagent guard (#1204) * fix(guard): allow session-local todo tools in the primary The delegation-shape guard denied TaskCreate and TaskUpdate because their normalized names contain the `task` stem. Those tools write only the harness's session-local todo list, which has no executor: it spawns no agent, allocates no worktree, registers no schedule, and starts nothing that outlives the session. That is not the unaccounted work the guard exists to stop, so the stem match was a false positive, and the deny text told the primary to run bin/fm-brief.sh and bin/fm-spawn.sh to create a todo entry. Add a separately-reasoned PLAN_ONLY_TOOLS exact-name exclusion rather than widening OBSERVE_ONLY_TOOLS, whose documented contract is tools that only observe or stop existing work. Both lists stay exact-name so neither can widen by substring. Tests cover the two allowed names and six near-miss names that a substring or shortened-stem widening would release; both mutations were watched red. * no-mistakes(review): drop session-local todo tools from recommended deny list * no-mistakes: apply CI fixes * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid (#1206) * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid fm_harness_ancestry_pid() previously returned the first ancestor process whose command matched a verified harness name. Claude Code's Stop hook fires as a bg-spare worker several levels below the session's actual lock-owning claude process (hook shell -> claude bg-spare -> claude bg-pty-host -> claude -> claude(lock)), so the first match was the bg-spare worker, not the lock owner. fm_session_lock_owned_by_self() then never matched state/.lock, and the Claude Stop auto-arm silently treated its own primary session as an unrelated live owner and never armed the watcher. The walk now keeps going past a claude-named match, looking for a still more ancestral claude-named match, and stops the instant a non-match follows an already-found match (bounding it to a contiguous run rather than the literal ancestry top, so an unrelated claude-named process further up the real process tree is never mistaken for part of this session's own nested chain). Every other harness keeps the original first-match-wins behavior, since e.g. Pi's shared signed-wrapper ancestry actually holds the session at the inner engine pid, not an outer wrapper pid. Hop limit raised from 8 to 16 to cover the deeper bg-spare chain. * no-mistakes(review): Add nested-claude-ancestry regression test; fix nudge doc depth claim * no-mistakes: apply CI fixes * fix: conferma l'avvio del watcher su Windows/MSYS (#1212) * fix: confirm watcher startup on MSYS * no-mistakes(review): gate MSYS arm ready timeout, cache uname, harden locale test * no-mistakes(review): validate OpenCode ready timeout, make uname cache internal * fix(spawn): forward CLAUDE_CONFIG_DIR to claude crewmates (#1195) * fix(spawn): forward firstmate's CLAUDE_CONFIG_DIR to claude crewmates Crewmate panes are created by a long-lived tmux/herdr daemon that does not inherit firstmate's current environment. When firstmate runs under a non-default CLAUDE_CONFIG_DIR (for example a work-vs-personal subscription split), a bare `claude` in the crewmate pane fell back to the default ~/.claude store and launched unauthenticated, blocking the crewmate before it could do any work. fm-spawn now prefixes the claude launch with firstmate's own resolved CLAUDE_CONFIG_DIR when set, so the crewmate uses the same credential/config store firstmate is authenticated with. An unset value is the single-store default and adds no prefix; non-claude harnesses are unaffected. Adds three tests in fm-spawn-dispatch-profile.test.sh (forwarded-when-set, omitted-when-unset, non-claude-ignored) and pins CLAUDE_CONFIG_DIR in the test helper so launch assertions no longer depend on the developer's environment. * no-mistakes: apply CI fixes * fix: preserve dispatch identity across authentication checks (#1233) * fix: preserve dispatch harness identity * no-mistakes(review): Fix Grok counterfactual tuple validation * no-mistakes(document): Scope dispatch authentication to selected tuple * fix: restore dispatch instruction budget * no-mistakes(review): Scope dispatch authentication after candidate selection * fix(bin): normalize relative durable paths (#1256) * fix(bin): handle dash-leading harness process names (#2) * fix: handle dash-leading harness process names * no-mistakes(review): Make dash-leading harness regression hermetic * fix: preserve secondmate reply routes across relative homes Resolve relative home, data, and state inputs before durable charter generation, and fail when caller-relative directories cannot be resolved. Use absolute paths at the related spawn, AFK daemon, and X-mode cross-process handoffs so later processes cannot reinterpret them from another working directory. * no-mistakes(review): Preserve absolute overrides and normalize relative durable paths * no-mistakes(review): Normalize relative home before deriving durable paths * no-mistakes(document): Document relative durable-path normalization * no-mistakes(review): Captain: Ignore inherited CDPATH during relative path normalization * no-mistakes(lint): Fix empty CDPATH assignments for ShellCheck * refactor(skills): make Bearings chat-only by default (#1136) * Add internal status skill * no-mistakes(document): register /status skill in documentation-audiences inventory * no-mistakes(lint): replace grep|wc -l with grep -c in status skill test * test: silence literal status skill patterns * Refactor bearings default to chat-only --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> * Clarify follow-up routing during validation (#1277) * fix: honor concrete approval for project operations (#1272) * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * no-mistakes(review): Align project removal preflight with approved exception * no-mistakes(document): Align project removal documentation with approved exception * fix: restore removal test byte-for-byte and preserve the default sentence tests/fm-instruction-owners.test.sh had been changed to assert different text; restore it byte-for-byte to origin/main. project-management SKILL.md's Remove section now keeps the exact default "Never issue a raw removal command from Firstmate." sentence that test still asserts, immediately followed by the already-approved captain-operation-or-scope exception, so the default and the exception both stay explicit and consistent. * no-mistakes(document): Align project-write boundary documentation * fix(skills): route new project intake through secondmate scopes (#1275) * Route project intake through secondmate scopes * no-mistakes(test): Guard all main-home project registry mutations * no-mistakes(document): Consolidate secondmate routing documentation * no-mistakes: apply CI fixes * Restore new-project routing scope * no-mistakes(document): Clarify secondmate routing for new-project intake * no-mistakes: apply CI fixes * fix: scope validation corrections by accepted behavior (#1281) * fix: scope validation corrections by accepted behavior * no-mistakes(review): Classify stale delivery evidence as an autonomous correction * test: replace source assertions with behavioral coverage (#1282) * test: remove source-content assertions * no-mistakes(review): Replace source assertions with runtime behavior coverage * no-mistakes(review): Isolate Kimi task temp runtime coverage * no-mistakes(document): Refresh test cleanup documentation * no-mistakes: apply CI fixes * fix(watch): escalate busy workers with no completed turn (#1286) * fix(watch): bound how long a busy pane may run with no completed turn A busy pane (backend busy state or the harness's rendered footer) was unconditional, unbounded proof of liveness in every escalation path, so a hung foreground tool call behind a busy signature could run for hours undetected (2026-07 hibit-agent-focus-nonsteal-r1 incident: a catastrophic- backtracking regex hung one bash call for 25h behind an unchanging "Working..." footer). FM_BUSY_TURN_MAX_SECS (default 3600s) now bounds how long a busy pane may run with no completed turn (state/<id>.turn-ended, or its spawn record before any turn has completed). Past the bound, busy_turn_over_age routes the pane through the existing wedge_timer_check, reusing the identical stale reason, escalation counter, and demand-deep-inspection marker for human inspection only - never an automatic interrupt, signal, or restart of the worker or its tool process. A completed turn resets the age. Reproduced end-to-end against the real installed Pi TUI: a foreground `sleep 999999` bash call with no timeout renders the actual busy footer, and two captures ~15s apart show the elapsed counter changing the pane hash while the same turn stays unfinished. Running the pre-fix watcher against the real captures showed it never starts a wedge timer no matter how long the pane stays busy; the fixed watcher starts and escalates the timer through the same mechanism, while the real hung process remained untouched and alive throughout. * no-mistakes(review): fix: parse enriched AFK stale reasons * no-mistakes(review): fix: preserve enriched wedges during AFK supervision * no-mistakes(review): fix: route all enriched AFK wedges * no-mistakes(document): Clarify busy-turn age supervision documentation * fix(gitignore): ignore config/ as a directory, not by exact filename (#1261) A name-by-name list of config/ entries silently stops ignoring any new or home-local file placed there, which makes the working tree read as dirty and blocks guarded sync paths that refuse to touch a dirty home. AGENTS.md already documents config/ as captain-private and gitignored as a category; this makes .gitignore match that contract. * fix(tests): replace source-content .gitignore assertion with behavioral coverage (#1304) The second assertion in fm-gitignore-config.test.sh (added by #1261) greps .gitignore for a specific spelling of the config/ ignore pattern. It fails on a semantically equivalent pattern like config/** and does not prove Git actually ignores anything, per the completed source-content-test audit. Replace it with a real git check-ignore control test on a generated unrelated path, and strengthen the existing directory-coverage test with generated unpredictable direct and nested config/ paths. * feat: bound and consolidate startup memory during stow (#1303) * Add bounded startup memory curation * no-mistakes(review): Record reproducible stow verification evidence * no-mistakes(review): Validate inherited secondmate stow evidence * no-mistakes(document): Do…
DereKk8
added a commit
to DereKk8/firstmate
that referenced
this pull request
Aug 15, 2026
* fix: reconcile existing AGENTS.md safely (#405)
* fix(agents-md): inject self-governance section into existing AGENTS.md
fm-ensure-agents-md.sh only appended the canonical "## Maintaining this
file" section on skeleton create or CLAUDE.md promotion, so an existing
AGENTS.md that lacked it exited unchanged and forced hand-copying the
wording during a rollout across existing projects. Call the already-
idempotent ensure_maintenance_section on the existing-AGENTS.md paths and
report whether the file changed; a re-run and an already-complete file stay
byte-identical.
Also fixes #389: refuse a case-variant real memory file (e.g. a lowercase
agents.md) instead of silently emitting a CLAUDE.md symlink whose uppercase
literal target dangles once the tree lands on a case-sensitive filesystem.
Tests extend tests/fm-ensure-agents-md.test.sh; skeleton-create and
CLAUDE.md-promotion regressions still pass. Docs updated to match.
* no-mistakes(review): Captain: preserve CRLF maintenance-section idempotency
* no-mistakes(review): Preserve CRLF during maintenance-section injection
* no-mistakes(review): Captain: harden dangling-symlink regression coverage
* no-mistakes(document): Document agent-memory injection outcomes
* feat: support project-less secondmate homes (#409)
* feat(secondmate): support project-less homes via --no-projects
fm-brief.sh --secondmate and fm-home-seed.sh now accept an explicit
--no-projects signal to scaffold, seed, and register a secondmate home
whose subject is the firstmate repo itself (no clones). The signal is
mutually exclusive with a project list; omitting both still fails loudly
so an accidental omission is never a silent project-less seed. The
registry line renders an empty projects: field, which spawn and the
snapshot already tolerate. Docs updated in the secondmate-provisioning
skill and both script headers.
* no-mistakes(review): Captain: document project-less secondmate flow
* no-mistakes(review): Captain: refuse project-less reseeding of populated homes
* fix(seed): fail closed on unreadable project data
* no-mistakes(review): Captain: reject stale projectful charters
* no-mistakes(review): Captain: fail closed on unsafe project paths
* no-mistakes(review): Captain: validate project-less charter clone sections
* no-mistakes(document): Document project-less secondmate seeding
* fix: delegate backlog handoffs to tasks-axi (#411)
* wip(handoff): record verified delegation design + tasks-axi mv blocker
No production code changed yet. tasks-axi mv (v0.2.1) cannot atomically
move a blocked-by-linked item set across backlogs (deadlocks both orders,
no batch/--force), which fm-secondmate-lifecycle-e2e requires. Parked
pending a tasks-axi connected-set mv enhancement; note captures the
verified design, semantics, test/CI/doc changes, and resume checklist.
* refactor(handoff): delegate the item move to tasks-axi mv
fm-backlog-handoff.sh's two-pass awk was a second parser of the backlog
format and the source of the PR #401 body-orphaning drift. Delete it and
delegate the move to `tasks-axi mv <id>... --to <dest>` (v0.2.2 atomic
multi-id), the single owner of the format: a connected set (blocker plus
dependents) moves together with blocked-by preserved, item blocks stay
byte-exact, and destination section placement holds. The helper keeps only
the fleet-level validation tasks-axi cannot know - secondmate-home
resolution, the seeded-home safety checks, the In-flight refusal, and
idempotent per-key reporting - and is atomic: on any move failure nothing
moves.
Tests: fm-backlog-handoff.test.sh keeps PR #401's regression matrix but now
exercises the delegated path and skips cleanly when tasks-axi is absent; the
two whole-file fixtures move to tasks-axi's canonical whitespace. The
lifecycle-e2e and safety move-cases gain the same skip guard. CI installs
tasks-axi so the delegated path is exercised. Docs state that
config/backlog-backend=manual governs firstmate's own hand-editing, not this
validated helper, which delegates fleet-wide because bootstrap requires
tasks-axi on PATH.
Remove the now-redundant WIP design note.
* no-mistakes(review): Captain: harden atomic backlog handoffs
* no-mistakes(review): Captain: enforce queued-only backlog handoffs
* no-mistakes(review): Captain: harden handoff section parsing
* no-mistakes(document): Document delegated backlog handoffs
* no-mistakes(lint): Silence ShellCheck source diagnostics
* fix: ignore secondmate home marker during sync (#417)
* fix: gitignore the secondmate home marker
bin/fm-home-seed.sh writes an untracked .fm-secondmate-home marker into
every seeded secondmate home. A secondmate home is a worktree of the
firstmate repo, so any plain `git status --porcelain` dirtiness check
counted the untracked marker and the home read as dirty forever:
fleet-sync reported it STUCK and the local fast-forward convergence
sweeps risked leaving it stale on firstmate updates.
Add .fm-secondmate-home to the tracked .gitignore so the marker is
invisible to every dirtiness check uniformly, without weakening
fleet-sync's deliberate untracked-counting for project clones.
Convergence chicken-and-egg: existing homes predate the fix and it only
arrives by fast-forward. The already-present marker-tolerant ff-skip
(ignore_seed_marker=yes, used by the bootstrap sweep, /updatefirstmate,
and spawn pre-launch) advances such a home past the fix commit, after
which .gitignore takes over - no hand intervention.
Tests in tests/fm-secondmate-sync.test.sh cover a freshly seeded home
reading clean, an existing marker-only home converging then reading
clean, and a genuinely dirty home still skipping.
* no-mistakes(review): Captain: document standalone-clone update path
* no-mistakes(document): Document secondmate marker migration
* fix(composer): prevent dead-shell message injection (#416)
* fix(composer): stop reading dead-shell prompts as empty agent composers
Consolidate composer empty/pending/unknown classification into one shared
owner, bin/fm-composer-lib.sh's fm_composer_classify_content, delegated to by
all four backend adapters (tmux via fm-tmux-lib.sh, herdr, orca, cmux). This
replaces four drifting copies of the glyph decision.
Safety fix: a bare shell prompt glyph (> $ % #) on an unstructured row is now
classified unknown (a dead shell, unsafe for injection), not empty. It is only
empty inside a bordered composer box (the harness's own prompt). Agent glyphs
❯ (claude) and › (codex) read empty either way. The away-mode injector
(inject_msg) now requires an affirmatively-empty composer, deferring on pending
or unknown, so an escalation can never be typed into (or executed by) a pane
whose agent exited to its login shell.
Regression coverage: new tests/fm-composer-lib.test.sh pins the shared owner;
per-backend dead-shell tests in fm-daemon (tmux + injector), orca, and the
existing herdr/cmux suites. shellcheck clean; herdr incident regressions stay
green.
* no-mistakes(review): Captain: harden composer safety checks
* no-mistakes(test): Stabilize Herdr prune safety setup
* no-mistakes(document): Document composer injection safety
* no-mistakes(lint): Clean composer safety lint
* no-mistakes: apply CI fixes
* feat(watcher): add paused external-wait supervision (#421)
* feat(watcher): add paused/awaiting-external crew state
A crew (or firstmate steering it) can declare a deliberate wait on a known
external dependency with a paused: <reason> status. Both the always-on watcher
and the away-mode daemon absorb such an idle pane through shared fm-classify-lib.sh
vocabulary instead of tripping the possible-wedge stale escalation, and re-surface
it for a recheck only on a long bounded cadence (FM_PAUSE_RESURFACE_SECS) so a
forgotten pause cannot rot invisibly. fm-crew-state.sh reports state: paused
distinctly. A crew that goes idle without declaring a pause classifies exactly as
before. Docs and brief scaffold state lists updated; tests colocated.
* no-mistakes(review): Captain: fix paused-state transitions
* init
* no-mistakes(review): Captain: fix paused-state supervision transitions
* no-mistakes(review): Captain: fix paused supervision handoffs
* no-mistakes(review): Reconcile paused supervision markers
* no-mistakes(review): Captain: prioritize paused states over captain relevance
* no-mistakes(review): Captain: preserve paused-working wedge timer
* no-mistakes(review): Captain: honor configured pause verb in briefs
* no-mistakes(test): Captain: fix AFK paused watcher handoff
* no-mistakes(document): Document declared external waits
* no-mistakes(lint): Clean paused-state lint
---------
Co-authored-by: fmtest <fmtest@example.invalid>
* fix: preserve X-mode follow-up platform limits (#425)
* fix(x-mode): make follow-up platform splitting immune to link ordering
A ~470-char Discord follow-up posted as a (1/2)(2/2) thread split at ~280
chars because fm-x-link only learned the platform from the inbox payload,
and the fmx-respond ack path can drain that inbox file before the task is
linked. A link recorded after cleanup silently lost the platform and the
splitter defaulted to the X 280-char budget.
Make platform resolution ordering-proof:
- fm-x-link now resolves the platform AUTHORITATIVELY by request_id via a
new fmx_request_relay_context helper (POST /connector/request-context)
when neither the inbox payload nor carry flags carry it. The request_id
survives the inbox drain, so a post-cleanup link still learns the right
split budget. Best-effort: no token/curl or a non-2xx relay degrades to
the loud warning below rather than a silent X default.
- fm-x-link warns loudly when no platform source resolves, so the loss is
never silent.
- The fmx-respond procedure now orders link-before-inbox-cleanup so the
fast local path stays correct without a relay round-trip.
Colocated regression tests: a Discord follow-up >280 <2000 posts as ONE
message even when linked after inbox cleanup, and an unresolvable platform
warns loudly instead of splitting silently. docs/configuration.md documents
the request-context lookup.
The relay endpoint is the companion durable change (see done status); until
it ships, the link-before-cleanup reorder keeps the normal path correct.
* no-mistakes(document): Document X-mode platform recovery
* fix(composer): handle ANSI ghost text safely (#429)
* fix(composer): one ANSI-aware ghost owner covers claude dim + grok truecolor
Away-mode injection wedged all night on the primary claude-on-herdr pane:
the herdr composer classifier never stripped generic dim ghost text (only a
narrow codex bold-wrapped byte-pattern check), so claude's rotating
prompt-suggestion ghost - a bare "❯" then SGR-2 dim text, which herdr's ANSI
pane read preserves - read as real pending input and every escalation deferred
(6524 lifetime "pending input (non-empty composer)" defers; wedge 30623s).
Consolidate ghost extraction into one fleet-wide ANSI-aware owner,
fm_composer_strip_ghost (bin/fm-composer-lib.sh), that drops every
de-emphasised run - dim/faint (SGR 2: claude, codex) AND a dark/muted truecolor
foreground (grok's placeholder, luminance below FM_COMPOSER_GHOST_LUMA_MAX,
default 128, dark-theme assumption). Both ANSI-capable backends route through
it: fm_tmux_composer_state (fm_tmux_strip_ghost is now a thin adapter) and
fm_backend_herdr_composer_state. The herdr-only faint byte-pattern check is
removed and fm_backend_herdr_strip_ansi reduced to a thin adapter over the
shared fm_composer_strip_ansi. Bordered detection now reads the plain row so a
dark box border dropped with the ghost does not lose the composer shape.
This also closes the documented grok TRUECOLOR placeholder gap by the same
mechanism (harness-adapters skill note updated).
Empirical evidence (read-only live capture + isolated tmux, no herdr lifecycle)
and the incident write-up are in docs/herdr-backend.md; deterministic
regressions feed the exact captured bytes through the real classifiers
(tests/fm-backend-herdr.test.sh, tests/fm-composer-ghost.test.sh). Two prior
ghost-test fixtures that used a near-black 38;2;1;2;3 as "real" colored text
(never a realistic real-input color) are corrected to a bright 38;2;224;222;244,
preserving the truecolor payload-skip parser intent.
* no-mistakes(review): Preserve dark shell prompt safety
* no-mistakes(review): Harden erased shell prompt classification
* no-mistakes(document): Document shared composer ghost extraction
* no-mistakes(lint): Normalize tmux comment punctuation
* fix(spawn): make tmux window handling robust under non-default config (#134)
* test: isolate session-start suite from ambient harness markers (#432)
* fix(session-start): isolate harness env markers in suite runner
Neutralize CLAUDECODE, PI_CODING_AGENT, and GROK_AGENT in
run_session_start so ambient interactive shells cannot override the
suite's fake ps harness (local-vs-CI split on the pi supervision case).
* no-mistakes(document): Correct Pi marker documentation
* fix(teardown): retry transient index locks during worktree return (#435)
* fix(teardown): retry treehouse return on transient index.lock
Killed crew git ops can leave a short-lived worktree index.lock that
makes treehouse return fail. Retry on that error signature with a
bounded wait (env-overridable), never force-delete a live lock, and
only then fall back to the existing provably-stale cleanup path.
* no-mistakes(review): Harden teardown retry configuration
* no-mistakes(document): Document teardown index-lock retry behavior
* no-mistakes(lint): Fix empty shell variable assignments
* fix: complete brief help and consolidate documentation (#438)
* docs: de-feature the scripts.md and CONTRIBUTING test inventories
Slice 1 of the documentation redundancy cleanup wave (firstmate scope).
docs/scripts.md: every row is now one purpose clause; script headers
are the declared owner of behavior, flags, and contracts. Coverage
stays 61/61 scripts; bytes drop 19,922 -> 7,958.
CONTRIBUTING.md: the 54-row per-test inventory is gone; contributors
discover tests by listing tests/*.test.sh and reading each script's
own header, and gated tests print their own skip gates. The run
commands, symlink assertions, and watcher smoke line are unchanged.
Lines drop 135 -> 84 (18,797 -> 7,831 bytes).
Two facts that existed only as inventory rows moved into their
owners' headers first: fm-brief.sh's paused-vs-blocked scaffold
distinction and fm-session-start.sh's Pi extension-loaded check.
No instruction-surface or behavior change; AGENTS.md untouched.
* no-mistakes(review): Captain, fix brief help and Grok test discovery
* no-mistakes(review): Captain: document Grok lock-holder test coverage
* fix: detect Git and centralize backend configuration (#445)
* docs: consolidate universal backend contracts into configuration.md
Slice 2 of the documentation redundancy cleanup wave (firstmate scope).
docs/configuration.md is now the declared single owner of three
universal contracts, each with an explicit ownership sentence:
- the universal toolchain list (Toolchain), now also carrying the
per-tool purpose clauses that previously lived only in the tmux guide;
- the task-selector vocabulary (Runtime backend);
- the tasks-axi compatibility definition (Backlog backend).
The five backend guides' prerequisites replace their verbatim
universal-requirements parentheticals (5 full copies) with a pointer
plus only backend-specific items; zellij/cmux selector restatements
and architecture.md's partial copy become pointers or are dropped;
CONTRIBUTING's compatibility sentence becomes a pointer; two
near-verbatim orca-bootstrap restatements (configuration.md Runtime
backend, orca guide) collapse into the Toolchain owner copy.
Backend-specific setup, behavior, target-string shapes, and every
empirical verification record are untouched. AGENTS.md untouched
(slice 3).
* docs: include git and GitHub auth in the toolchain owner list
The review flagged that the new universal-toolchain owner omitted git
and GitHub authentication while every backend guide now defers its
prerequisites here; bootstrap's NEEDS_GH_AUTH check makes them real
universal requirements.
* no-mistakes(review): Detect Git in bootstrap toolchain
* no-mistakes(document): Clarify GitHub CLI and centralize selector documentation
* feat(daemon): add backend-independent wedge alerts (#444)
* feat(daemon): backend-independent active alert for the wedge alarm
When away-mode injection wedges past max-defer, inject_wedge_alarm only
actively signalled via the tmux status-line, which is skipped on non-tmux
backends. A wedged claude-on-herdr primary left only the passive
state/.subsuper-inject-wedged marker (2026-07-10 overnight incident).
Add a config-gated active alert (config/wedge-alarm, local/gitignored;
FM_WEDGE_ALARM_CHANNEL) that reaches the captain even when every pane and
its status-line is unreadable: an OS-level macOS notification (osascript),
a herdr notification, or a captain-supplied command. Default-on (auto) so
the alarm is never silent; each channel best-effort, degrading to the next
and never crashing the daemon loop. The tmux flash and durable marker stay.
The OS notifiers route through a single FM_WEDGE_ALARM_EXEC seam. When the
daemon is sourced (only tests do this; production execs it) the seam
defaults to "discard", and tests/wake-helpers.sh points it at a recorder,
so it is structurally impossible for any test to post a real notification.
Channels verified once manually on macOS 26.5.2 / herdr 0.7.3; see
docs/wedge-alarm.md.
* no-mistakes(review): Bound wedge alarm notifier execution
* no-mistakes(review): Captain: harden wedge alarm notifier safety
* no-mistakes(review): Captain: harden wedge alarm test notifier isolation
* no-mistakes(review): Captain: harden wedge alarm throttling
* no-mistakes(review): Redact wedge alarm directive logs
* no-mistakes(review): Harden wedge alarm notifier safety
* no-mistakes(review): Track notifier process groups through cleanup
* no-mistakes(document): Document wedge-alarm active alert behavior
* docs: centralize firstmate operating contracts (#447)
* docs(agents): extract conditional AGENTS.md material to owned homes
Slice 3 of the documentation redundancy cleanup wave (firstmate scope):
the always-loaded instruction surface drops from 941 lines / 116,733
bytes (~29k tokens per session per fleet member) to 785 / 91,353
(~22.8k tokens), moving only audit-identified conditional and
situational material while preserving every load-bearing invariant at
its trigger point via the inline-stub pattern.
Moves, each to one declared owner plus an inline stub:
- section 3's bootstrap output-line handbook (~44 lines) -> new
agent-only bootstrap-diagnostics skill, added to the section 13
trigger index; the detect-consent-install rule and the
do-not-dispatch gate stay inline as safety-critical.
- section 4's crew-dispatch JSON schema and field semantics ->
docs/configuration.md 'Crew dispatch profiles' (pointer direction
flipped); the intake procedure, precedence, backstop, and
never-select-unverified rules stay inline.
- section 4's quota-balanced algorithm -> bin/fm-dispatch-select.sh
header (now the declared owner; usage() converted to the dynamic
header extraction pattern PR #438 established for fm-brief.sh).
- section 7's spawn resolution narrative and example sprawl ->
bin/fm-spawn.sh header; the isolated-worktree assertion, refusal-is-
a-blocker rule, and post-spawn duties stay inline.
- section 7's teardown landed-work mechanics -> bin/fm-teardown.sh
header (section 1's containment pointer retargeted); the fork benign
case and never-force rule stay inline.
- section 8's watcher classification narrative -> docs/architecture.md
'Event-driven supervision' (already the owner); every operative rule
(one live cycle, no turn ends blind, drain first, wake ladder,
never-pkill, guard responses) stays inline.
- sections 3/4/6/7 secondmate sync, propagation, schema, and handoff
restatements -> secondmate-provisioning skill, now the declared
owner including the literal-file inheritance nuance.
- section 14's X-mode cadence mechanism -> docs/configuration.md
'X mode (.env)', closing issue #363; activation semantics, the
fmx-respond trigger, and the terminal-wake final-follow-up duty
stay inline.
CLAUDE.md stays a symlink; no behavior or test change.
* no-mistakes(document): Centralize contract-owner documentation
* fix(cmux): close last workspace during teardown (#449)
* fix(cmux): close the last/selected workspace in a window at teardown
cmux keeps every window at >=1 workspace, so close-workspace on the only
workspace in a window silently no-ops (returns OK, workspace stays), and a
window holding a live session cannot be closed over the control socket.
That left a selected task workspace open at teardown (the last workspace
in a window is always the selected one).
Add fm_backend_cmux_window_of_workspace and have fm_backend_cmux_kill
create a throwaway default sibling in the target's window before closing
when the target is the last workspace there, so the close lands; the
window keeps a fresh default workspace (cmux's own "closed the last tab"
outcome). Non-last teardown closes directly, as before.
Cover both kill branches plus the helper with fake-CLI unit tests, add a
real-cmux window/count detection smoke assertion, and record the
empirical evidence in docs/cmux-backend.md.
* no-mistakes(review): Derive cmux count from membership snapshot
* no-mistakes(document): Document cmux last-workspace teardown behavior
* fix: recover orphaned packed-refs locks during fleet sync (#453)
* fix(fleet-sync): recover from an orphaned packed-refs.lock
A git ref rewrite (fetch --prune, pack-refs, branch -D) killed after
creating .git/packed-refs.lock but before renaming it - e.g. bootstrap's
timed-out fleet-sync kill or teardown's process kills - leaves a lock that
makes the next sync's fetch fail with "Unable to create
'...packed-refs.lock': File exists", leaving the clone unsynced.
On that signature only, fm-fleet-sync.sh now retries the fetch with a
bounded wait (transient locks self-clear), then removes the lock and
retries once more ONLY when it is provably stale: still present, mtime
age past a threshold, and no lsof holder of the lock file or of the clone
worktree itself (a live git keeps that as its cwd even in the window after
it closes the lock and before it exits). A live lock, a missing lsof, any
failed check, or any other fetch failure keeps today's behavior. Every
wait/retry/removal prints to stderr, and a successful recovery also prints
one "recovered:" summary to stdout so a session-start refresh - which
discards fleet-sync stderr and relays only stdout - still surfaces it.
The shared "is this git lock provably abandoned?" proof is extracted into
bin/fm-lock-lib.sh so it has one owner, used by both fm-teardown.sh and
fm-fleet-sync.sh. Constants are env-overridable knobs. tests/fm-gotmp.test.sh
gains the fm-lock-lib.sh symlink teardown now needs in its fake bin/.
* no-mistakes(review): Captain, remove obsolete teardown wake dependency
* no-mistakes(document): Document packed-refs lock recovery architecture
* feat(herdr): escalate blocked panes immediately (#472)
* feat(herdr): immediate blocked-state escalation via native events.subscribe push
Fold herdr's native pane.agent_status_changed stream into the single watcher so
a crew entering blocked wakes its supervisor sub-second (measured 0.129s)
instead of after the ~240s stale-pane wedge timer.
- bin/fm-transition-lib.sh: backend-neutral normalized-transition record shape
plus the single-owner status->action policy table (blocked=actionable,
working=absorb+clear-dedupe, idle/done=defer, else=fall back to polling).
- bin/backends/herdr.sh + herdr-eventwait.py: a raw AF_UNIX events.subscribe
subscriber over one connection for all this home's herdr panes, subscribing to
ALL statuses, returning the first fresh blocked edge, with a per-pane dedupe
marker and a reconnect level-reconcile. Version/schema capability gate.
- bin/fm-backend.sh: has-push / events-capable / wait-transition dispatchers so
the watcher stays backend-agnostic and the shape+policy are reusable.
- bin/fm-watch.sh: splice the bounded event wait in as the watcher's terminal
wait primitive (replacing the blind sleep POLL for push-capable homes),
behind a source guard so the splice is unit-testable; secondmate/paused
exemptions; map pane->window->task and enqueue a stale wake. No second
watcher process; the single-cycle invariant and every guard/beacon/turn-end
mechanism are unchanged.
- Polling stays the permanent fail-closed backstop: below-capability, subscribe
failure, and repeated runtime failures all degrade to sleep.
- Tests: fake-CLI units (fm-transition-lib, wait/apply/dedupe/reconcile/
fallbacks in fm-backend-herdr, watcher exemptions in fm-supervision-events)
plus an isolated real-herdr idle->blocked smoke. docs/herdr-backend.md carries
the dated evidence and retires the old gap note.
* no-mistakes(review): Captain, fix Herdr disconnect handling and dedupe docs
* no-mistakes(review): Captain, commit markers after wake and reuse capability cache
* no-mistakes(review): Captain, clear stale markers and secure Herdr FIFOs
* no-mistakes(review): Captain, subscribe before Herdr reconciliation
* no-mistakes(review): Captain, make Herdr FIFO handling Bash 3.2-safe
* no-mistakes(test): Captain: include lock library in teardown fixture
* no-mistakes(document): Captain: document Herdr immediate blocked escalation
* fix: clarify shellcheck conditionals
* docs(readme): reposition firstmate as an agent distro (#473)
* feat: add deterministic bounded bearings snapshots (#475)
* feat(bearings): deterministic bearings snapshot + durable decision model
Add bin/fm-bearings-snapshot.sh: a bounded TOON-by-default projection over the
canonical fm-fleet-snapshot. Default is local-only (zero network); live open-PR
discovery and checks happen only under --include-prs, which fails soft. Every
dropped surface is marked in omitted[] with the flag that reveals it, and the
prs: line states when checks were not requested, so absence is never silent.
Fix the unresolved-decision masking bug in the canonical layer. fm-classify-lib
gains status_open_decisions, the one authoritative keyed open/resolved fold over
the whole status stream: needs-decision/blocked opens a keyed entry, only an
explicit keyed resolution (or, for run-backed tasks, run-step advancement)
closes it, so a later unrelated done/paused can no longer mask a still-open
captain decision. fm-fleet-snapshot surfaces hints.open_decisions and derives
pending_decision/blocked_event from it; the canonical schema stays complete.
Point the /bearings skill at the one command; add the resolved: writer line to
ship, scout, and secondmate briefs. Register the script and add regression
tests for the output bound, TOON/JSON parity, local-only default, opt-in PR
fetch, partial-failure degradation, decision durability, and report pointers.
* fix(bearings): completed scout report is a pointer, not a pending decision
A completed scout that raised a needs-decision and then finished (done) without
a keyed resolution falsely surfaced as an open/pending decision (the Lavish-103
case). Root cause: the open-decision reconciliation in bin/fm-fleet-snapshot.sh
cleared a stale decision only for a live run-step/pane activity read, so a
terminal task whose current state is read from the status log (a scout or ship
that reached done/failed) never cleared its stale, never-keyed-resolved
needs-decision, and it lingered as pending.
The open-decision set is still derived purely from the keyed fold - never from a
report body or decision-like prose - and reconciled against the crew lifecycle.
Extend that reconciliation so a terminal done/failed state on a single-owner
task (scout or ship), whose deliverable is its report or PR, also clears the set;
a completed scout now surfaces only as a report pointer. Secondmates are excluded
from the terminal clear (persistent, multiplexed stream), which keeps the
unrelated-event masking fix intact. Add regression tests: a completed scout with
decision-like report prose is a pointer not pending (canonical + end-to-end), and
a scout still parked at a decision stays pending so the terminal clear never
over-fires.
* no-mistakes(review): Captain, preserve keyed decisions across shared status parsing
* no-mistakes(review): Captain, close blockers and harden keyed decision parsing
* no-mistakes(review): Captain, bound GitHub enrichment without coreutils timeout
* no-mistakes(review): Captain, bound bearings sections and fail closed
* no-mistakes(review): Captain, disclose capped per-repository PR results
* no-mistakes(document): Refresh bearings documentation and status contracts
* fix(bearings): avoid ambiguous worktree guard
* fix: enforce deterministic ShellCheck parity (#481)
* fix(lint): one shellcheck owner pinned to 0.11.0 for CI/local parity
Firstmate PRs passed local no-mistakes validation but failed CI's
"Lint shell scripts" job on shellcheck findings (SC2015, SC1007, SC2034).
Two divergences caused it:
1. The no-mistakes gate had no commands.lint, so its lint step never ran
the deterministic shellcheck bin/*.sh bin/backends/*.sh tests/*.sh that
CI runs. Confirmed from state.sqlite: the lint step_result recorded
findings:null with no lint agent invocation.
2. CI's shellcheck floated with the runner image while local ran a newer
build; shellcheck retired SC2015 in 0.11.0, so an older CI shellcheck
rejected an SC2015 that the newer local one no longer emits.
Establish bin/fm-lint.sh as the single owner of the lint definition: the
file set, the config, and the pinned shellcheck version (0.11.0, printed
via --required-version). Both CI (.github/workflows/ci.yml) and the
no-mistakes gate (.no-mistakes.yaml commands.lint) invoke it; CI installs
the exact version it names and logs the resolved version, and fm-lint.sh
refuses to lint under any other version. This is not a CI relaxation: it
adopts shellcheck 0.11.0's rule set consistently, dropping only the
upstream-retired, false-positive-prone SC2015; default severity and every
still-supported finding stay enforced (no severity downgrade, no excludes).
tests/fm-lint.test.sh asserts both gates invoke the owner, that CI installs
and logs the pinned version, that the owner refuses a non-pinned shellcheck,
and that it rejects a real lint defect the old no-op gate passed.
* no-mistakes(review): Captain, harden deterministic ShellCheck parity
* no-mistakes(review): Captain, neutralize ambient ShellCheck overrides
* feat: guard primary shells from persistent cd commands (#483)
* feat: add cd-guard PreToolUse seatbelt for the primary shell
A stray persistent top-level `cd projects/<clone>` in the primary firstmate
shell relocates the shell, so a later firstmate-owned command (a backlog write,
an fm-* lifecycle call, tasks-axi) runs inside a project clone instead of the
home. The cd-guard denies exactly that command shape before it runs, across all
five verified primary harnesses, mirroring the watcher-arm PreToolUse seatbelt.
- bin/fm-cd-command-policy.mjs: sole block/allow decision owner. Reuses the
shell classifier exported from bin/fm-arm-command-policy.mjs (no duplicate
lexer; that file's CLI now runs only when invoked directly).
- bin/fm-cd-pretool-check.sh: transport, strict-superset prefilter, harness
output rendering, and primary-checkout scoping - fires in a secondmate's own
primary session, inert in crew/scout child worktrees and non-firstmate repos.
- Wired into claude, codex, grok, opencode, and pi PreToolUse-equivalents;
per-harness hooks only call the owner.
- Blocks top-level cd/pushd/popd (including cd to an absolute path, X=1 cd,
and command cd). Allows git -C, subshell / bash -c / env -C / make -C /
find -execdir, pipeline and background forms, and cd-as-data. Fails open on
malformed input; agent-mistake threat model.
- tests/fm-cd-pretool-check.test.sh: 43-case x 5-harness-entry-form matrix,
end-to-end cwd-leak regression, scoping, fail-open, prefilter, and wiring.
- docs/cd-guard.md: full contract plus live validation (claude, codex,
opencode, pi blocked end-to-end; grok live run blocked by an API balance
limit, with mechanism parity and deterministic coverage recorded).
* no-mistakes(review): Captain, fix cd-guard classification and prefilter coverage
* no-mistakes(review): Captain, allow path-qualified command wrappers
* no-mistakes(review): Captain, allow non-executing command queries
* no-mistakes(test): Captain, clarify cd-guard safe-path remediation
* docs: clarify cd guard guidance
* no-mistakes(document): Clarify cd-guard safe target guidance
* brief: add no-mistakes shared-daemon rule to ship and scout scaffolds (#267)
Crews must never stop, restart, or update the shared no-mistakes
daemon since one instance serves every firstmate lane/home; a restart
kills other lanes' in-flight pipeline runs and forces expensive
re-runs. Encodes this as a new numbered rule in both the ship-task and
scout-task brief scaffolds.
Co-authored-by: mielyemitchell <249051873+mielyemitchell@users.noreply.github.com>
* feat: make bearings concise and accurate (#485)
* feat(bearings): four-section chat contract, accurate secondmate landed, resolved-event state render
/bearings skill (one owner of the chat-response format): mandate the four
always-present chat sections - Captain's Call, Recently Landed, Underway,
Charted Next - each with an explicit empty-state sentence, no At Anchor,
materially shorter than and linking to the report file. Resolves the ambiguous
Check first / Decisions pending split into one strict captain-action section.
fm-crew-state: the log fallback derives current state only from a real
run-state verb, so a trailing decision-closing resolved: event no longer
renders a healthy idle crew (typically a secondmate) as unknown with the
resolution prose as its detail. The keyed-decision contract in
fm-classify-lib.sh is untouched; map_log_state stays the one verb->state owner.
fm-fleet-snapshot: add a bounded, read-only secondmate_landed roll-up of Done
records from registered secondmate homes, reusing the single backlog parser and
the one secondmate-home enumerator (meta home= with data/secondmates.md
fallback); no network, per-home capped.
fm-bearings-snapshot: landed now merges main-home Done with the secondmate
roll-up, bounded by a per-home cap and an overall cap with omitted[] disclosure
(also fixing the previously-silent landed truncation); --all-landed reveals the
full set.
tests: resolved-event state render, secondmate landed aggregation with caps and
omitted[] disclosure, Captain's Call anti-leak, and the four-section contract.
* no-mistakes(review): Captain, ensure bearings reveals all landed work
* no-mistakes(document): Document bearings accuracy contracts
* fix: harden away-mode daemon lifecycle (#490)
* fix: script-owned non-visible away-daemon launch + stale-artifact lifecycle
Away-mode entry left "make the daemon a tracked background terminal" to the
operator; on a pi/herdr primary that meant splitting the captain's active pane,
which visibly shrank it. Add bin/fm-afk-launch.sh, a single owner that launches
the daemon in a non-visible tracked terminal per backend (herdr dedicated
--no-focus workspace, detached tmux session), never a split, pins the captain
pane as FM_SUPERVISOR_TARGET/FM_SUPERVISOR_BACKEND, records the exact terminal
id, and tears it down or reconciles a leaked one by that id. No shell &.
Extract supervisor-pane discovery into bin/fm-supervisor-target-lib.sh, shared
with the daemon (one owner).
Fix the stale subsuper-artifact leak: clear the prior away session's delivery
cache on a fresh entry (fm_afk_clear_stale_artifacts), and stop the daemon
before clearing state/.afk so its shutdown flush runs instead of being a no-op.
Tests: tests/fm-afk-launch.test.sh (per-backend topology invariant in a lab
session, stale clear-on-entry vs refresh, exit ordering). Docs: /afk SKILL.md,
docs/herdr-backend.md (dated herdr evidence), AGENTS.md exit stub, docs/scripts.md.
* no-mistakes(review): Captain, serialize AFK launcher lifecycle safely
* no-mistakes(review): Captain, harden AFK launcher lifecycle races
* no-mistakes(review): Captain, ensure AFK daemon launch readiness
* no-mistakes(review): Captain, unify AFK lifecycle ownership and teardown
* no-mistakes(review): Captain, preserve AFK reconciliation records uniformly
* no-mistakes(review): Captain, harden AFK recovery state durability
* no-mistakes(review): Captain, harden AFK tmux ownership checks
* no-mistakes(review): Captain, simplify AFK lifecycle failure handling
* no-mistakes(review): Captain, require confirmed AFK daemon shutdown
* no-mistakes(review): Captain, confirm AFK exit by process identity
* no-mistakes(document): Align AFK launcher lifecycle documentation
* no-mistakes: apply CI fixes
* fix: prevent no-mistakes gate agents from driving the fleet (#518)
* feat: contain no-mistakes gate agents from driving the fleet
Add bin/fm-gate-refuse-lib.sh, sourced at the top of fm-spawn/fm-send/
fm-teardown before any fleet mutation. It fails closed when NO_MISTAKES_GATE
is set, and via an unspoofable git-common-dir backstop when invoked from a
no-mistakes gate worktree (.no-mistakes/repos/*.git) even with the marker
unset. A normal firstmate session has neither signal and is unaffected.
Set disable_project_settings: true in the tracked .no-mistakes.yaml so the
installed pipeline neutralizes gate agents' project instructions for this repo
(trusted-only, honored from the default branch).
firstmate's own suite runs from a gate worktree during validation, so the
shared test helpers set FM_GATE_REFUSE_BYPASS=1 to exempt it; the dedicated
tests/fm-gate-refuse.test.sh strips it to verify real refusal.
* no-mistakes(review): Captain, refuse empty no-mistakes gate markers
* no-mistakes(document): Document no-mistakes gate authority boundary
* fix: guard secondmate primary sessions from blind turn ends (#505)
* fix: guard secondmate own-home turn ends
Remove the .fm-secondmate-home early-exit in fm-turnend-guard.sh so the
'no turn ends blind' backstop fires in a secondmate's own primary session,
matching the cd-guard's scope: the own home is guarded, child crew/scout
worktrees stay exempt via the retained git-dir/git-common-dir test. This
was pure scoping from the guard's primary-only origin and guarded against
no secondmate-specific hazard.
Add secondmate regression tests (blind-turn block, idle-by-default,
stop_hook_active loop guard, deferred-death recovery loop, child-worktree
exemption) and record the autonomous background-notify re-invoke
measurement (Claude Code 2.1.207, 11s) in docs/turnend-guard.md.
* no-mistakes(document): Correct secondmate guard documentation, captain
* fix: force-include marked secondmate homes in turn-end guard
The prior remove-only form (just deleting the .fm-secondmate-home check)
left the DEFAULT secondmate topology unguarded: a treehouse-leased home is
a linked git worktree (git-dir != git-common-dir), which the retained
git-dir exemption still skipped, so its own primary session could still end
a turn blind. Invert the marker: a genuinely-marked home is force-included
as a guarded primary (treehouse-leased linked OR git-cloned plain), and the
git-dir exemption applies only to UNMARKED child worktrees. Marker
validation (regular non-symlink file, non-empty id-token content) blocks a
stray or empty marker from spoofing inclusion.
Add real linked-worktree regression tests: a treehouse-leased LINKED
secondmate home is guarded, a stray/empty marker stays exempt, and the
unmarked child worktree stays exempt - the topology the plain git-init
fixtures masked. Predicates, in-flight gate, and loop guard untouched.
* fix: force ASCII collation in secondmate marker validation
Add a function-scoped local LC_ALL=C in fm_root_is_secondmate_home so the
[A-Za-z0-9._-] id allowlist matches under C collation, not the ambient
locale - a locale-crafted non-ASCII marker id can no longer slip through
the range match and spoof force-inclusion of a linked child worktree.
Add a regression test proving a non-ASCII marker id is rejected and the
linked worktree stays exempt.
* no-mistakes(test): fix backend baseline gate-refusal dependency
* no-mistakes(document): Correct secondmate turn-end guard documentation
* fix: make bootstrap diagnostics backend-aware (#519)
* fix: make bootstrap required-tool detection backend-aware
Bootstrap demanded tmux and treehouse for every backend except orca, so a
herdr/zellij/cmux home with tmux absent was wrongly told MISSING: tmux.
Required tools now follow the resolved backend via the single-owner
fm_backend_required_tools helper (bin/fm-backend.sh): each backend's own
session-provider CLI, jq for the JSON-emitting adapters (herdr/zellij/cmux),
and treehouse for session-provider-only backends (orca owns its worktree).
The treehouse lease-support check is gated to backends that use treehouse.
Adds install hints for herdr/zellij/cmux, regression tests for the full
backend dependency matrix (herdr-without-tmux repro plus each boundary),
and updates the authoritative Toolchain docs.
* no-mistakes(review): Captain, prevent executing Herdr install guidance
* no-mistakes(review): Captain, harden backend-aware bootstrap diagnostics
* no-mistakes(review): Captain, separate manual dependency remediation
* no-mistakes(review): Captain, align bootstrap diagnostic consumers
* no-mistakes(document): Align backend adapter dependency comments
* fix: preserve follow-up platform context after inbox cleanup (#520)
* fix: recover X/Discord follow-up platform after inbox cleanup
A milestone follow-up posted directly by request_id after the inbox was
drained - and with no task link, because one persistent secondmate's single
x_request slot collides across concurrent requests - resolved platform only
from the local inbox, so a >280 Discord reply silently defaulted to the X
280-char budget and threaded as (1/2).
- fm-x-poll records a durable per-request reply context
(state/x-context/<rid>.json) at stash time, keyed by request_id so
concurrent requests never overwrite each other; it survives inbox cleanup
and restart.
- fm-x-reply resolves platform/budget through registry -> inbox -> relay
(the relay lookup confined to a live follow-up), recovering the original
platform independent of task-link availability.
- Fail-safe: a follow-up whose platform/budget cannot be authoritatively
resolved and that would split is refused (exit 8) and held for retry,
never wrongly split; fm-x-followup keeps the link on that exit.
- fm-x-dismiss clears the durable context for a dismissed mention.
Refactors reply-context extraction into a single owner and adds regression
coverage for all four cases.
* no-mistakes(review): Captain, fail closed on incomplete follow-up context
* no-mistakes(review): Captain, bound X context registry retention
* no-mistakes(review): Captain, align context retention with answer binding
* no-mistakes(document): Align X follow-up context documentation
* no-mistakes(document): Align durable X follow-up documentation
* fix: preserve secondmate routing markers in terminal sends (#533)
* fix: preserve secondmate routing markers
* no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends
* no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift
* no-mistakes(document): Refresh Herdr marker documentation
* fix: align Grok effort handling with 0.2.99 (#527)
* fix: align grok effort docs and spawn with 0.2.99 ceiling
grok 0.2.99 accepts only low|medium|high for --reasoning-effort and
rejects both xhigh and max. Omit unsupported values on spawn, flag them
in crew-dispatch validation, and update harness-adapters.
* no-mistakes(test): Captain: refresh gotmp teardown fixture dependencies
* no-mistakes(document): Clarify Grok effort documentation ownership
* fix: derive bearings from authoritative secondmate state (#555)
* fix: make bearings use secondmate home state
* test: anonymize bearings fixtures
* no-mistakes(review): Bound parent activity evidence scans, captain
* no-mistakes(review): Preserve structured secondmate authority and bounds, captain
* no-mistakes(review): Preserve registry completeness and child inventory, captain
* no-mistakes(review): Reconcile parent evidence by verb and key, captain
* no-mistakes(review): Treat unkeyed parent evidence as inconclusive, captain
* no-mistakes(document): Document bearings local snapshot and PR opt-in
* no-mistakes(lint): Fix fleet snapshot ShellCheck findings
* no-mistakes: apply CI fixes
* fix: restore fleet snapshots on stock macOS Bash (#578)
* fix: restore stock macOS snapshot parsing
* no-mistakes(document): Clarify Linux gate and macOS CI coverage
* fix(afk): make Pi escalation and return catch-up reliable (#587)
* fix: close away-mode blocker supervision gap
* no-mistakes(review): Gate teardown retries and verify U+2063 dedupe
* no-mistakes(test): Fail closed on incomplete Pi composer separators
* no-mistakes(document): Document Pi composer recognition and return gating
* feat: support Pi max reasoning profiles (#537)
* support Pi max thinking profiles
* no-mistakes(review): Captain, allow Pi max dispatch profiles
* chore: no-mistakes(document): Clarify yolo response ownership (#595)
* Clarify validation response ownership
* no-mistakes(document): Clarify yolo response ownership
* feat: establish instruction ownership foundation (#619)
* Add instruction owners foundation
* no-mistakes(document): Refresh project-management owner pointers
* fix: compress Firstmate contract and enforce delivery rigor ownership (#626)
* docs: compress firstmate operating contract
* docs: make delivery rigor single-owner
PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion.
* no-mistakes(review): Honor configured merge authority across faster delivery paths
* no-mistakes(document): Align docs with compressed operating contract
* feat: add durable captain decision holds (#593)
* Add durable captain decision holds
* no-mistakes(review): Validate decision hold retries and origin paths
* no-mistakes(review): Enforce durable decision lifecycle boundaries
* no-mistakes(review): Harden decision display and partial retry recovery
* no-mistakes(test): Update scout teardown fixtures for decision inventory
* no-mistakes(document): Align decision lifecycle and scout teardown documentation
* no-mistakes: apply CI fixes
* no-mistakes(review): Reconcile terminal decision holds
* no-mistakes(document): Align captain decision-hold documentation
* fix(bin): harden PR check artifacts (#556)
* fix: harden PR check artifacts
* fix: close PR check migration gaps
* fix: close PR check retry gaps
* fix: clarify migration outcomes and ESM boundary
* fix: keep failed migrations authoritative
* test: use inert PR validation fixtures
* no-mistakes(review): Reserve noncanonical PR quarantine namespace
* no-mistakes(review): Prevalidate final PR-check teardown artifacts
* no-mistakes(review): Preserve X metadata and validate teardown IDs
* no-mistakes(review): Initialize migration state before watcher exclusion
* no-mistakes(review): Isolate failed poll migrations from bootstrap recovery
* no-mistakes(review): Allow safe polling during incomplete private repairs
* no-mistakes(review): Authenticate watcher checks at execution time
* no-mistakes(review): Preserve custom checks with hash-bound registration
* no-mistakes(review): Clean custom check snapshots on watcher signals
* no-mistakes(review): Stop watcher checks promptly on signals
* no-mistakes(review): Terminate watcher check groups before cleanup
* no-mistakes(document): Correct stale X-mode watcher documentation
* fix: drain returned watcher check groups
* no-mistakes(review): Harden quarantine links and recover validated replacement polls
* no-mistakes(review): Preserve X mode across shim version transitions
* no-mistakes(review): Refresh legacy X shims before marker short-circuits
* no-mistakes(document): Correct persisted PR-check artifact documentation
* no-mistakes(document): Correct stale PR-check documentation
* fix: bind PR poll repair provenance
* no-mistakes(review): Enforce single-link ownership for custom check artifacts
* no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs
* no-mistakes(review): Separate task creation and legacy teardown validation
* no-mistakes(review): Restore safe legacy operations and teardown validation
* no-mistakes(review): Disambiguate migration obligations and preserve legacy retries
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits
* no-mistakes(document): Document private poll artifact safety contracts
* no-mistakes(lint): Suppress intentional literal-dollar lint finding
* fix: migrate historical X poll identity
* fix: harden PR check artifacts
* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence
* no-mistakes(review): Reconcile legacy migration retries and teardown collisions
* fix: migrate historical X poll identity
* no-mistakes(review): Harden X-mode artifact publication against symlink corruption
* no-mistakes(review): Guard X artifact publication
* no-mistakes(review): Enforce private X artifact reads
* no-mistakes(test): Fix backend compatibility fixture dependencies
* no-mistakes(document): Refresh PR-check documentation
* no-mistakes(lint): Remove unused x-mode test locals
* no-mistakes: apply CI fixes
* fix(bin): compact session-start backlog digest (#636)
* fix: compact session-start backlog digest
* no-mistakes(test): Fix legacy backend fixture helper
* no-mistakes(test): Fix watcher exit wait helper
* no-mistakes(document): Document compact backlog digest
* fix: dedupe stale watcher guard banners (#637)
* fix: dedupe stale watcher guard banner
* no-mistakes(review): Keep read-only guard state nonmutating
* no-mistakes(document): Clarify stale watcher docs
* fix(bin): balance bearings landed baseline (#640)
* fix: balance bearings landed defaults
* no-mistakes(document): Document balanced landed baseline
* no-mistakes: apply CI fixes
* fix: clarify captain-facing translation contract (#644)
* docs: clarify captain-facing translation contract
* no-mistakes(review): Restore runtime fallback mandate
* no-mistakes(document): Align Bearings translation wording
* fix(bin): make bootstrap output and nudges deterministic (#646)
* fix: make bootstrap nudges deterministic
* no-mistakes(review): Honor state override for bootstrap nudges
* no-mistakes(review): Update benign bootstrap documentation labels
* no-mistakes(review): Validate bootstrap nudge retry markers
* no-mistakes(document): Align bootstrap nudge documentation
* no-mistakes: apply CI fixes
* docs(secondmate-provisioning): clarify concise registry ownership (#649)
* Clarify concise secondmate registry contract
* no-mistakes(review): Expand secondmate registry boilerplate coverage
* no-mistakes(document): Point route docs to owner
* fix(bin): strip quoted blocked_by values during decision hold resolve (#654)
* fix(bin): strip quotes on blocked_by in decision-hold resolve
tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary
membership test only matched middle elements. Strip surrounding quotes
before matching so first and last hold ids resolve correctly.
* no-mistakes(document): Refresh decision-hold regression evidence
* feat(secondmate): inherit shared captain preferences (#656)
* feat(secondmate): inherit shared captain preferences
* no-mistakes(review): Honor shared captain data overrides
* no-mistakes(review): Honor bootstrap data override registry
* no-mistakes(document): Refresh shared inheritance docs
* no-mistakes(document): Clarify inherited local-material docs
* feat: gate local agent secret injection (#658)
* feat(spawn): gate local agent secret injection
* fix(spawn): align final Keychain slot
* no-mistakes: apply CI fixes
* test: isolate Herdr autodetect smoke sessions (#662)
* test: isolate herdr autodetect smoke session
* no-mistakes(review): Restored autodetect smoke gate bypass
* no-mistakes(test): Harden Herdr lab provisioning
* no-mistakes(document): Refresh Herdr lab docs
* docs: adopt under way for active work (#666)
* Revert "feat: gate local agent secret injection (#658)" (#668)
This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef.
* fix(pi): distinguish stale locks when arming watcher (#681)
* fix(pi): distinguish stale locks when arming watcher
* no-mistakes(test): Stabilize watcher extension async waits
* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate house vocabulary (#685)
* fix: accept secondmate as house vocabulary
* no-mistakes(test): Update captain vocabulary contract test
* no-mistakes(document): Align secondmate documentation vocabulary
* fix(bin): parse handoff homes after registry parentheticals (#686)
* fix: parse secondmate home after pre-field parentheses
Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.
* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges (#687)
* feat: add native session-start nudges
* no-mistakes(document): Document nudge script inventory
* docs: call built-in defaults the firstmate repo, not template (#688)
Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
* fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205)
* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn
Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(brief): harden fm-brief regression coverage for parse and scaffolds
Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the
Co-authored-by: Cursor <cursoragent@cursor.com>
#166 apostrophe regression cannot return unnoticed.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(bin): keep watcher supervision continuous across child cycles (#693)
* fix: make watcher supervision continuous
* no-mistakes(review): Bound watcher retries and log attached signals
* no-mistakes(review): Add bounded successor-recovery wake fallbacks
* no-mistakes(review): Prevent overlapping successor-arm retries
* no-mistakes(review): Resume supervision after late arm closes
* no-mistakes(review): Bind OpenCode recovery to attempted arm
* no-mistakes(test): Synchronize peer beacon regression fixture
* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures
* no-mistakes(document): Captain: document watcher successor protocol behavior
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* no-mistakes: apply CI fixes
* fix: fetch current PR head for review diffs (#722)
* fix: always fetch PR head for review diffs
Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.
* no-mistakes(test): Isolate session-start nudge tests from gate state
* no-mistakes(document): Correct review-diff documentation
* docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736)
* docs: resolve five contract contradictions
* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): correct Grok exit guidance (#742)
* docs(harness): reverify grok exit command
* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for parked crew (#743)
* fix(watcher): bound stale wakes for exited paused crew
* no-mistakes(review): Gate pause suppression on confirmed agent death
* no-mistakes(test): Fixed stale pause cadence
* no-mistakes(document): Document dead-agent hold cadence
* fix(supervision): distinguish ordinary wakes from recovery (#744)
* fix(supervision): distinguish ordinary wakes from repair
* no-mistakes(review): Make passive guard follow-ups recovery-only
* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes (#745)
* fix(x-mode): dedupe pending mention wakes
* no-mistakes(review): fix x-poll claim error deduplication
* no-mistakes(review): separate claim diagnostics from relay recovery
* no-mistakes(document): Document X-mode once-only mention wakes
* feat(wake): enrich drained signals with bounded status context (#747)
* feat(wake): enrich drained signal context
* no-mistakes(review): Bound wake enrichment reads
* no-mistakes(document): Document wake-drain annotations
* docs(wake): explain at-least-once drain boundary
* no-mistakes(review): Prevent symlink races in wake annotations
* no-mistakes(review): Exercise wake symlink race regression
* test: document intentional AFK marker subprocesses
* fix(wake): isolate annotation marker state
* feat(herdr): add optional presentation spaces (#784)
* feat(herdr): add optional presentation spaces
* no-mistakes(review): Harden Herdr projection creation and spawn serialization
* no-mistakes(review): Captain, disarm Herdr cleanup before launch submission
* no-mistakes(test): Correct stale Orca metadata failure fixture
* no-mistakes(document): Document Herdr presentation projection accurately
* fix(send): treat opencode busy-queued composer state as submitted (#775)
* fix(send): treat opencode busy-queued composer state as submitted
When fm-send sends a message to a BUSY opencode crewmate on the tmux
backend, opencode accepts the Enter and queues the message for the next
turn, but leaves the typed text visible in the composer row. The
submit-verification loop sees a pending composer, exhausts retries, and
reports a false "Enter swallowed" failure while the message is actually
delivered.
Fix: after Enter retries are exhausted and the composer still shows
pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn,
footer shows "esc interrupt"), the harness queued the message, so
return "empty" (accepted). On an idle pane, keep returning "pending"
(genuine swallow detection preserved).
Regression tests cover four scenarios:
- busy pane + pending composer -> empty (message queued)
- idle pane + pending composer -> pending (genuine swallow)
- busy pane + composer clears on first Enter -> empty
- idle pane + composer clears on first Enter -> empty (existing path)
* docs: document busy-queued Enter exception across backend docs and skills
Add explanatory comments and backend documentation for the
busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn
but keeps typed text in composer until the turn ends):
- bin/fm-tmux-lib.sh: document the busy-aware fallback in the
file header and above fm_tmux_submit_enter_core
- .agents/skills/afk/SKILL.md: daemon-facing policy note
- .agents/skills/harness-adapters/SKILL.md: harness-specific fact
- docs/tmux-backend.md: submit-acknowledgement section with the
busy-queue exception
- docs/herdr-backend.md: record the known gap
- docs/architecture.md: cross-reference in the daemon section
* test(tmux): fix SC2181 and make busy-submit test executable
* fix(spawn): require two stable reads before accepting worktree path (#765)
* fix(spawn): require two stable reads before accepting worktree path
The treehouse-get worktree-detection loop in fm-spawn.sh accepted the
first pane_current_path read that differed from the project path, but
on some tmux/WSL setups a brand-new window transiently reports a
stale-but-real path before the pane actually settles into the
worktree. Since that stale path is itself a real, distinct git
checkout, it also passes validate_spawn_worktree's isolation check,
so the loop silently recorded the wrong worktree in state/<id>.meta
(and, for claude harness spawns, installed the turn-end hook there
too).
Require two consecutive polls to agree on the same non-project path
before accepting it, using the existing inter-poll sleep as the
confirmation gap so an already-settled pane isn't slowed down by an
extra cycle.
* fix(tests): drop unused CASE_DIR read in worktree-settle test
ShellCheck SC2034: CASE_DIR is split out of the case record but
never referenced; discard it with _ instead.
---------
Co-authored-by: Freudator86 <tim@allesknut.de>
* fix(bin): make watcher process identity immune to Linux wall-clock changes (#752)
* fix(watcher): stabilize Linux process identity
* no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale
* fix: prevent AFK idle stalls and stale run attribution (#758)
* fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state
Stop free-text tokens like "merged" from promoting nonterminal working: lines
to captain-relevant, so AFK no longer permanently suppresses idle recovery.
Defend wedge aging independently for nonterminal progress verbs, bind
no-mistakes current-state attribution to code identity (not branch alone),
and mark setup-complete as nonterminal in the ship brief scaffold.
* no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution
* no-mistakes(document): Document current-code-bound run attribution
* no-mistakes(test): Wait for stable Herdr shell readiness
* no-mistakes(test): Make Herdr and watcher readiness tests deterministic
* no-mistakes(test): Make tmux capture and watcher lifecycle deterministic
* no-mistakes(document): Document corrected supervision contracts
* fix(bin): allow safe teardown during watcher recovery (#750)
* fix: allow safe teardown during watcher recovery
* no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code
* no-mistakes(document): Sync continuity-gate docs to allow teardown recovery
* test: mark dynamic teardown fixture literal
* no-mistakes(document): docs: add teardown to continuity gate allow list
* feat(herdr): order presentation spaces while preserving focus (#790)
* feat(herdr): order presentation worker spaces
* fix(herdr): preserve focus during projected cleanup
* no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs
* no-mistakes(review): Serialize Herdr aborts with guarded focus regressions
* no-mistakes(review): Fall back flat when Herdr serialization is unavailable
* no-mistakes(test): Stabilize watcher startup and AFK handoff tests
* no-mistakes(document): Correct Herdr ordering and focus documentation
* fix(bin): send literal config reread nudges after pushes (#809)
* Send literal config reread after inherited config push
When declared inherited config changes under an already-running secondmate,
build a per-home instruction from validated destination post-write bytes and
deliver it on the routed secondmate path. Unchanged config sends nothing;
ABSENT represents removal; captain-shared is never inlined. Covers mid-session
config-push and the locked bootstrap convergence path without hardening spawn
against deliberate runtime choice.
* no-mistakes(review): Fix config reread framing, partial propagation, and respawn order
* no-mistakes(review): Send config rereads via durable single-line pointers
* no-mistakes(review): Make failed config rereads retryable
* no-mistakes(review): Make config reread retries generation-safe
* no-mistakes(review): Make config rereads durable and ordered
* no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode
* no-mistakes(review): Retain write retries and quarantine stale respawn generations
* no-mistakes(review): Preserve exact config reread retries and delivery order
* no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning
* no-mistakes(document):…
7hoenix
added a commit
to 7hoenix/firstmate
that referenced
this pull request
Aug 27, 2026
…signing (#19) * fix: preserve secondmate routing markers in terminal sends (#533) * fix: preserve secondmate routing markers * no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends * no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift * no-mistakes(document): Refresh Herdr marker documentation * fix: align Grok effort handling with 0.2.99 (#527) * fix: align grok effort docs and spawn with 0.2.99 ceiling grok 0.2.99 accepts only low|medium|high for --reasoning-effort and rejects both xhigh and max. Omit unsupported values on spawn, flag them in crew-dispatch validation, and update harness-adapters. * no-mistakes(test): Captain: refresh gotmp teardown fixture dependencies * no-mistakes(document): Clarify Grok effort documentation ownership * fix: derive bearings from authoritative secondmate state (#555) * fix: make bearings use secondmate home state * test: anonymize bearings fixtures * no-mistakes(review): Bound parent activity evidence scans, captain * no-mistakes(review): Preserve structured secondmate authority and bounds, captain * no-mistakes(review): Preserve registry completeness and child inventory, captain * no-mistakes(review): Reconcile parent evidence by verb and key, captain * no-mistakes(review): Treat unkeyed parent evidence as inconclusive, captain * no-mistakes(document): Document bearings local snapshot and PR opt-in * no-mistakes(lint): Fix fleet snapshot ShellCheck findings * no-mistakes: apply CI fixes * fix: restore fleet snapshots on stock macOS Bash (#578) * fix: restore stock macOS snapshot parsing * no-mistakes(document): Clarify Linux gate and macOS CI coverage * fix(afk): make Pi escalation and return catch-up reliable (#587) * fix: close away-mode blocker supervision gap * no-mistakes(review): Gate teardown retries and verify U+2063 dedupe * no-mistakes(test): Fail closed on incomplete Pi composer separators * no-mistakes(document): Document Pi composer recognition and return gating * feat: support Pi max reasoning profiles (#537) * support Pi max thinking profiles * no-mistakes(review): Captain, allow Pi max dispatch profiles * chore: no-mistakes(document): Clarify yolo response ownership (#595) * Clarify validation response ownership * no-mistakes(document): Clarify yolo response ownership * feat: establish instruction ownership foundation (#619) * Add instruction owners foundation * no-mistakes(document): Refresh project-management owner pointers * fix: compress Firstmate contract and enforce delivery rigor ownership (#626) * docs: compress firstmate operating contract * docs: make delivery rigor single-owner PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion. * no-mistakes(review): Honor configured merge authority across faster delivery paths * no-mistakes(document): Align docs with compressed operating contract * feat: add durable captain decision holds (#593) * Add durable captain decision holds * no-mistakes(review): Validate decision hold retries and origin paths * no-mistakes(review): Enforce durable decision lifecycle boundaries * no-mistakes(review): Harden decision display and partial retry recovery * no-mistakes(test): Update scout teardown fixtures for decision inventory * no-mistakes(document): Align decision lifecycle and scout teardown documentation * no-mistakes: apply CI fixes * no-mistakes(review): Reconcile terminal decision holds * no-mistakes(document): Align captain decision-hold documentation * fix(bin): harden PR check artifacts (#556) * fix: harden PR check artifacts * fix: close PR check migration gaps * fix: close PR check retry gaps * fix: clarify migration outcomes and ESM boundary * fix: keep failed migrations authoritative * test: use inert PR validation fixtures * no-mistakes(review): Reserve noncanonical PR quarantine namespace * no-mistakes(review): Prevalidate final PR-check teardown artifacts * no-mistakes(review): Preserve X metadata and validate teardown IDs * no-mistakes(review): Initialize migration state before watcher exclusion * no-mistakes(review): Isolate failed poll migrations from bootstrap recovery * no-mistakes(review): Allow safe polling during incomplete private repairs * no-mistakes(review): Authenticate watcher checks at execution time * no-mistakes(review): Preserve custom checks with hash-bound registration * no-mistakes(review): Clean custom check snapshots on watcher signals * no-mistakes(review): Stop watcher checks promptly on signals * no-mistakes(review): Terminate watcher check groups before cleanup * no-mistakes(document): Correct stale X-mode watcher documentation * fix: drain returned watcher check groups * no-mistakes(review): Harden quarantine links and recover validated replacement polls * no-mistakes(review): Preserve X mode across shim version transitions * no-mistakes(review): Refresh legacy X shims before marker short-circuits * no-mistakes(document): Correct persisted PR-check artifact documentation * no-mistakes(document): Correct stale PR-check documentation * fix: bind PR poll repair provenance * no-mistakes(review): Enforce single-link ownership for custom check artifacts * no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs * no-mistakes(review): Separate task creation and legacy teardown validation * no-mistakes(review): Restore safe legacy operations and teardown validation * no-mistakes(review): Disambiguate migration obligations and preserve legacy retries * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits * no-mistakes(document): Document private poll artifact safety contracts * no-mistakes(lint): Suppress intentional literal-dollar lint finding * fix: migrate historical X poll identity * fix: harden PR check artifacts * no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence * no-mistakes(review): Reconcile legacy migration retries and teardown collisions * fix: migrate historical X poll identity * no-mistakes(review): Harden X-mode artifact publication against symlink corruption * no-mistakes(review): Guard X artifact publication * no-mistakes(review): Enforce private X artifact reads * no-mistakes(test): Fix backend compatibility fixture dependencies * no-mistakes(document): Refresh PR-check documentation * no-mistakes(lint): Remove unused x-mode test locals * no-mistakes: apply CI fixes * fix(bin): compact session-start backlog digest (#636) * fix: compact session-start backlog digest * no-mistakes(test): Fix legacy backend fixture helper * no-mistakes(test): Fix watcher exit wait helper * no-mistakes(document): Document compact backlog digest * fix: dedupe stale watcher guard banners (#637) * fix: dedupe stale watcher guard banner * no-mistakes(review): Keep read-only guard state nonmutating * no-mistakes(document): Clarify stale watcher docs * fix(bin): balance bearings landed baseline (#640) * fix: balance bearings landed defaults * no-mistakes(document): Document balanced landed baseline * no-mistakes: apply CI fixes * fix: clarify captain-facing translation contract (#644) * docs: clarify captain-facing translation contract * no-mistakes(review): Restore runtime fallback mandate * no-mistakes(document): Align Bearings translation wording * fix(bin): make bootstrap output and nudges deterministic (#646) * fix: make bootstrap nudges deterministic * no-mistakes(review): Honor state override for bootstrap nudges * no-mistakes(review): Update benign bootstrap documentation labels * no-mistakes(review): Validate bootstrap nudge retry markers * no-mistakes(document): Align bootstrap nudge documentation * no-mistakes: apply CI fixes * docs(secondmate-provisioning): clarify concise registry ownership (#649) * Clarify concise secondmate registry contract * no-mistakes(review): Expand secondmate registry boilerplate coverage * no-mistakes(document): Point route docs to owner * fix(bin): strip quoted blocked_by values during decision hold resolve (#654) * fix(bin): strip quotes on blocked_by in decision-hold resolve tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary membership test only matched middle elements. Strip surrounding quotes before matching so first and last hold ids resolve correctly. * no-mistakes(document): Refresh decision-hold regression evidence * feat(secondmate): inherit shared captain preferences (#656) * feat(secondmate): inherit shared captain preferences * no-mistakes(review): Honor shared captain data overrides * no-mistakes(review): Honor bootstrap data override registry * no-mistakes(document): Refresh shared inheritance docs * no-mistakes(document): Clarify inherited local-material docs * feat: gate local agent secret injection (#658) * feat(spawn): gate local agent secret injection * fix(spawn): align final Keychain slot * no-mistakes: apply CI fixes * test: isolate Herdr autodetect smoke sessions (#662) * test: isolate herdr autodetect smoke session * no-mistakes(review): Restored autodetect smoke gate bypass * no-mistakes(test): Harden Herdr lab provisioning * no-mistakes(document): Refresh Herdr lab docs * docs: adopt under way for active work (#666) * Revert "feat: gate local agent secret injection (#658)" (#668) This reverts commit c27135cd9d35bc4c237d49b3b374da31fbd52eef. * fix(pi): distinguish stale locks when arming watcher (#681) * fix(pi): distinguish stale locks when arming watcher * no-mistakes(test): Stabilize watcher extension async waits * no-mistakes(document): Document Pi lock recovery * fix: accept secondmate house vocabulary (#685) * fix: accept secondmate as house vocabulary * no-mistakes(test): Update captain vocabulary contract test * no-mistakes(document): Align secondmate documentation vocabulary * fix(bin): parse handoff homes after registry parentheticals (#686) * fix: parse secondmate home after pre-field parentheses Registry summaries often include parentheticals before the structured (home: ...) field. Match that field with a greedy prefix so handoff no longer reports "has no home" for those entries. * no-mistakes(document): Refresh handoff test comments * feat: add native session-start nudges (#687) * feat: add native session-start nudges * no-mistakes(document): Document nudge script inventory * docs: call built-in defaults the firstmate repo, not template (#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged. * fix(bin): repair fm-brief.sh parse error and harden set -u array expansion (#205) * fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4 (notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing. Co-authored-by: Cursor <cursoragent@cursor.com> * test(brief): harden fm-brief regression coverage for parse and scaffolds Tighten bash -n checking, pin literal backtick rendering in the no-mistakes DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the Co-authored-by: Cursor <cursoragent@cursor.com> #166 apostrophe regression cannot return unnoticed. --------- Co-authored-by: Cursor <cursoragent@cursor.com> * fix(bin): keep watcher supervision continuous across child cycles (#693) * fix: make watcher supervision continuous * no-mistakes(review): Bound watcher retries and log attached signals * no-mistakes(review): Add bounded successor-recovery wake fallbacks * no-mistakes(review): Prevent overlapping successor-arm retries * no-mistakes(review): Resume supervision after late arm closes * no-mistakes(review): Bind OpenCode recovery to attempted arm * no-mistakes(test): Synchronize peer beacon regression fixture * no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures * no-mistakes(document): Captain: document watcher successor protocol behavior * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: fetch current PR head for review diffs (#722) * fix: always fetch PR head for review diffs Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded pr_head= so reviewers never hold a merge over a "missing" fix that already landed on the remote PR. Recorded SHA is offline fallback only; local branch is last resort with a warning. Store the tip under refs/fm-review/ so a later base-branch fetch cannot clobber the compare tip via FETCH_HEAD. * no-mistakes(test): Isolate session-start nudge tests from gate state * no-mistakes(document): Correct review-diff documentation * docs: resolve five contract contradictions across AGENTS.md, README, and skills (#736) * docs: resolve five contract contradictions * no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck * docs(harness): correct Grok exit guidance (#742) * docs(harness): reverify grok exit command * no-mistakes(test): Correct Grok exit resume attribution * fix(watcher): bound stale wakes for parked crew (#743) * fix(watcher): bound stale wakes for exited paused crew * no-mistakes(review): Gate pause suppression on confirmed agent death * no-mistakes(test): Fixed stale pause cadence * no-mistakes(document): Document dead-agent hold cadence * fix(supervision): distinguish ordinary wakes from recovery (#744) * fix(supervision): distinguish ordinary wakes from repair * no-mistakes(review): Make passive guard follow-ups recovery-only * no-mistakes(document): Clarify recovery-only turn-end guard documentation * fix(x-mode): dedupe pending mention wakes (#745) * fix(x-mode): dedupe pending mention wakes * no-mistakes(review): fix x-poll claim error deduplication * no-mistakes(review): separate claim diagnostics from relay recovery * no-mistakes(document): Document X-mode once-only mention wakes * feat(wake): enrich drained signals with bounded status context (#747) * feat(wake): enrich drained signal context * no-mistakes(review): Bound wake enrichment reads * no-mistakes(document): Document wake-drain annotations * docs(wake): explain at-least-once drain boundary * no-mistakes(review): Prevent symlink races in wake annotations * no-mistakes(review): Exercise wake symlink race regression * test: document intentional AFK marker subprocesses * fix(wake): isolate annotation marker state * feat(herdr): add optional presentation spaces (#784) * feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately * fix(send): treat opencode busy-queued composer state as submitted (#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable * fix(spawn): require two stable reads before accepting worktree path (#765) * fix(spawn): require two stable reads before accepting worktree path The treehouse-get worktree-detection loop in fm-spawn.sh accepted the first pane_current_path read that differed from the project path, but on some tmux/WSL setups a brand-new window transiently reports a stale-but-real path before the pane actually settles into the worktree. Since that stale path is itself a real, distinct git checkout, it also passes validate_spawn_worktree's isolation check, so the loop silently recorded the wrong worktree in state/<id>.meta (and, for claude harness spawns, installed the turn-end hook there too). Require two consecutive polls to agree on the same non-project path before accepting it, using the existing inter-poll sleep as the confirmation gap so an already-settled pane isn't slowed down by an extra cycle. * fix(tests): drop unused CASE_DIR read in worktree-settle test ShellCheck SC2034: CASE_DIR is split out of the case record but never referenced; discard it with _ instead. --------- Co-authored-by: Freudator86 <tim@allesknut.de> * fix(bin): make watcher process identity immune to Linux wall-clock changes (#752) * fix(watcher): stabilize Linux process identity * no-mistakes(document): document FM_PROC_ROOT_OVERRIDE and Linux starttime identity rationale * fix: prevent AFK idle stalls and stale run attribution (#758) * fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts * fix(bin): allow safe teardown during watcher recovery (#750) * fix: allow safe teardown during watcher recovery * no-mistakes(review): Distinguish unsafe-teardown deny guidance via policy reason code * no-mistakes(document): Sync continuity-gate docs to allow teardown recovery * test: mark dynamic teardown fixture literal * no-mistakes(document): docs: add teardown to continuity gate allow list * feat(herdr): order presentation spaces while preserving focus (#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation * fix(bin): send literal config reread nudges after pushes (#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation * feat(watch): follow GitLab merge requests to merge (#797) * feat(watch): follow GitLab merge requests to merge The merge watch only understood GitHub pull requests, so a task whose deliverable is a GitLab merge request was never followed to merge. Generalize the stored poll identity from owner/repository to a provider-tagged provider/url/host/path/number record. GitLab runs mostly on self-hosted instances and its projects nest under groups at no fixed depth, so the host and the full project path are data in the record rather than constants, and every consumer rebuilds the URL from those parts and refuses any record that does not reconstruct it exactly. The GitLab state is read with plain glab, matching the GitHub path's use of plain gh, so an upstream checkout needs no extra tooling. Two things about glab were established by running it rather than assumed, because a wrong invocation here fails silently into a permanent "not merged": - glab has no field selector, and its JSON would need a JSON processor that firstmate does not require, so the state is read from glab's own field output. Only an exact "merged" wakes firstmate, so a changed format stays silent instead of reporting a merge. - glab cannot take a merge request URL the way gh can, because that form resolves through the current git repository and the watcher has none. It is addressed by project URL and merge request number instead. An absent glab produces no wake rather than a false merge, and arming refuses with a clear message since that is the one point where a missing CLI can still be reported. A GitLab task records no pr_head, which both consumers already treat as optional. The merge path still addresses GitHub only and refuses a merge request URL rather than sending it to the wrong forge. The record version moves to v2, and the existing non-executing migration rebuilds an already-armed watch from its recorded URL, so no watch is lost by upgrading. docs/gitlab-merge-watch.md records the evidence, taken against the public fixture project https://gitlab.com/KarotKris/gitlab-merge-watch-fixture. * no-mistakes(review): Reject github.com host in GitLab MR URL/sidecar validation * no-mistakes(document): Note GitLab MR URLs are explicitly refused, not just malformed ones, in fm-pr-merge.sh docs * fix(herdr): group projected children beneath owning parents (#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck * fix: keep local no-mistakes tests intent-targeted (#823) * fix(no-mistakes): drop full-suite local Test override Local no-mistakes Test is intent-targeted; CI Behavior keeps the broad tests/*.test.sh suite. Keep commands.lint on bin/fm-lint.sh and add a focused contract test so the override cannot silently return. * no-mistakes(lint): Make CI contract assertion ShellCheck-clean * feat: add canonical timed test runner (#825) * feat(test): add canonical timed suite runner and honest CI timeout Introduce bin/fm-test-run.sh as the single serial owner for selecting one script, a family, a conservative changed-file set, or the explicit complete suite, with per-script timing markers and a JSON artifact. Wire CI Behavior through the runner, raise the hang-tripwire timeout to 25 minutes, and document entry points without restoring a full-suite local no-mistakes Test command. * no-mistakes(review): Captain: fix changed selection and empty summaries * no-mistakes(review): Captain: fail closed on unmapped changed sources * no-mistakes(document): Document canonical timed test entry points * fix: surface main inventory gaps in Bearings (#830) * fix: disclose main-home orphan and unstructured inventory gaps Main Bearings could report an empty fleet while structured in-flight rows lacked meta or current backlog rows were free-form. Emit main_inventory from the fleet snapshot, map it into Bearings omitted surfaces and a Charted Next gate, and keep meta as the only live Underway source. * no-mistakes(document): Document Bearings inventory-integrity projection * no-mistakes: apply CI fixes * feat: add bounded concurrent test isolation proof (#832) * feat: add concurrent test isolation proof for Phase 2 Prove an audited portable candidate set passes under concurrent workers with private mode-0700 temp roots, without enabling production CI sharding or fm-test-run --jobs. * no-mistakes(review): Pin isolation proof to audited candidate manifest * feat: guard against missed secondmate reports (#834) * feat(secondmate): parent-owned guards for missed status reports Marked parent-to-secondmate requests now create a durable pending-reply expectation with a privacy-safe correlation id before delivery. Transport success never resolves it; only a correlated parent status or document pointer does. After a completed turn with no report, the parent sends one recovery repost and escalates once if that turn is also missed, without scraping the secondmate conversation or looping. * no-mistakes(review): Deduplicate wrong-home pending-reply sightings * no-mistakes(review): Harden pending-reply recovery and escalation guards * no-mistakes(review): Bound pending-reply backend polling * no-mistakes(review): Cache pending-reply status scans * no-mistakes(review): Protect undelivered pending-reply records from scans * no-mistakes(review): Close pending-reply delivery durability gaps * no-mistakes(review): Separate pending-reply transport outcomes * no-mistakes(review): Escalate stalled pending-reply deliveries once * no-mistakes(review): Resolve attempted deliveries from correlated reports * no-mistakes(review): Resolve late reports after delivery escalation * no-mistakes(document): Document pending-reply grace and ownership * no-mistakes(lint): Silence intentional pending-reply test fixture lint warnings * feat: require pinned real-Herdr CI coverage (#838) * feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat: shard portable tests and add bounded local parallelism (#841) * feat: shard portable CI tests after isolation proof Balance the Phase 2 proven-isolated set into two LPT portable parallel lanes from Phase 1 timing evidence, keep stateful work in a required portable serial lane, exclude real Herdr to its dedicated required lane, and prove complete inventory coverage with a deterministic guard. Add bounded local --jobs only for the proven set, per-lane timing plus aggregate artifacts, and reduce the interim portable hang tripwire now that the serial remainder owns the long wall-clock path. * no-mistakes(review): Captain, fix CI contracts and completion-order worker scheduling * no-mistakes(review): Captain, preserve stderr gate-skip detection in parallel tests * no-mistakes(document): Document portable sharding and timing aggregation * no-mistakes: apply CI fixes * fix: block primary-session delegation outside the fleet (#854) * feat: fence primary-session delegation outside the fleet A firstmate primary that delegates through Claude Code's built-in delegation tools creates work with no state/<id>.meta. Because fm-supervision-lib.sh counts *.meta and fm-turnend-guard.sh exits silently at zero, such work does not merely go unsupervised: it makes the whole guard stack structurally inert, and it dies with the primary session. On 2026-07-22 that cost two workers mid-flight and left supervision down for 73 minutes unnoticed. Layer 1, the primary fix: a permissions.deny list in .claude/settings.json removes the 18 delegation, scheduling, worktree, and task-tracking tools from the model's schema, so they are never offered. This is removal rather than interception, so there is no call to intercept and no fail-open path. The list is flat and in one file so its width stays reviewable; the captain owns that width. Layer 2, bin/fm-subagent-pretool-check.sh: a deny list is fail-open against tools that do not exist yet, and permissions.allow is a pre-approval list rather than an availability list, so there is no fail-closed allowlist to use instead. This backstop classifies the tool NAME by shape rather than against a fixed list, so a delegation tool that ships before the deny list is updated is still refused. It excludes mcp__* names and observe-or-stop operations, scopes itself to a genuine primary home via the shared fm_primary_scope_matches predicate so a crewmate's task worktree is unaffected, and offers one deliberate FM_ALLOW_SUBAGENT=1 escape hatch that must be set at launch. Verified live against Claude Code 2.1.217, including a deny-key A/B with a nonsense-name control, layer 2 denying an un-denied Workflow call, the same call allowed in a linked worktree, and the escape hatch. Corrects a prior finding: both Task and Agent work as deny keys, so both are pinned. Codex 0.144.1 verified to expose no delegation tool; grok, opencode, and pi are inspected and documented as not wired because those binaries are absent from this host and the repo requires live validation before trusting a harness hook. Evidence in docs/subagent-guard.md. * no-mistakes(review): Ship scoped Claude delegation guard * no-mistakes(test): Ship Claude delegation deny list * no-mistakes(document): Clarify PreToolUse guard ownership * no-mistakes(lint): Keep Claude deny list local * fix: install tasks-axi in portable CI shards (#866) Reproduction: portable-parallel-2 completed successfully without tasks-axi while fm-decision-hold-lifecycle emitted a gate skip in 30 ms. The pre-shard lane installed tasks-axi and exercised the test fully. Installing tasks-axi is the smallest counterfactual and makes the representative shard execute the test with gate_skip=false in about 20 seconds. Both parallel jobs receive symmetric setup, while the exact 91-test inventory and coverage guard remain unchanged. * feat(bin): make dispatch profiles quota aware (#867) * feat: make dispatch profiles quota aware * no-mistakes(review): Fix quota window and Grok product scoping * no-mistakes(document): Document implicit quota-aware dispatch accurately * Add built-in ahoy recap skill (#873) * fix: preserve trustworthy Bearings data in partial snapshots (#875) * fix: preserve mixed Bearings projections * no-mistakes(review): Enforce strict invalidity precedence for partial snapshots * no-mistakes(review): Enforce ownership for unknown child metadata * no-mistakes(document): Document partial structured Bearings projections * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * feat(pi): add session-local calm mode (#884) * Add session-local Pi calm mode * no-mistakes(review): Preserve Pi HTML exports during calm mode * no-mistakes(review): Preserve calm exports across submit bindings and share * no-mistakes(document): Document calm-mode feasibility across supported harnesses * fix(pi): prevent redundant watcher re-arms (#885) * fix(pi): limit watcher arm tool to recovery * no-mistakes(review): Strengthen Pi live re-arm regression coverage * no-mistakes(document): Document Pi first-cycle and recovery-only watcher arming * fix(pi): clean up Calm transcript rendering (#895) * fix(pi): clean up Calm transcript rendering * no-mistakes(review): Captain, preserve Calm exports and classify Pi launch briefs * no-mistakes(review): Captain, eliminate Calm gaps and verify exported conversations * no-mistakes(review): Restore Calm rows received while active * no-mistakes(review): Preserve diagnostics during Calm restoration * no-mistakes(document): Clarify Calm transcript behavior and injection paths * fix: execute every PR body compliance event (#898) * fix: execute every PR body compliance event * no-mistakes(document): Document independent PR compliance events * fix: exclude operational injections from ahoy boundaries (#899) * fix: distinguish operational input in ahoy * no-mistakes(review): Handle legacy Ahoy operational boundaries * no-mistakes(review): Narrow legacy Ahoy boundaries with live regressions * no-mistakes(document): Document Ahoy operational marker ownership * no-mistakes(lint): Suppress intentional literal fixture lint warnings * fix: canonically classify operational inputs across harnesses (#909) * fix: type canonical operational inputs * no-mistakes(document): Correct canonical operational-input documentation ownership * fix: avoid generic secondmate start acknowledgements (#926) * fix: avoid generic secondmate acknowledgements * no-mistakes(document): Document sparse secondmate acknowledgement behavior * no-mistakes: apply CI fixes * fix(pi): make calm mode persistent and gapless (#927) * fix(pi): preserve calm presentation across sessions * no-mistakes(review): Fix Calm home fallback persistence * no-mistakes(document): Clarify Calm gapless and export contracts * no-mistakes: apply CI fixes * fix(watch): retire merged PR polls after durable notification (#932) * fix: retire merged PR polls after notification * no-mistakes(review): Decouple PR retirement recovery from template updates * no-mistakes(review): Recover pending PR retirements before poll migration * no-mistakes(document): Document merged PR poll retirement contracts * fix: refine scout intake and parallel dispatch (#934) * Clarify intake evidence and overlap handling * no-mistakes(review): Align scout guard with intake classification * no-mistakes(document): Clarify scout documentation and intake ownership * fix(pi): prevent duplicate assistant replies in Calm (#936) * fix(pi): preserve operational follow-up semantics in Calm * no-mistakes(document): Correct Calm operational-row visibility documentation * perf(bin): shrink the ShellCheck source graph (#939) * perf(lint): shrink shell source graph * no-mistakes(review): Ensure lint workers terminate fully on cancellation * no-mistakes(document): Repair stale lint documentation ownership * fix(pi): remove Calm hidden-block gaps (#942) * fix(pi): remove Calm hidden-block gaps * no-mistakes(review): Validate Calm geometry against current viewport * no-mistakes(review): Synchronize Calm geometry checks with reload completion * fix: enforce contract boundaries for ask-user findings (#945) * fix: escalate ask-user contract expansion * no-mistakes(document): Point project management to authority owner * docs: prefer direct operational paths (#946) * fix(pi): hide operational user rows in Calm mode (#948) * fix(pi): hide Calm operational user rows * no-mistakes(review): Narrow Calm operational input suppression * no-mistakes(review): Avoid Calm replay classifier subprocesses * no-mistakes(document): docs: point Pi verification to Calm owner * fix: relaunch missing second mates at session start (#950) * fix(session-start): relaunch missing second mates * fix(test): detect completed parallel workers * no-mistakes(review): Isolate session-start recovery test cleanup * no-mistakes(review): Complete backend-safe secondmate session recovery * no-mistakes(review): Resolve Zellij task ownership before recovery * no-mistakes(review): Recover relocated Zellij ghost tabs safely * no-mistakes(review): Restore conservative Zellij recovery boundary * no-mistakes(review): Reject malformed tmux recovery targets * no-mistakes(document): Align secondmate recovery documentation * no-mistakes: apply CI fixes * fix(herdr): reclaim resumed task projections after restart (#967) * fix(herdr): reclaim resumed task projections safely * no-mistakes(review): Enforce safe Herdr reclaim close boundaries * no-mistakes(document): docs: clarify Herdr restart projection contract * Teach Ahoy to surface open decisions (#968) * Require shipshape routine acknowledgement (#969) * docs: separate current guidance from verification evidence (#994) * docs: separate current guides from verification * no-mistakes(review): Restore Herdr 0.7.5 restart-reclaim verification evidence * fix: preserve Claude watcher continuity across Stop hooks (#997) * feat(claude): Stop-owned tokenless watcher continuity via asyncRewake auto-arm Claude primaries (main home and marked secondmate homes) no longer depend on the model remembering to re-arm the watcher after each wake. A tracked Stop asyncRewake hook (bin/fm-claude-stop-autoarm.sh, timeout 28800s) fires on every turn end, claims one home-scoped single-flight owner, foregrounds bin/fm-watch-arm.sh inside the hook-owned process tree, and translates an actionable close or typed watcher failure into exactly one exit-2 rewake. The hook scopes to genuine primary checkouts, requires the session lock to be held by its own harness ancestor, stays inert while AFK owns triage or the home is idle, and hands AFK transitions mid-cycle to the daemon without rewaking. The synchronous turn-end guard gains a --claude cooperative mode: it ignores stop_hook_active (true on every post-continuation stop, which is what re-opened the 2026-07-21 blind window), waits briefly for a watcher health proof, a live auto-arm owner claim, or a fresh rewake epoch, and re-blocks only when the auto-arm genuinely failed to establish - bounded to 3 consecutive blocks per session, safely below Claude Code's 8-block override, then a degraded allow with a visible systemMessage. Codex keeps the previous one-block loop guard byte-identically, and Pi, OpenCode, and Grok adapters are untouched. Continuity PreToolUse gate and durable wake queue are preserved; the gate's recovery guidance now names the Stop-owned re-arm and reserves manual background arms for auto-arm failure. Claude supervision protocol, harness-adapters facts, architecture, configuration, and continuity docs updated; docs/turnend-guard.md records the 2026-07-24 Claude 2.1.218 contract revalidation (tokenless multi-cycle rewake, no-dedup, timeout process-group kill, 8-block cap, interactive non-stall) and the 2.1.219 product live E2Es. Regression matrix: hermetic tests cover scope, identity, AFK, need, single-flight, translation, guard cooperation, budget, and registration; the new live E2E proves two full tokenless auto-arm rewake cycles with zero model arm commands; Pi and OpenCode Option B live E2Es pass unchanged. * no-mistakes(review): Fix Claude X-mode auto-arm continuity backstop * no-mistakes(review): Remove unsupported Claude contract-lab verification claims * no-mistakes(document): Update Claude auto-arm continuity documentation * fix(herdr): clean stale projections at session start (#996) * Clean stale Herdr projections at session start * no-mistakes(document): Document stale Herdr session-start projection cleanup * no-mistakes(review): Enforce locked exact Herdr projection cleanup * no-mistakes(review): Fail closed on unverified session lock ownership * no-mistakes(review): Serialize session lock acquisition atomically * no-mistakes(document): Align session-start and Herdr cleanup documentation * no-mistakes(document): Generalize lock-refusal diagnostics * no-mistakes(lint): Avoid reserved keyword in concurrency test * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * fix: recover Claude supervision without watcher-status gate (#1001) * fix: recover Claude supervision at session start * fix: remove Claude watcher-status command gate * no-mistakes(document): docs: remove stale continuity gate references * fix: make quota-aware profile selection agent-owned (#1018) * Replace quota dispatch selector instructions * no-mistakes(review): Align bootstrap docs with agent-owned dispatch selection * fix(bin): remove vestigial dispatch selector (#1026) * remove vestigial dispatch selector * no-mistakes(review): Synchronize isolation proof and portable shard evidence * no-mistakes(review): Correct shard history and proof archive date * no-mistakes(review): Remove reintroduced selector documentation reference * no-mistakes(document): Remove stale dispatch strategy documentation * docs(agents): drop superseded interim quota-window rule (#1039) quota-axi 0.1.13 emits schemaVersion 2 with a quotaSemantics object per provider, so the successor named in the interim rule has landed and the rule's own removal condition is satisfied. Keep the ownership clause so quota-axi remains the single owner of how model or product windows relate to bounding account windows, and drop the interim weakest-headroom instruction. The unknown-semantics case is already covered by the existing requirement to stop and report a candidate whose applicable quota data or interpretation cannot be established. Drop the matching assertion phrase from tests/fm-instruction-owners.test.sh; the retained ownership phrase still asserts. * fix(tmux): scope busy detection and recognize current Claude turns (#1049) * fix(tmux): scope Claude busy detection by harness * no-mistakes(review): Separate verified and fallback busy signatures * no-mistakes(test): Scope busy signatures to supplied harnesses * no-mistakes(document): Document harness-scoped busy detection * feat: add verified Kimi crewmate adapter (#1047) * Add verified Kimi crewmate harness adapter * no-mistakes(review): Scope Kimi moon detection to spinner lines * no-mistakes(review): Match only complete Kimi spinner rows * no-mistakes(review): Resolve Kimi binary portably before pane creation * no-mistakes(document): Align Kimi adapter documentation * no-mistakes(lint): Suppress false-positive ShellCheck warning for sourced watcher override * Fix Kimi busy spinner detection * no-mistakes(review): Recognize Kimi session-lock ancestry and holders * no-mistakes(review): Scope pending-reply Kimi busy detection by harness * no-mistakes(document): Correct Kimi spinner capture documentation * no-mistakes(document): Clarify optional Kimi spinner whitespace * no-mistakes(lint): Silence intentional pending-reply test stub warnings * test: align rebased Kimi busy fixtures * no-mistakes: apply CI fixes * Reconcile Kimi busy detection after per-harness scoping * no-mistakes(review): Clarify observed Kimi spinner whitespace contract * no-mistakes(document): Clarify Kimi harness documentation * fix: harden Kimi submission and spinner matching (#1058) * fix kimi pointer submission and spinner conformance * no-mistakes(review): Preserve Kimi submit target ownership guard * feat(bin): add guarded Kimi turn-end wake (#1059) * Add guarded Kimi turn-end hook * no-mistakes(review): Require jq before installing Kimi turn-end hook * no-mistakes(review): Expose jq inside isolated Kimi test fixtures * no-mistakes(review): Preserve Kimi config boundaries during hook removal * no-mistakes(review): Document Kimi removal newline safeguard * no-mistakes(document): Document Kimi shared-home preservation * fix(tmux): classify bordered composers across all rows (#1066) * Fix structural tmux composer reading * Verify Calm compatibility with Pi 0.82 * no-mistakes(review): Harden structural composer classification boundaries * no-mistakes(review): Refresh composer and Kimi regression fixtures * no-mistakes(review): Fail closed on unbounded composer edges * no-mistakes(review): Enforce aligned composer geometry safely * no-mistakes(review): Make composer ambiguity locale-safe * no-mistakes(review): Preserve ambiguity through composer submission * no-mistakes(review): Carry composer proof through retries * no-mistakes(document): Document structural tmux composer delivery guarantees * no-mistakes: apply CI fixes * feat(bin): add verified pi-signed runtime adapter (#1145) * feat: add verified pi-signed adapter * no-mistakes(review): Correct pi-signed maintainer verification date * no-mistakes(review): Correct remaining pi-signed verification dates * no-mistakes(review): Preserve authoritative pi-signed runtime identity * no-mistakes(document): Document pi-signed shared adapter semantics * no-mistakes: apply CI fixes * fix(pi): rearm watcher across session transitions (#1166) * fix(pi): rearm watcher across same-process session transitions Pi emits session_shutdown for ordinary /new, /resume, and /fork replacement as well as terminal quit. The primary watcher extension latched a module-level stopping flag on every shutdown, so a replacement session in the same process could not arm monitoring until Pi restarted. Own arm authority per session generation so only the active live generation may start, stop, or rearm the child. Replacement sessions can arm again without restarting Pi, stale prior-generation callbacks cannot mutate the active cycle, and real quit still blocks late rearm. * no-mistakes(review): Preserve Pi generation isolation and exit cleanup * no-mistakes(document): Correct Pi watcher transition documentation * feat: route crew dispatch using quota-window pace (#1172) * Consume quota-axi pace signals in dispatch profile array selection. Add quota-array-dispatch as the single owner of the pace-aware candidate choice, keep AGENTS.md to the intake boundary and load trigger, and cover the acceptance cases with sanitized schemaVersion 3 fixtures. * no-mistakes(review): Stop and report genuine quota dispatch ties * no-mistakes(document): Document quota pace freshness and uncertainty * fix: adapt Grok Stop continuation and harden endpoint cleanup (#1171) * fix(grok): adapt Stop continuation to runtime capability * no-mistakes(review): Reject ambiguous Grok Stop payloads * no-mistakes(review): Reject duplicate Grok fields and accept spaced tmux sessions * no-mistakes(review): Enforce exact tmux cleanup selectors * no-mistakes(test): Fix historical tmux fixture and validate Grok Stop * no-mistakes: apply CI fixes * fix: restore stock macOS Bash 3.2 brief scaffolding (#1093) * fix(brief): make DOD scaffolding parse-safe on stock macOS Bash 3.2 fm-brief.sh built each Definition-of-done block and the not-enabled Herdr declaration with `VAR=$(cat <<EOF ... EOF)`. On Bash 3.2 (macOS /bin/bash) the lexer scans for the command substitution's closing `)` textually and tracks quote state through the heredoc body, so a single apostrophe, unbalanced quote, or unbalanced paren in that prose breaks parsing of the whole script. Every ship-brief scaffold (no-mistakes, direct-PR, local-only) failed with `unexpected EOF while looking for matching )`. Bash 4+ parses it fine, so the breakage stayed invisible everywhere except stock macOS. Replace all four command-substitution heredocs with `IFS= read -r -d '' VAR <<EOF || true`. That removes the `$(...)` wrapper and the entire defect class regardless of future prose, and preserves the variable expansion the direct-PR and local-only bodies need. `read` keeps the heredoc's trailing newline that `$(...)` used to strip, so trim one newline to keep every generated brief byte-identical to prior output. Guard the structure, not one historical phrase: a new test rejects any heredoc nested in a command substitution anywhere in fm-brief.sh, where the old assertion pinned a single apostrophe phrase and so missed the reintroduction. Extend the stock-macOS Bash CI job from parsing one script to the whole maintained shell surface (bin/*.sh, bin/backends/*.sh, tests/*.sh), matching bin/fm-lint.sh's canonical file set so parse scope and lint scope cannot drift apart. * no-mistakes(review): Captain: harden Bash structure and inventory guards * no-mistakes(document): Align stock macOS Bash contributor checks * no-mistakes(lint): Suppress deliberate SC2016 literal fixture warnings * test: stabilize tmux teardown conformance baseline (#1209) * fix(test): pin teardown tmux baseline to historical kill selectors merge-base HEAD main collapses to HEAD after the exact-selector change lands on the default branch, so the old teardown fixture was accidentally exercising current exact targets. Resolve a content-historical permissive tmux adapter from first-parent history and force that post-squash topology inside the conformance case so main and feature branches keep the same old-vs-new contract. * no-mistakes(lint): Suppress intentional literal-pattern ShellCheck warnings * docs: slim quota-array-dispatch to the pace selection core (#1197) Cut the runtime skill to the compact pace-aware selection procedure plus minimum owner pointers. Keep every distinct decision rule and move expanded acceptance scenarios to deterministic fixture ownership assertions. Size: 170/1374/10187 -> 63/544/4068 (about 63%/60%/60% reduction). * feat(bin): inherit backend config into secondmate homes (#1219) * Inherit config/backend into secondmate homes with deliberate-override preservation Add backend to the shared inheritable config allowlist so launch, locked bootstrap, and config-push converge a primary pin into secondmate homes as each home local future-spawn default. Track last-inherited bytes in a private state provenance marker so deliberate per-home overrides survive present and absent primary convergence, keep --backend and FM_BACKEND stronger, and extend the existing inheritance tests plus docs and skill claims. * no-mistakes(review): Preserve equal unprovenanced backend overrides * no-mistakes(review): Preserve symlink overrides and verify spawn precedence * no-mistakes(review): Snapshot backend inheritance for consistent provenance * no-mistakes(review): Simplify backend inheritance to primary-authoritative convergence * no-mistakes(document): Document inherited backend override preservation * fix: restore primary-authoritative backend inheritance after document regression The document step reintroduced provenance and deliberate per-home override semantics after review had simplified config/backend to plain primary-authoritative allowlist membership. Restore the primary-always-wins path: present overwrites, absent removes, no provenance marker, and docs/tests match that contract. * no-mistakes(review): Add divergent backend precedence regression fixtures * no-mistakes(document): Document backend inheritance contract * fix(pi): remove Calm's upper version ceiling (#1226) * fix(pi): remove Calm's exclusive Pi upper-version ceiling tests/fm-calm-pi-extension.test.sh gated on a closed PI_COMPAT_VERSIONS allowlist ("0.81.1 0.82.0") that refused any other installed Pi, and docs described that range as "supported" rather than verified evidence. The Calm CHANGELOG shows no API introduced at either version, so there is no evidence for a real minimum; the presentation adapters already probe the exact method they patch rather than checking a version. Replace the allowlist with dated version evidence that never rejects a newer Pi, and make each presentation adapter degrade independently with a diagnostic if a future Pi removes its API, instead of the whole Calm extension failing to load. Rewrite the feasibility doc's "Pi 0.81.1 through 0.82.0" phrasing to state it as verified evidence, not a ceiling. * no-mistakes(review): Probe missing Calm adapter exports safely * no-mistakes(document): Document Calm's unbounded Pi compatibility * fix(bin): allow session-local todo tools in the subagent guard (#1204) * fix(guard): allow session-local todo tools in the primary The delegation-shape guard denied TaskCreate and TaskUpdate because their normalized names contain the `task` stem. Those tools write only the harness's session-local todo list, which has no executor: it spawns no agent, allocates no worktree, registers no schedule, and starts nothing that outlives the session. That is not the unaccounted work the guard exists to stop, so the stem match was a false positive, and the deny text told the primary to run bin/fm-brief.sh and bin/fm-spawn.sh to create a todo entry. Add a separately-reasoned PLAN_ONLY_TOOLS exact-name exclusion rather than widening OBSERVE_ONLY_TOOLS, whose documented contract is tools that only observe or stop existing work. Both lists stay exact-name so neither can widen by substring. Tests cover the two allowed names and six near-miss names that a substring or shortened-stem widening would release; both mutations were watched red. * no-mistakes(review): drop session-local todo tools from recommended deny list * no-mistakes: apply CI fixes * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid (#1206) * fix(session-lock): resolve Claude bg-spare ancestry to the outermost claude pid fm_harness_ancestry_pid() previously returned the first ancestor process whose command matched a verified harness name. Claude Code's Stop hook fires as a bg-spare worker several levels below the session's actual lock-owning claude process (hook shell -> claude bg-spare -> claude bg-pty-host -> claude -> claude(lock)), so the first match was the bg-spare worker, not the lock owner. fm_session_lock_owned_by_self() then never matched state/.lock, and the Claude Stop auto-arm silently treated its own primary session as an unrelated live owner and never armed the watcher. The walk now keeps going past a claude-named match, looking for a still more ancestral claude-named match, and stops the instant a non-match follows an already-found match (bounding it to a contiguous run rather than the literal ancestry top, so an unrelated claude-named process further up the real process tree is never mistaken for part of this session's own nested chain). Every other harness keeps the original first-match-wins behavior, since e.g. Pi's shared signed-wrapper ancestry actually holds the session at the inner engine pid, not an outer wrapper pid. Hop limit raised from 8 to 16 to cover the deeper bg-spare chain. * no-mistakes(review): Add nested-claude-ancestry regression test; fix nudge doc depth claim * no-mistakes: apply CI fixes * fix: conferma l'avvio del watcher su Windows/MSYS (#1212) * fix: confirm watcher startup on MSYS * no-mistakes(review): gate MSYS arm ready timeout, cache uname, harden locale test * no-mistakes(review): validate OpenCode ready timeout, make uname cache internal * fix(spawn): forward CLAUDE_CONFIG_DIR to claude crewmates (#1195) * fix(spawn): forward firstmate's CLAUDE_CONFIG_DIR to claude crewmates Crewmate panes are created by a long-lived tmux/herdr daemon that does not inherit firstmate's current environment. When firstmate runs under a non-default CLAUDE_CONFIG_DIR (for example a work-vs-personal subscription split), a bare `claude` in the crewmate pane fell back to the default ~/.claude store and launched unauthenticated, blocking the crewmate before it could do any work. fm-spawn now prefixes the claude launch with firstmate's own resolved CLAUDE_CONFIG_DIR when set, so the crewmate uses the same credential/config store firstmate is authenticated with. An unset value is the single-store default and adds no prefix; non-claude harnesses are unaffected. Adds three tests in fm-spawn-dispatch-profile.test.sh (forwarded-when-set, omitted-when-unset, non-claude-ignored) and pins CLAUDE_CONFIG_DIR in the test helper so launch assertions no longer depend on the developer's environment. * no-mistakes: apply CI fixes * fix: preserve dispatch identity across authentication checks (#1233) * fix: preserve dispatch harness identity * no-mistakes(review): Fix Grok counterfactual tuple validation * no-mistakes(document): Scope dispatch authentication to selected tuple * fix: restore dispatch instruction budget * no-mistakes(review): Scope dispatch authentication after candidate selection * fix(bin): normalize relative durable paths (#1256) * fix(bin): handle dash-leading harness process names (#2) * fix: handle dash-leading harness process names * no-mistakes(review): Make dash-leading harness regression hermetic * fix: preserve secondmate reply routes across relative homes Resolve relative home, data, and state inputs before durable charter generation, and fail when caller-relative directories cannot be resolved. Use absolute paths at the related spawn, AFK daemon, and X-mode cross-process handoffs so later processes cannot reinterpret them from another working directory. * no-mistakes(review): Preserve absolute overrides and normalize relative durable paths * no-mistakes(review): Normalize relative home before deriving durable paths * no-mistakes(document): Document relative durable-path normalization * no-mistakes(review): Captain: Ignore inherited CDPATH during relative path normalization * no-mistakes(lint): Fix empty CDPATH assignments for ShellCheck * refactor(skills): make Bearings chat-only by default (#1136) * Add internal status skill * no-mistakes(document): register /status skill in documentation-audiences inventory * no-mistakes(lint): replace grep|wc -l with grep -c in status skill test * test: silence literal status skill patterns * Refactor bearings default to chat-only --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> * Clarify follow-up routing during validation (#1277) * fix: honor concrete approval for project operations (#1272) * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * docs: add captain-approved project operation exception to hard rule 1 Firstmate stays read-only over projects by default, but when the captain clearly approves a concrete project operation and scope in the moment, firstmate may perform exactly that approved operation with its own tools. The approval is never inferred, broadened, or standing, and it does not relax the existing force, discard, unlanded-work, or merge-authority boundaries. * no-mistakes(review): Clarify captain-approved project operation boundaries * no-mistakes(document): Clarify captain-approved project operation scope * docs: cover directories and preserve the operation-or-scope alternative Widen the captain-approved project operation exception in AGENTS.md to files or directories, and restore the explicit operation-or-scope alternative that a prior pipeline auto-fix had collapsed into "and". Rework project-management SKILL.md's Remove section, which previously told firstmate to refuse project removal until a guarded helper existed; that helper was never built, so the text directly contradicted the new instruction-only exception. It now points at the exception plus the existing removal preflight it still requires unchanged. Update the one instruction-owners test assertion that hard-coded the sentence removed above, so the suite tracks current, not obsolete, text. * no-mistakes(review): Align project removal preflight with approved exception * no-mistakes(document): Align project removal documentation with approved exception * fix: restore removal test byte-for-byte and preserve the default sentence tests/fm-instruction-owners.test.sh had been changed to assert different text; restore it byte-for-byte to origin/main. project-management SKILL.md's Remove section now keeps the exact default "Never issue a raw removal command from Firstmate." sentence that test still asserts, immediately followed by the already-approved captain-operation-or-scope exception, so the default and the exception both stay explicit and consistent. * no-mistakes(document): Align project-write boundary documentation * fix(skills): route new project intake through secondmate scopes (#1275) * Route project intake through secondmate scopes * no-mistakes(test): Guard all main-home project registry mutations * no-mistakes(document): Consolidate secondmate routing documentation * no-mistakes: apply CI fixes * Restore new-project routing scope * no-mistakes(document): Clarify secondmate routing for new-project intake * no-mistakes: apply CI fixes * fix: scope validation corrections by accepted behavior (#1281) * fix: scope validation corrections by accepted behavior * no-mistakes(review): Classify stale delivery evidence as an autonomous correction * test: replace source assertions with behavioral coverage (#1282) * test: remove source-content assertions * no-mistakes(review): Replace source assertions with runtime behavior coverage * no-mistakes(review): Isolate Kimi task temp runtime coverage * no-mistakes(document): Refresh test cleanup documentation * no-mistakes: apply CI fixes * fix(watch): escalate busy workers with no completed turn (#1286) * fix(watch): bound how long a busy pane may run with no completed turn A busy pane (backend busy state or the harness's rendered footer) was unconditional, unbounded proof of liveness in every escalation path, so a hung foreground tool call behind a busy signature could run for hours undetected (2026-07 hibit-agent-focus-nonsteal-r1 incident: a catastrophic- backtracking regex hung one bash call for 25h behind an unchanging "Working..." footer). FM_BUSY_TURN_MAX_SECS (default 3600s) now bounds how long a busy pane may run with no completed turn (state/<id>…
lytv
pushed a commit
to lytv/mymate
that referenced
this pull request
Sep 8, 2026
…nguid#688) Relabel absent-captain and related domain defaults wording so it names the firstmate repo rather than treating "template" as this domain's identity label. Keep the design-tenet "shared template" statements and unrelated launch/PR-poll template uses unchanged.
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
The captain objects to calling this repo/domain a "template" as an identity label for built-in defaults; that is inaccurate. Relabel tracked uses of "template" that stand in for THIS repo's built-in defaults to "the firstmate repo" phrasing, while KEEPING design-tenet statements that firstmate IS a reusable OSS template (AGENTS.md "This repo is a shared template..." and CONTRIBUTING.md "This repo is a template for running a firstmate orchestrator agent."). Also keep all unrelated command/file "template" uses: launch_template / launch template (spawn, architecture, configuration, harness-adapters) and PR-poll TEMPLATE hashes/vars. Do not touch gitignored data/. Named spots: AGENTS.md "means template defaults" and "use this template's defaults"; bin/fm-session-start.sh "captain.md absent = template defaults"; plus any other same-sense domain label found by grep (e.g. secondmate-provisioning "Firstmate template path"). Wording only - no behavior change. Tight reviewable diff; one sentence per line in Markdown; plain dash; bin/fm-lint.sh green.
What Changed
AGENTS.mdandbin/fm-session-start.shfrom template-based identity language to firstmate repo phrasing.Risk Assessment
✅ Low: Captain, risk is low because this is a tight wording-only change that preserves the required template identity statements and unrelated launch/PR-poll template uses while updating the named same-sense defaults references.
Testing
The pre-run full shell test baseline had already passed; I reran the session-start and instruction-owner suites, then captured a focused CLI transcript proving the relabel intent on the real tracked files plus isolated session-start behavior. All exercised tests passed, and the worktree was left clean; only
bin/fm-lint.shevidence is missing because this test prompt forbade linters.Evidence: Domain relabel evidence transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
bin/fm-lint.shto be green, but this testing prompt explicitly prohibited running linters or static analysis, so I did not runbin/fm-lint.sh. Lint evidence remains uncollected in this test step unless that rule is overridden or a later lint step runs it.command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"Baseline already ran successfully before this step:command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"bash tests/fm-session-start.test.shbash tests/fm-instruction-owners.test.shGenerated reviewer evidence withgit diff,rgchecks for required/protected/forbidden template wording, and an isolatedFM_HOME=... bin/fm-session-start.shdigest excerpt into/var/folders/5x/4nqprlbx0518k3ybcb1sz6gr0000gn/T/no-mistakes-evidence/01KXSETK42BKTB4MTPTTPCN8SG/fm-domain-relabel-evidence.txt✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.