fix: align Grok effort handling with 0.2.99 - #527
Merged
Merged
Conversation
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.
Owner
|
Thanks @korallis - merged! Really appreciate the contribution. |
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 14, 2026
* fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com>
curtis-arch
added a commit
to curtis-arch/firstmate
that referenced
this pull request
Jul 15, 2026
* fix: preserve secondmate routing markers in terminal sends (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 * test(orca): pin conservative liveness baseline (rider P1) * docs(orca): record unavailable E1 observation (rider P2) * docs(orca): refuse ambiguous semantic mapping (rider P3) * docs(orca): record deferred liveness milestone (rider P11) * docs(orca): record actual E1 scout refusal (rider P11) * test(orca): tie E1 gates to runtime evidence (rider P3) * feat(orca): add semantic agent liveness * feat(orca): recover reminted terminal handles * no-mistakes(review): Fix Orca liveness and durable recovery edge cases * no-mistakes(review): Serialize metadata updates and harden Orca recovery CAS * no-mistakes(review): Harden task metadata lifecycle against reuse races * no-mistakes(review): Harden metadata lifecycle across task generations * no-mistakes(review): Harden resumable teardown and Orca metadata lookup * 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 * test(teardown): complete gotmp fixture dependencies * docs(orca): clarify metadata and liveness contracts * fix(shell): clear integration lint warnings * feat: supervise Orca attention states * fix: detect external Orca worktree destruction * feat(orca): add bounded team teardown guard * Revert "feat(orca): add bounded team teardown guard" This reverts commit 38c21e1. * feat(orca): team-pane primitives - CAS meta contract, fail-closed pane resolution, per-pane inventory state * feat(orca): fm-team.sh - explicit shared-worktree team contract (add/status/close, coordinator-only edit policy) * feat(orca): teardown enumerates and closes recorded team panes fail-closed before worktree removal * fix(orca): secondmate refusal names the exact missing adopt-existing-directory primitive * test(orca): team foundation fixtures from observed 1.4.141 shapes; document the team contract and refusal boundary * fix(teardown): prevalidate forced secondmate cleanup * test(shell): silence fixture lint false positives * fix(spawn): make secondmate replacement fail closed * no-mistakes(review): Harden replacement and teardown lifecycle ownership * no-mistakes(review): Harden replacement and teardown lifecycle ownership * fix(teardown): use arithmetic array index syntax --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com>
fongryan
added a commit
to fongryan/firstmate
that referenced
this pull request
Jul 16, 2026
…n current (#3) * fix: complete brief help and consolidate documentation (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 kunchenguid#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 kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#473) * feat: add deterministic bounded bearings snapshots (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: add closed-loop task lifecycle supervision * fix: close lifecycle supervision gaps * feat: import legacy tasks into lifecycle loop * feat: make bearings concise and accurate (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: bound firstmate secondmate recovery during bootstrap * fix: align Grok effort handling with 0.2.99 (kunchenguid#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: bound and rotate secondmate recovery * fix: preserve bounded recovery failures * feat: replace Treehouse with Git worktrees * test: isolate dispatch profile fixtures * test: isolate backend worktree root * fix: register detached lifecycle worktrees * fix: harden lifecycle startup and spawn cleanup * docs: retire Treehouse provider references * fix(firstmate): keep supervision keeper alive * docs(firstmate): document supervision keeper * fix: reject shared codex app-server as firstmate holder * chore: make no-mistakes optional * fix: resolve residual conflict markers after merge The auto-merge left several orphan <<<<<< / >>>>> markers and a few nested blocks where git recorded a content conflict but the regex-based script-resolution left lines like >>>>>>> origin/main stranded between clean sections. This commit removes them, takes the union of HEAD-vs-origin/main local-variable declarations in three of the affected files, and keeps both sides' content where they were complementary additions. No behavior change; the affected scripts all pass 'bash -n'. --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: mielyemitchell <mielyemitchell@gmail.com> Co-authored-by: mielyemitchell <249051873+mielyemitchell@users.noreply.github.com> Co-authored-by: Ryan Fong <noreply@anthropic.com> Co-authored-by: Korallis <lee.barry84@gmail.com>
Marl0nL
added a commit
to Marl0nL/firstmate
that referenced
this pull request
Jul 16, 2026
* fix: ignore secondmate home marker during sync (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#134) * test: isolate session-start suite from ambient harness markers (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 kunchenguid#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 kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#473) * feat: add deterministic bounded bearings snapshots (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (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 --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: fmtest <fmtest@example.invalid> Co-authored-by: Pierre Marais <pierremarais67@gmail.com> Co-authored-by: mielyemitchell <mielyemitchell@gmail.com> Co-authored-by: mielyemitchell <249051873+mielyemitchell@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: Marlon <marlonleicester@gmail.com>
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 17, 2026
* fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com>
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 19, 2026
* fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com>
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 20, 2026
* 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: durable pause recognition across watcher restarts (#1) * fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> * fix(herdr): distinguish submitted codex redraws * no-mistakes(review): Harden Herdr submit and nested inbox detection * no-mistakes(review): Harden Herdr confirmation and Codex activation * no-mistakes(review): Track all operations inbox events * no-mistakes(review): Captain: harden activation and bound inbox polling * no-mistakes(review): Captain: harden activation, cleanup, and inbox markers * no-mistakes(review): Harden activation and bound inbox scans * no-mistakes(review): Prevent capped inbox runners resetting deadlines * no-mistakes(review): Harden submit verification and cleanup recovery * no-mistakes(test): Preserve pause recheck grace * no-mistakes(document): Document operations-inbox scan bounds * no-mistakes(lint): Remove unused Herdr scan variable * test(orca): align abort cleanup fixture * no-mistakes(review): Fix Codex home cleanup identity arguments * no-mistakes(review): Harden failed-spawn cleanup safety * no-mistakes(review): Harden cleanup safety, captain * no-mistakes(review): Fail closed unknown Herdr preflight * no-mistakes(test): Fix teardown patch equivalence and OpenCode lock race * no-mistakes(test): Captain: align teardown tests with lock preflight * no-mistakes(document): Document submit and failed-spawn safeguards * fix(teardown): honor checkout default branch * no-mistakes(review): Harden teardown and inbox fingerprinting * no-mistakes(review): Bound ops inbox fingerprint scans * no-mistakes(review): Harden spawn cleanup and inbox overflow detection * no-mistakes(review): Stabilize overflowed inbox fingerprints * no-mistakes(review): Harden leased spawn cleanup and watcher reaping * no-mistakes(review): Captain: harden treehouse lease cleanup validation * no-mistakes(review): Guard treehouse leases against active worktree collisions * no-mistakes(test): Update spawn test fakes for verified treehouse leases * no-mistakes(document): Document strict spawn isolation and watcher timeout reaping * test(orca): preserve fixture default branch * no-mistakes(review): Captain: fail closed on unconfirmed submits * no-mistakes(review): Require confirmed Orca terminal absence before teardown * no-mistakes(review): Preserve Orca resources without terminal confirmation * no-mistakes(review): Captain: Preserve leases pending endpoint confirmation * no-mistakes(review): Preserve confirmed Orca terminal absence * no-mistakes(review): Honor confirmed Orca terminal absence * no-mistakes(review): Harden fm-send and Orca cleanup * no-mistakes(review): Harden backend agent liveness and Orca recovery * no-mistakes(review): Fail closed without native backend liveness * no-mistakes(review): Captain: harden explicit target liveness * no-mistakes(test): Fix fm-send test liveness fixtures * no-mistakes(test): Preserve endpoints on failed worktree cleanup * no-mistakes(test): Return lease before failed Codex activation cleanup * no-mistakes(document): Document fail-closed steering and teardown safety * no-mistakes(review): Fail closed on unverified Python liveness * fix(orca): retain abort cleanup state * fix(orca): preserve abort cleanup safety * test(send): model a live tmux agent * test(codex): keep activation fixture alive * fix(teardown): check locks before safety approval --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me>
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 21, 2026
* 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: durable pause recognition across watcher restarts (#1) * fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> * fix(herdr): distinguish submitted codex redraws * no-mistakes(review): Harden Herdr submit and nested inbox detection * no-mistakes(review): Harden Herdr confirmation and Codex activation * no-mistakes(review): Track all operations inbox events * no-mistakes(review): Captain: harden activation and bound inbox polling * no-mistakes(review): Captain: harden activation, cleanup, and inbox markers * no-mistakes(review): Harden activation and bound inbox scans * no-mistakes(review): Prevent capped inbox runners resetting deadlines * no-mistakes(review): Harden submit verification and cleanup recovery * no-mistakes(test): Preserve pause recheck grace * no-mistakes(document): Document operations-inbox scan bounds * no-mistakes(lint): Remove unused Herdr scan variable * test(orca): align abort cleanup fixture * no-mistakes(review): Fix Codex home cleanup identity arguments * no-mistakes(review): Harden failed-spawn cleanup safety * no-mistakes(review): Harden cleanup safety, captain * no-mistakes(review): Fail closed unknown Herdr preflight * no-mistakes(test): Fix teardown patch equivalence and OpenCode lock race * no-mistakes(test): Captain: align teardown tests with lock preflight * no-mistakes(document): Document submit and failed-spawn safeguards * fix(teardown): honor checkout default branch * no-mistakes(review): Harden teardown and inbox fingerprinting * no-mistakes(review): Bound ops inbox fingerprint scans * no-mistakes(review): Harden spawn cleanup and inbox overflow detection * no-mistakes(review): Stabilize overflowed inbox fingerprints * no-mistakes(review): Harden leased spawn cleanup and watcher reaping * no-mistakes(review): Captain: harden treehouse lease cleanup validation * no-mistakes(review): Guard treehouse leases against active worktree collisions * no-mistakes(test): Update spawn test fakes for verified treehouse leases * no-mistakes(document): Document strict spawn isolation and watcher timeout reaping * test(orca): preserve fixture default branch * no-mistakes(review): Captain: fail closed on unconfirmed submits * no-mistakes(review): Require confirmed Orca terminal absence before teardown * no-mistakes(review): Preserve Orca resources without terminal confirmation * no-mistakes(review): Captain: Preserve leases pending endpoint confirmation * no-mistakes(review): Preserve confirmed Orca terminal absence * no-mistakes(review): Honor confirmed Orca terminal absence * no-mistakes(review): Harden fm-send and Orca cleanup * no-mistakes(review): Harden backend agent liveness and Orca recovery * no-mistakes(review): Fail closed without native backend liveness * no-mistakes(review): Captain: harden explicit target liveness * no-mistakes(test): Fix fm-send test liveness fixtures * no-mistakes(test): Preserve endpoints on failed worktree cleanup * no-mistakes(test): Return lease before failed Codex activation cleanup * no-mistakes(document): Document fail-closed steering and teardown safety * no-mistakes(review): Fail closed on unverified Python liveness * fix(orca): retain abort cleanup state * fix(orca): preserve abort cleanup safety * test(send): model a live tmux agent * test(codex): keep activation fixture alive * fix(teardown): check locks before safety approval --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me>
quinnbot-ai
added a commit
to quinnbot-ai/firstmate
that referenced
this pull request
Jul 21, 2026
…d guard (#16) * 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: harden watcher arm relay leases * no-mistakes(review): Harden relay leases and cleanup identity * no-mistakes(review): Harden tmux ownership and review remote selection * no-mistakes(review): Harden watcher relay and tmux recovery safety * 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 * no-mistakes(test): Fix strict target-validation test fixtures * no-mistakes(document): Document relay lease hardening * no-mistakes(lint): Fix relay lease lint warnings * fix: reject symlinked Codex roots before spawn metadata * fix: reject symlinked Codex root before metadata * no-mistakes(review): Harden relay leases and normalize PR remotes * 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 * no-mistakes(test): Fix malformed tangle guard test fixtures * no-mistakes(document): Document watcher and daemon lease lifecycle * fix: preserve pre-metadata spawn refusal * no-mistakes(test): Preserve failed lease metadata and attached arm lifecycle logs * no-mistakes(review): Fix shared PR review fetch ref * no-mistakes(review): Harden daemon lease ownership handoff * no-mistakes(review): Harden stale daemon lease recovery and arm tick validation * no-mistakes(review): Fence stale AFK lease recovery * no-mistakes(review): Fence watcher identity lease publication * no-mistakes(review): Guard reclaimed AFK launcher locks * no-mistakes(review): Harden relay and launcher lease races * no-mistakes(document): Document daemon lease recovery grace * no-mistakes(lint): Isolate lease test helper shells * fix: harden watcher arm relay leases * no-mistakes(review): Harden relay leases and cleanup identity * no-mistakes(review): Harden tmux ownership and review remote selection * no-mistakes(review): Harden watcher relay and tmux recovery safety * no-mistakes(test): Fix strict target-validation test fixtures * no-mistakes(document): Document relay lease hardening * no-mistakes(lint): Fix relay lease lint warnings * fix: reject symlinked Codex roots before spawn metadata * fix: reject symlinked Codex root before metadata * no-mistakes(review): Harden relay leases and normalize PR remotes * no-mistakes(test): Fix malformed tangle guard test fixtures * no-mistakes(document): Document watcher and daemon lease lifecycle * fix: preserve pre-metadata spawn refusal * no-mistakes(test): Preserve failed lease metadata and attached arm lifecycle logs * no-mistakes(review): Fix shared PR review fetch ref * no-mistakes(review): Harden daemon lease ownership handoff * no-mistakes(review): Harden stale daemon lease recovery and arm tick validation * no-mistakes(review): Fence stale AFK lease recovery * no-mistakes(review): Fence watcher identity lease publication * docs: retain wake drain annotations * fix: preserve spawn refusal metadata boundary * fix: retain prepublication spawn rollback * test: model stable tmux endpoint cleanup * fix: retain prelaunch endpoint recovery 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: preserve watcher lease handoffs * fix(spawn): isolated CODEX_HOME for crewmate codex spawns (#3) * fix: isolate Codex crewmate MCP config * no-mistakes(review): Harden Codex home cleanup failures * no-mistakes(review): Harden isolated Codex crewmate launches * fix: scope Codex trust to worktree * no-mistakes(review): Harden Codex crewmate launch isolation * no-mistakes(review): Record failed Codex endpoint cleanup * no-mistakes(review): Harden case-insensitive Codex launch isolation * no-mistakes(review): Harden Codex raw launch isolation * no-mistakes(review): Harden Codex spawn isolation * no-mistakes(review): Harden Codex launch isolation cleanup * no-mistakes(review): Harden Codex wrappers and Orca cleanup metadata * no-mistakes(review): Harden Codex isolation and cleanup * no-mistakes(review): Captain: Harden Codex spawn isolation * no-mistakes(review): Harden Codex launch isolation * no-mistakes(review): Captain: Harden Codex launch isolation * no-mistakes(review): Captain: harden Codex activation and backend cleanup * no-mistakes(review): Harden Codex launch isolation * no-mistakes(review): Captain: preserve raw custom shell launches * no-mistakes(review): Harden Codex isolation and Zellij cleanup * no-mistakes(review): Confirm strict Zellij cleanup closures * no-mistakes(review): Harden Codex activation result isolation * no-mistakes(review): Harden Codex launch isolation * fix: harden failed spawn teardown * fix: harden Codex launch cleanup * no-mistakes(review): Harden indirect Codex launch isolation * no-mistakes(review): Harden Codex activation and builtin dispatch * no-mistakes(review): Harden Orca cleanup and raw launch parsing * no-mistakes(review): Confirm Orca terminal absence before cleanup * no-mistakes(test): Disable external review diff drivers * no-mistakes(test): Fix spawn isolation test fixture * no-mistakes(review): Respect explicit CODEX_HOME overrides * no-mistakes(document): Document Codex crewmate isolation * no-mistakes(lint): Fix ShellCheck lint diagnostics --------- Co-authored-by: QuinnBot <quinnbot@proton.me> * fix: isolate review diffs and Herdr prompt parsing (#2) * fix(watcher): preserve coalesced pause tracking * no-mistakes(review): Preserve immediate gone-worker wake detection * no-mistakes(review): Preserve pause-only signal handoffs * no-mistakes(test): Fix C-locale Herdr composer detection * no-mistakes(document): Document coalesced pause recovery --------- Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> * feat: surface operations inbox events in session start and watcher wakes (#4) * feat: surface operations inbox events * no-mistakes(review): Harden ops inbox polling * no-mistakes(review): Bound operations inbox polling * no-mistakes(review): Harden operations inbox polling * no-mistakes(review): Harden operations inbox polling * no-mistakes(review): Captain: bound ops inbox marker traversal * no-mistakes(review): Bound escaped operations inbox command capture * no-mistakes(document): Document operations-inbox controls * test: align ops inbox digest baseline * fix: keep watcher dependencies fork-local * fix: keep ops inbox signal output clean --------- Co-authored-by: QuinnBot <quinnbot@proton.me> * fix(watcher): preserve coalesced pause handoffs * fix(spawn): restore isolated Codex homes * fix(spawn): resolve isolated CODEX_HOME to a real path for macOS (#6) * fix(spawn): resolve isolated CODEX_HOME to a real path for macOS * test(spawn): assert real-path CODEX_HOME activation contract * style: apply formatter pass to fm-codex-home.py --------- Co-authored-by: QuinnBot <quinnbot@proton.me> * Fix teardown landed-work safeguards (#7) * Fix teardown landed-work safeguards * no-mistakes(review): Harden teardown landing safeguards * no-mistakes(review): Harden teardown cleanup safety * no-mistakes(review): Captain: harden Orca spawn cleanup * no-mistakes(review): Captain: harden cleanup safety * no-mistakes(review): Fix cmux cross-window task discovery * no-mistakes(review): Harden teardown ownership and legacy cleanup * no-mistakes(test): Fix teardown lock and endpoint cleanup * no-mistakes(test): Fix Herdr composer detection under C locale * no-mistakes(document): Document teardown containment safeguards --------- Co-authored-by: QuinnBot <quinnbot@proton.me> * test: cover legacy teardown task temp paths (#8) Co-authored-by: QuinnBot <quinnbot@proton.me> * fix: absorb declared pauses at parked gates (#9) * fix: absorb declared pauses at parked gates * no-mistakes(document): Document parked-gate pause handling --------- Co-authored-by: QuinnBot <quinnbot@proton.me> * fix(spawn): pin worktree-local git identity with Epstein boundary (#14) * 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 * Pin crew worktree git identities * no-mistakes(review): Captain: retry shared Git config initialization * no-mistakes(review): Normalize worktree config boolean handling * no-mistakes(test): Captain, isolate review diffs from external renderers * no-mistakes(lint): Silence unused retry loop variable * no-mistakes(lint): Remove unused ShellCheck local * test: align secondmate charter assertion --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * feat(watch): escalate busy-looking zero-progress crews (#12) * 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 * Escalate busy crews with no progress * no-mistakes(review): Captain: escalate AFK busy-progress wedges * no-mistakes(review): Scope pane progress parsing to current footer * no-mistakes(review): Captain: Harden busy-progress watcher safeguards * no-mistakes(review): Captain: clear teardown busy-progress state * no-mistakes(review): Harden busy-progress marker recovery * fix: cache watcher busy state * test: bound watcher cache cleanup * no-mistakes(test): Captain: stabilize tmux smoke and review diffs * no-mistakes(test): Captain: fix Herdr UTF-8 prompt classification * no-mistakes(test): Captain: fix transient Herdr worktree detection * no-mistakes(test): Fix checkpoint cleanup and spawn isolation * no-mistakes(document): Document busy-progress watcher escalation * test(brief): restore portable charter assertion --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * fix(spawn): durable worktree leases prevent held-slot reallocation (#13) * 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 * fix: hold treehouse worktrees until teardown * no-mistakes(review): rollback treehouse leases on spawn failures * no-mistakes(review): recover stranded treehouse lease handoffs * no-mistakes(review): Harden treehouse lease recovery * fix: serialize treehouse lease handoffs * fix: harden treehouse lease cleanup * no-mistakes(review): Tombstone returned treehouse lease handoffs * fix: harden treehouse teardown handoffs * fix: ignore transient lease handoffs * no-mistakes(test): Fix lease-aware test fixtures * no-mistakes(test): Fix locale-safe composer and watcher races * no-mistakes(test): Close AFK launcher signal race * no-mistakes(document): Document durable treehouse task leases * fix: preserve Orca abort cleanup through activation * fix: retain fork charter portability updates * test: model leased treehouse allocations in identity fixture * fix: close failed spawn endpoint before lease return * fix: retain committed lease on activation failure * fix: retain recovery metadata after lease commit * test: match durable lease handoff format * test: retain committed lease after endpoint closure * test: model absent endpoint in spawn abort fixture * test: initialize fixture repositories on main * fix: preserve durable returned lease tombstones * fix: make leased spawn setup failures deterministic * test: forward task temp failure injection * ci: trace tangle guard hang * test: make lease setup failure injection deterministic * ci: allow bounded watcher lifecycle tests to finish --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * fix(spawn): tolerate transient cwd reads and clean up refused spawns (#15) * 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 * 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(spawn): tolerate transient worktree cwd * no-mistakes(review): Guard leased worktree CWD resolution * no-mistakes(test): Captain: synchronize secondmate charter role assertion * no-mistakes(test): Stabilize Herdr heartbeat test waits * no-mistakes(document): Document spawn isolation safeguards * test: include lease helper in teardown fixture --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * Fix fail-closed fm-send delivery verification (#17) * 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: durable pause recognition across watcher restarts (#1) * fix: prevent no-mistakes gate agents from driving the fleet (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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 (kunchenguid#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: preserve declared pauses across watcher restarts * no-mistakes(review): Preserve unknown-state stale wake safety * no-mistakes(test): Stabilize PR review diffs --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> * fix(herdr): distinguish submitted codex redraws * no-mistakes(review): Harden Herdr submit and nested inbox detection * no-mistakes(review): Harden Herdr confirmation and Codex activation * no-mistakes(review): Track all operations inbox events * no-mistakes(review): Captain: harden activation and bound inbox polling * no-mistakes(review): Captain: harden activation, cleanup, and inbox markers * no-mistakes(review): Harden activation and bound inbox scans * no-mistakes(review): Prevent capped inbox runners resetting deadlines * no-mistakes(review): Harden submit verification and cleanup recovery * no-mistakes(test): Preserve pause recheck grace * no-mistakes(document): Document operations-inbox scan bounds * no-mistakes(lint): Remove unused Herdr scan variable * test(orca): align abort cleanup fixture * no-mistakes(review): Fix Codex home cleanup identity arguments * no-mistakes(review): Harden failed-spawn cleanup safety * no-mistakes(review): Harden cleanup safety, captain * no-mistakes(review): Fail closed unknown Herdr preflight * no-mistakes(test): Fix teardown patch equivalence and OpenCode lock race * no-mistakes(test): Captain: align teardown tests with lock preflight * no-mistakes(document): Document submit and failed-spawn safeguards * fix(teardown): honor checkout default branch * no-mistakes(review): Harden teardown and inbox fingerprinting * no-mistakes(review): Bound ops inbox fingerprint scans * no-mistakes(review): Harden spawn cleanup and inbox overflow detection * no-mistakes(review): Stabilize overflowed inbox fingerprints * no-mistakes(review): Harden leased spawn cleanup and watcher reaping * no-mistakes(review): Captain: harden treehouse lease cleanup validation * no-mistakes(review): Guard treehouse leases against active worktree collisions * no-mistakes(test): Update spawn test fakes for verified treehouse leases * no-mistakes(document): Document strict spawn isolation and watcher timeout reaping * test(orca): preserve fixture default branch * no-mistakes(review): Captain: fail closed on unconfirmed submits * no-mistakes(review): Require confirmed Orca terminal absence before teardown * no-mistakes(review): Preserve Orca resources without terminal confirmation * no-mistakes(review): Captain: Preserve leases pending endpoint confirmation * no-mistakes(review): Preserve confirmed Orca terminal absence * no-mistakes(review): Honor confirmed Orca terminal absence * no-mistakes(review): Harden fm-send and Orca cleanup * no-mistakes(review): Harden backend agent liveness and Orca recovery * no-mistakes(review): Fail closed without native backend liveness * no-mistakes(review): Captain: harden explicit target liveness * no-mistakes(test): Fix fm-send test liveness fixtures * no-mistakes(test): Preserve endpoints on failed worktree cleanup * no-mistakes(test): Return lease before failed Codex activation cleanup * no-mistakes(document): Document fail-closed steering and teardown safety * no-mistakes(review): Fail closed on unverified Python liveness * fix(orca): retain abort cleanup state * fix(orca): preserve abort cleanup safety * test(send): model a live tmux agent * test(codex): keep activation fixture alive * fix(teardown): check locks before safety approval --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * fix(watch): sync fork with upstream through 4ab61fa, fix pause-liveness merge regression (#18) * 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 * fix(watch): resolve fork/upstream pause-liveness merge conflict; add divergence runbook The fork/upstream sync merge (67c79e2) combined pause_state_class's parked-gate override (fork-local) with the new exited-agent liveness gate (upstream) in a way that was syntactically clean but behaviorally wrong: any class=paused verdict, including a plain authoritative "state: paused" read, was silently downgraded to none whenever the agent wasn't CONFIRMED dead - even for "unknown" liveness, which must never license an action on its own. Split crew_absorb_class into a line-based classifier shared with pause_state_class so the parked-gate-override case can bypass the liveness gate entirely (an explicit declaration is authoritative) while a confirmed-live agent at a plain "paused" read still gets a fresh surface, and unknown liveness keeps trusting whatever classification already stood. Full fm-watch-triage suite (56 tests) now passes clean. Also adds docs/fm-main-divergence/runbook.md: the verified, exercised command sequence for hard-aligning the primary checkout's local main to fork/main once this branch merges, plus the audit proving no local-only content is at risk and a root-cause note on why /updatefirstmate's base_mode="origin" never pulls fork-only merges. * no-mistakes(review): Captain: refresh fork tracking refs * no-mistakes(review): Reclaim orphaned Treehouse handoff writer files * no-mistakes(review): Recover X-mode wakes * docs: fail closed on runbook fetches * no-mistakes(test): Captain: restore second mate charter role * no-mistakes(document): Document paused wake recovery --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> * fix: harden watcher arm relay leases * no-mistakes(review): Harden relay leases and cleanup identity * no-mistakes(review): Harden tmux ownership and review remote selection * no-mistakes(review): Harden watcher relay and tmux recovery safety * no-mistakes(test): Fix strict target-validation test fixtures * no-mistakes(document): Document relay lease hardening * no-mistakes(lint): Fix relay lease lint warnings * fix: reject symlinked Codex roots before spawn metadata * fix: reject symlinked Codex root before metadata * no-mistakes(review): Harden relay leases and normalize PR remotes * no-mistakes(test): Fix malformed tangle guard test fixtures * no-mistakes(document): Document watcher and daemon lease lifecycle * fix: preserve pre-metadata spawn refusal * no-mistakes(test): Preserve failed lease metadata and attached arm lifecycle logs * no-mistakes(review): Fix shared PR review fetch ref * no-mistakes(review): Harden daemon lease ownership handoff * no-mistakes(review): Harden stale daemon lease recovery and arm tick validation * no-mistakes(review): Fence stale AFK lease recovery * no-mistakes(review): Fence watcher identity lease publication * docs: retain wake drain annotations * fix: preserve spawn refusal metadata boundary * fix: retain prepublication spawn rollback * test: model stable tmux endpoint cleanup * fix: retain prelaunch endpoint recovery state * fix: preserve watcher lease handoffs * no-mistakes(review): Harden tmux ownership and review remote selection * no-mistakes(test): Fix strict target-validation test fixtures * no-mistakes(document): Document relay lease hardening * no-mistakes(test): Fix malformed tangle guard test fixtures * fix: preserve pre-metadata spawn refusal * no-mistakes(test): Preserve failed lease metadata and attached arm lifecycle logs * no-mistakes(review): Harden stale daemon lease recovery and arm tick validation * no-mistakes(review): Fence stale AFK lease recovery * no-mistakes(review): Guard reclaimed AFK launcher locks * no-mistakes(review): Harden relay and launcher lease races * no-mistakes(document): Document daemon lease recovery grace * no-mistakes(lint): Isolate lease test helper shells * no-mistakes(review): Publish lease before watcher binding * no-mistakes(test): Fix watcher and Herdr teardown regressions * no-mistakes(test): Fix watcher and Codex activation test fixtures * no-mistakes(test): Preserve paused recovery across watcher restarts * no-mistakes(test): Remove duplicate pause-liveness test invocation * no-mistakes(test): Fix attached arm lifecycle ledger race * no-mistakes(document): Document lease and Git identity helpers * no-mistakes(lint): Resolve ShellCheck warnings in lease regression tests * no-mistakes(review): Reclaim reused watcher locks during normal arm * no-mistakes(review): Fence watcher lock reclaim race * fix: fence watcher restart reclaim * no-mistakes(review): Fence arm lease release by owner PID * no-mistakes(document): Correct operations inbox and relay lease docs * no-mistakes(lint): Remove unused treehouse lease assignment * no-mistakes(lint): Captain: remove unused treehouse lease assignment * fix(spawn): preserve prepublication refusal boundary * test(spawn): model stable tmux cleanup identity * test(spawn): cover stable data-root refusal cleanup * test(spawn): cover stable abort cleanup paths * test(spawn): model stable isolation cleanup * fix(watch): surface attached relay handoff failures --------- Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com> Co-authored-by: Israel Wilson <31997700+ICGNU3@users.noreply.github.com> Co-authored-by: QuinnBot <quinnbot@proton.me> Co-authored-by: nickespo7-del <261696157+nickespo7-del@users.noreply.github.com> Co-authored-by: Korallis <lee.barry84@gmail.com>
Keigyoku
added a commit
to Keigyoku/firstmate
that referenced
this pull request
Jul 23, 2026
* docs: compress AGENTS.md via instruction ownership skills Port upstream kunchenguid#619/kunchenguid#626/kunchenguid#736 instruction-ownership foundation adapted to this fork: add project-management, diagnostic-reasoning, and bootstrap-diagnostics skills; deepen stuck-crewmate-recovery, harness effort fallback, and coding-guidelines enforcement; compress always-on AGENTS.md while preserving fork-private layout, guards, watchdog, Crew Lead, role delivery, and X-mode triggers. * fix: stop free-text tokens promoting working status to captain-relevant Port the kunchenguid#758 classify-lib verb-awareness fix: nonterminal working:, resolved:, captain-held:, and paused: lines no longer become captain-relevant merely because prose contains merged/PR ready tokens. Bare legacy free-text tokens remain recognized. Prevents AFK idle stalls when progress notes mention a merged PR. * fix: reject grok xhigh/max in crew-dispatch validation Align bootstrap crew-dispatch effort validation with grok's model ceiling (low|medium|high only), matching spawn omission of unsupported tiers and upstream kunchenguid#527. Spawn already omitted xhigh/max; validation now flags them. * no-mistakes(review): Fix review findings and preserve override contracts * no-mistakes(test): Make backend conformance tests hermetic * no-mistakes(document): Restore authoritative dispatch schema documentation
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…
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…
This was referenced Aug 2, 2026
Merged
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
* 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
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>…
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
Fix stale grok effort-level documentation and spawn handling in firstmate after grok 0.2.99 tightened --reasoning-effort to only low/medium/high (rejecting both xhigh and max). Empirically verified on grok 0.2.99 with exact commands/output that MUST appear in the PR description:
$ grok --version
grok 0.2.99 (b1b49ccb71a7) [stable]
$ grok --reasoning-effort xhigh -p ping
--effort/--reasoning-effort: unknown effort level 'xhigh'; use one of: high, medium, low
(exit 1)
$ grok --reasoning-effort max -p ping
--effort/--reasoning-effort: unknown effort level 'max'; use one of: high, medium, low
(exit 1)
high is accepted (starts a session / does not reject at parse).
Updated harness-adapters skill table and grok section, changed fm-spawn.sh so grok omits xhigh (like max) instead of passing a rejected flag, aligned crew-dispatch bootstrap validation so grok:xhigh is flagged invalid, and extended colocated tests. Minimal accuracy fix only; not a refactor. Shared vocabulary still accepts xhigh/max as profile axis values for other harnesses; for grok they are recorded in meta but omitted from the launch command. Prior ask-user on grok-auth-evidence was approved: worktree empirical proof satisfies the evidence bar. Push via fork korallis/firstmate; open PR against upstream kunchenguid/firstmate.
What Changed
low,medium, andhighreasoning-effort levels supported by Grok 0.2.99; unsupported requested values remain in task metadata but have no launch flag.xhigheffort, and refreshfm-gotmpteardown fixtures for current helper dependencies.Risk Assessment
🚨 High: Captain, the code patch is narrowly aligned, but a mandatory delivery and evidence requirement is currently unmet.
Testing
The configured full-suite baseline had already passed. Focused bootstrap and spawn integration tests passed; live Grok 0.2.99 transcripts show xhigh/max parse rejection and high progressing beyond parsing, while isolated end-to-end spawn evidence confirms omitted rejected flags, retained metadata, and bootstrap validation. No worktree transients remain.
Evidence: Grok 0.2.99 parser compatibility transcript
Evidence: Grok high-effort parser acceptance transcript
Evidence: fm-spawn end-to-end effort handling transcript
Evidence: Bootstrap Grok xhigh dispatch validation transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
gh-axi pr list --state all --head korallis:fm/fix-grok-effort-docreturned zero results), so the required evidence cannot be present. Publish the branch and add the transcript before merge.✅ **Test** - passed
✅ No issues found.
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"Reported baseline: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"grok --versiongrok --reasoning-effort xhigh -p pinggrok --reasoning-effort max -p pingBounded, credential-isolatedgrok --reasoning-effort high -p pingbash tests/fm-bootstrap.test.shbash tests/fm-spawn-dispatch-profile.test.shRealbin/fm-spawn.shin an evidence-only fixture for Grokxhigh,max, andhigh, using fake tmux to capture the generated launch commandFM_HOME=<evidence fixture> FM_ROOT_OVERRIDE=<evidence fixture> bin/fm-bootstrap.shgit status --shortafter test cleanupkorallis:fm/fix-grok-effort-doc, so the required Grok 0.2.99 command/output transcript is not recorded in a PR description.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.