diff --git a/.agents/skills/bootstrap-diagnostics/SKILL.md b/.agents/skills/bootstrap-diagnostics/SKILL.md index acec5cb937..5225fa67ad 100644 --- a/.agents/skills/bootstrap-diagnostics/SKILL.md +++ b/.agents/skills/bootstrap-diagnostics/SKILL.md @@ -20,7 +20,7 @@ The inline rules in `AGENTS.md` section 3 still bind: detect, then consent, then For `no-mistakes`, this also covers an installed version older than 1.31.2, because crewmate validation briefs delegate gate mechanics to no-mistakes' version-matched guidance. For `tasks-axi`, this also covers an installed build that fails the compatibility probe (`docs/configuration.md` "Backlog backend" owns the definition); `config/backlog-backend=manual` only suppresses the `TASKS_AXI: available` capability line, not this missing-tool report. For `quota-axi`, bootstrap requires it because crew-dispatch `quota-balanced` may call it and direct account-directory selection uses it; `bin/fm-dispatch-select.sh` still degrades at runtime when quota data is unavailable. - Direct account-directory selection also requires Agent Fleet's read-only profile registry to enforce crew-pool eligibility. + Direct account-directory selection also requires Agent Fleet's read-only profile registry to enforce worker-pool eligibility. - `MISSING_MANUAL: (instructions: )` - tell the captain why the tool is required and give them the printed instructions URL, but do not pass the tool to `bin/fm-bootstrap.sh install`; wait for the captain to complete the manual installation, then rerun session start to confirm the dependency is present. - `BACKEND_INVALID: (known: )` - the resolved runtime backend has no verified dependency or lifecycle contract, so do not dispatch work until the invalid `FM_BACKEND` or `config/backend` value is corrected to one of the listed backends. - `ACCOUNT_ROUTING: invalid routing policy - ` - the environment or `config/account-routing-mode` cannot resolve to exactly one of `off`, `observe`, or `enforce`; fix the reported source before dispatch because managed spawns will fail closed on the same policy error. diff --git a/.agents/skills/harness-adapters/SKILL.md b/.agents/skills/harness-adapters/SKILL.md index 22864d15ff..19b3cdeed0 100644 --- a/.agents/skills/harness-adapters/SKILL.md +++ b/.agents/skills/harness-adapters/SKILL.md @@ -22,7 +22,7 @@ Secondmates have their own harness knob, so a secondmate can run on a different `config/secondmate-harness` is the harness the primary uses to launch SECONDMATE agents, resolved through the fallback chain `config/secondmate-harness` -> `config/crew-harness` -> firstmate's own. An absent or `default` `config/secondmate-harness` therefore behaves exactly as the crewmate harness did before this knob existed (secondmates launched on the crewmate harness); setting it splits the two. The complete inheritable-config list is owned by the `secondmate-provisioning` skill. -This skill owns only the harness-relevant consequence: a secondmate's own crewmates use the primary's dispatch profiles, static harness value, and Claude crew model anchor, while `config/secondmate-harness` is the primary's own setting and is never inherited - secondmates do not spawn secondmates. +This skill owns only the harness-relevant consequence: a secondmate's own crewmates use the primary's dispatch profiles, static harness value, and Claude crewmate model anchor, while `config/secondmate-harness` is the primary's own setting and is never inherited - secondmates do not spawn secondmates. Inheritance copies the literal `config/crew-harness` file, so for a secondmate's own crewmates to run on the primary's crewmate harness the captain must set `config/crew-harness` to a concrete adapter name, such as `codex`. If `config/crew-harness` is unset or `default`, there is no concrete value to inherit, so the secondmate's own crewmates fall back to the secondmate's own/detected harness rather than the primary's effective crewmate harness. Inheritance also copies the literal `config/crew-dispatch.json` file, so secondmates apply the same best-fit profile rules for their own crewmates. diff --git a/AGENTS.md b/AGENTS.md index 5c32cbb4af..4e2860bef1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -220,8 +220,8 @@ Secondmate launches are exempt because they resolve through `fm-harness.sh secon `quota-balanced` selection is deterministic and owned by `bin/fm-dispatch-select.sh`; every real new ship/scout launch uses direct account-directory selection. When candidates carry account pools, the selector chooses the ordered first profile and passes its pool to spawn only as a compatibility activation input, never as an account choice or lease request. -Direct selection reads Agent Fleet's profile registry only for pool membership, excludes profiles outside the provider's crew pool, and requires Claude's non-secret per-directory quota-axi Keychain approval marker before any fallback or rotation. -When no usable Claude crew account survives those checks, selection fails closed and names the reserved or approval-required reasons. +Direct selection reads Agent Fleet's profile registry only for pool membership, excludes profiles outside the provider's worker pool, and requires Claude's non-secret per-directory quota-axi Keychain approval marker before any fallback or rotation. +When no usable Claude account for crewmates survives those checks, selection fails closed and names the reserved or approval-required reasons. An explicitly declared `claude-crew-last-resort` pool is consulted only after `claude-crew` has no usable account; manual-only profiles remain excluded, and selector code never guesses account ownership from unreadable identity data. Fresh Codex quota is an opportunistic ranking signal. Exact best-score Codex ties and an all-unavailable quota result rotate across eligible accounts under a serialized persistent cursor; Claude always uses that rotation because its per-directory quota signal is unreadable. diff --git a/bin/fm-account-directory.sh b/bin/fm-account-directory.sh index 33a999d087..264a44f3fa 100755 --- a/bin/fm-account-directory.sh +++ b/bin/fm-account-directory.sh @@ -10,9 +10,9 @@ # Account homes are discovered under the current passwd user's # .local/share/agent-fleet/accounts// tree without fixed counts. # Agent Fleet's read-only profile list is the source of pool eligibility: -# direct crew selection considers only enabled worker profiles with real homes +# direct crewmate selection considers only enabled worker profiles with real homes # registered in the fixed -crew pool, so a disabled, manual-only, or -# non-worker profile is never a crew candidate and no caller-supplied +# non-worker profile is never a crewmate candidate and no caller-supplied # compatibility alias can weaken that boundary. # Claude may also declare a separate claude-crew-last-resort pool. # It is consulted only when no usable claude-crew profile remains; Firstmate @@ -20,7 +20,7 @@ # Claude eligibility also requires quota-axi's exact, non-secret per-directory # Keychain access marker. # That check happens after pool filtering and before rotation, so a reserved -# profile cannot become a fallback and an unapproved crew profile fails honestly. +# profile cannot become a fallback and an unapproved crewmate profile fails honestly. # Codex selection removes that account's quota-axi window cache immediately # before every read, sets CODEX_HOME plus the account-isolated XDG_CACHE_HOME, # accepts only a fresh result with at least one numeric five_hour or weekly diff --git a/bin/fm-bootstrap.sh b/bin/fm-bootstrap.sh index 767595fb51..ad65a72289 100755 --- a/bin/fm-bootstrap.sh +++ b/bin/fm-bootstrap.sh @@ -55,7 +55,7 @@ # bootstrap prints TASKS_AXI: available. quota-axi is required because # crew-dispatch quota-balanced may call it; fm-dispatch-select.sh still # degrades at runtime when quota data is unavailable. -# Routed direct crew selection also requires Agent Fleet's read-only +# Routed direct crewmate selection also requires Agent Fleet's read-only # profile registry so pool-reserved accounts can fail closed. # X mode is OPTIONAL and inert unless FM_HOME/.env has a non-empty # FMX_PAIRING_TOKEN. When opted in, bootstrap requires curl+jq, writes diff --git a/docs/architecture.md b/docs/architecture.md index e675c3b72d..c95464199e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -16,7 +16,7 @@ Repeated unchanged wedge or permission-stall escalations add an escalation count Those actionable wakes are written to a durable local queue (`state/.wake-queue`) before detector state advances, so a missed process exit can be recovered by draining the queue. No-verb wakes, such as `working:` notes and bare turn-ended signals, are benign only when `bin/fm-crew-state.sh` reports positive evidence that the crewmate is still working: an actively running no-mistakes step for that crewmate's branch or a backend busy signature. A crewmate that declares `paused:` for a known external wait is separately absorbed while idle and re-surfaced only on the longer pause cadence, rather than being treated as a possible wedge. -For stale-pane triage only, that durable declaration also explains the expected idle pane after a matching no-mistakes run has reached terminal `done` (including passed or checks-passed outcomes); active and failed runs retain normal run-step precedence, and stopped crew without a declared pause surface immediately. +For stale-pane triage only, that durable declaration also explains the expected idle pane after a matching no-mistakes run has reached terminal `done` (including passed or checks-passed outcomes); active and failed runs retain normal run-step precedence, and stopped crewmates without a declared pause surface immediately. Pause cadence markers remain in force while the latest durable status still declares the pause and are cleared only after that status resumes, so every continuously declared pause still re-surfaces on the bounded long cadence. Its initial normal-mode status signal still surfaces through the no-verb path, while away mode self-handles that routine signal and owns the later recheck. Fresh stale panes use the same current-state read before trusting the status log, so an active run or busy pane outranks an old captain-relevant status-log line left behind before validation. @@ -139,8 +139,8 @@ That keeps spawn launch compatible across claude, codex, grok, pi, and opencode New ship/scout observe and enforce account routing is backend-neutral and uses the direct profile-directory contract owned by [configuration.md](configuration.md#agent-fleet-account-routing). Routing remains default-off and adds no account field or provider environment override until an explicit account flag or observe/enforce policy enables it. The direct selector reads Agent Fleet only for pool membership and enabled worker eligibility, excludes disabled, non-worker, and manual-only profiles, requires Claude's fully validated non-secret per-directory Keychain approval marker, then uses fresh Codex quota opportunistically. -If no usable Claude crew account survives eligibility, the launch fails closed before fallback selection. -Claude can declare a separate last-resort crew pool, consulted only after its primary crew pool is empty; no identity inference participates in either tier. +If no usable Claude account for crewmates survives eligibility, the launch fails closed before fallback selection. +Claude can declare a separate last-resort worker pool, consulted only after its primary worker pool is empty; no identity inference participates in either tier. It serializes round-robin fallback and exact-score tie-breaking so unavailable usage and concurrent launches cannot collapse onto the stable first account. For quota-balanced account-pool candidates, new dispatch deterministically uses the ordered first profile and passes its compatibility alias to spawn only as the activation signal for direct per-account selection. The legacy Agent Fleet pool-summary selector is inactive deferred code tracked by `remove-fleet-routing-deadcode`; it is not available to new dispatches. @@ -177,7 +177,7 @@ When the harness token is unset or `default`, launch falls back to `config/crew- Those optional tokens are re-read on every secondmate spawn or respawn and are overridden by explicit per-spawn `--model` or `--effort` flags. An explicit per-spawn harness or raw launch command does not inherit model or effort tokens from `config/secondmate-harness`. `config/crew-harness` remains the crewmate harness and is inherited into secondmate homes. -`config/claude-crew-model` is inherited too, so Claude crews in every home validate the same exact `claude-opus-5` model anchor. +`config/claude-crew-model` is inherited too, so Claude crewmates in every home validate the same exact `claude-opus-5` model anchor. `config/crew-dispatch.json` is inherited too; secondmates use the same natural-language dispatch profiles when spawning their own crewmates. `config/backlog-backend` is inherited too; absent or `tasks-axi` selects the default tasks-axi backlog backend, while `manual` forces routine backlog updates to hand-editing across the fleet without disabling validated handoff delegation. diff --git a/docs/configuration.md b/docs/configuration.md index 7e6159fcea..8bf590525a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -154,7 +154,7 @@ Claude and Grok use background-notify cycles, Codex uses bounded foreground chec When it is absent or contains `default`, crewmates mirror the firstmate's own harness. Claude crewmate and scout launches additionally require the exact installed Opus 5 model before endpoint creation. `fm-harness.sh claude-crew-model` resolves the one-value local `config/claude-crew-model` anchor, whose absent-file default and only accepted value is `claude-opus-5`; an explicit `--model` must equal that resolved anchor. -The anchor is inherited into secondmate homes so the same rule governs their Claude crews. +The anchor is inherited into secondmate homes so the same rule governs their Claude crewmates. An empty, invalid, mismatched, or `default` anchor, a mismatched explicit model, and a raw Claude launch fail closed rather than inheriting or selecting another Claude model. The resolved model is both passed through Claude's `--model` flag and recorded as `model=` in task metadata. Fresh launches and recovery share this final resolution guard: recovery preserves an explicit recorded model, while legacy `model=default` metadata resolves through the anchor before relaunch and is rewritten to the value actually used. @@ -178,7 +178,7 @@ The exact discovery, fresh-usage, health, fallback, and Herdr-hook mechanics are The selected provider command receives `CLAUDE_CONFIG_DIR=` or `CODEX_HOME=`, and task metadata records the non-secret `account_home=` for observability. New ship/scout launches never ask Agent Fleet to enable a profile, establish identity, install a bundle, or acquire a lease. They use Agent Fleet's read-only profile listing as the authoritative pool-membership registry. -Only enabled worker profiles with real account homes registered in the provider's crew pool are eligible, so disabled, non-worker, and manual-only profiles cannot be selected for crew work. +Only enabled worker profiles with real account homes registered in the provider's worker pool are eligible, so disabled, non-worker, and manual-only profiles cannot be selected for crewmate work. Claude candidates must additionally carry quota-axi's exact non-secret per-directory `claude-keychain-access-granted` marker with the exact `granted` newline payload, mode 0600, current-user ownership, one link, non-symlink path components, and stable metadata. Pool filtering and the marker check happen before fallback selection; if no Claude candidate survives, launch fails closed with the reserved and captain-approval-required reasons instead of borrowing a manual profile. The optional declared `claude-crew-last-resort` pool is checked only after no usable `claude-crew` profile remains and is announced loudly when used. @@ -215,7 +215,7 @@ It never creates `account_pool=`, `account_profile=`, `account_task=`, `account_ Existing ship/scout tasks that already carry `account_profile=` metadata remain legacy Agent Fleet managed generations. That compatibility path is recovery-only for ordinary crewmates and is not used for any new ship/scout task. Secondmate launches continue to create and recover legacy Agent Fleet managed generations until their dedicated direct-account integration is designed. -Bootstrap requires Agent Fleet for direct crew-pool eligibility, for enforced secondmate routing, and when legacy `account_profile=` or pending rollback metadata exists. +Bootstrap requires Agent Fleet for direct worker-pool eligibility, for enforced secondmate routing, and when legacy `account_profile=` or pending rollback metadata exists. New direct ship/scout routing also requires `jq`, `quota-axi`, and Herdr's integration installer. Same-profile recovery is sticky and fail-closed: `bin/fm-spawn.sh --resume-account` validates existing task metadata and Agent Fleet's session mapping, uses `lease recover` rather than new-task quota selection, resumes the recorded provider session without replaying the brief as a new prompt, and requires a higher monotonic `session_event_seq` from a SessionStart accepted after its local launch gate before committing the recovered lease. Wall-clock `updated_at` remains diagnostic only and never decides launch freshness. diff --git a/tests/fm-account-directory.test.sh b/tests/fm-account-directory.test.sh index ab4ad2cd2f..dc2d040470 100755 --- a/tests/fm-account-directory.test.sh +++ b/tests/fm-account-directory.test.sh @@ -605,7 +605,7 @@ make_spawn_case() { touch "$home/state/.last-watcher-beat" # A leased Treehouse worktree is handed over at detached HEAD on a clean # default branch, and fm-spawn refuses one that is still attached to a branch - # (the crew creates its own). Reproduce that shape, not a generic worktree. + # (the crewmate creates its own). Reproduce that shape, not a generic worktree. fm_git_worktree "$project" "$worktree" "wt-$name" git -C "$worktree" checkout --quiet --detach HEAD git -C "$project" branch --quiet -D "wt-$name" diff --git a/tests/fm-account-routing.test.sh b/tests/fm-account-routing.test.sh index 4dcbb8eb66..92d52f9d67 100755 --- a/tests/fm-account-routing.test.sh +++ b/tests/fm-account-routing.test.sh @@ -570,7 +570,7 @@ test_off_is_byte_compatible_and_never_calls_agent_fleet() { assert_grep '# Completion report' "$HOME_DIR/data/$id/brief.md" "post-cutover spawn did not upgrade a legacy unspawned brief" # Assert each required section by the exact heading publication demands, not by # the sentence that happens to list them. The prose was reworded once already - # (to spell out the level-two requirement crews kept getting wrong) and this + # (to spell out the level-two requirement crewmates kept getting wrong) and this # assertion broke even though the contract still named all six - it was pinned # to phrasing rather than to the guarantee. for section in '## Summary' '## What changed' '## Verification' \ diff --git a/tests/fm-crew-state.test.sh b/tests/fm-crew-state.test.sh index 38c57acd4d..8a4d81265b 100755 --- a/tests/fm-crew-state.test.sh +++ b/tests/fm-crew-state.test.sh @@ -38,7 +38,7 @@ TMP_ROOT=$(fm_test_tmproot fm-crew-state) fm_git_identity fmtest fmtest@example.invalid # A real git repo checked out on , so the helper's branch attribution -# (git symbolic-ref) resolves like it would for a live crew worktree. +# (git symbolic-ref) resolves like it would for a live crewmate worktree. make_repo_on_branch() { # local dir=$1 branch=$2 mkdir -p "$dir" diff --git a/tests/fm-gate-refuse.test.sh b/tests/fm-gate-refuse.test.sh index e77164a86b..f37027ed05 100755 --- a/tests/fm-gate-refuse.test.sh +++ b/tests/fm-gate-refuse.test.sh @@ -95,7 +95,7 @@ make_gate_worktree() { } # make_normal_repo -> echoes a plain (non-gate) git repo to stand in for a -# normal primary/crew checkout: its git-common-dir is /.git, never a gate. +# normal primary/crewmate checkout: its git-common-dir is /.git, never a gate. make_normal_repo() { local dir=$1 git init -q -b main "$dir" diff --git a/tests/fm-secondmate-harness.test.sh b/tests/fm-secondmate-harness.test.sh index 21ed4011b9..f995b48d6a 100755 --- a/tests/fm-secondmate-harness.test.sh +++ b/tests/fm-secondmate-harness.test.sh @@ -480,7 +480,7 @@ meta_field() { grep "^$2=" "$1" 2>/dev/null | tail -1 | cut -d= -f2-; } # capture technique in fm-spawn-dispatch-profile.test.sh so the constructed # launch command (not just meta) can be asserted on. Also answers the # `#{pane_current_path}` probe from FM_FAKE_PANE_PATH so this same stub works -# for a crew/scout (non-secondmate) spawn's treehouse-worktree wait loop. +# for a crewmate/scout (non-secondmate) spawn's treehouse-worktree wait loop. make_launch_capturing_tmux() { local dir=$1 fakebin="$1/fakebin" mkdir -p "$fakebin" @@ -703,7 +703,7 @@ test_spawn_explicit_harness_uses_explicit_profile_axes() { # The harness fallback chain (secondmate-harness -> crew-harness -> own) still # resolves correctly with no model/effort tokens anywhere in the chain, and a -# crew/scout (non-secondmate) launch is entirely unaffected by this feature: no +# crewmate/scout (non-secondmate) launch is entirely unaffected by this feature: no # model/effort is invented for it even though its own project has no profile set. test_spawn_fallback_chain_and_crew_scout_unaffected() { local w sm meta home proj wt fakebin launchlog id launch spawn_err spawn_rc node_bin node_dir @@ -722,7 +722,7 @@ test_spawn_fallback_chain_and_crew_scout_unaffected() { [ "$(meta_field "$meta" model)" = default ] || fail "fallback: meta model should stay default with no tokens anywhere" [ "$(meta_field "$meta" effort)" = default ] || fail "fallback: meta effort should stay default with no tokens anywhere" - # Crew/scout launch: same crew-harness config, no --secondmate. Must resolve + # Crewmate/scout launch: same crew-harness config, no --secondmate. Must resolve # the crewmate harness and record no model/effort - this codepath must never read # config/secondmate-harness's tokens at all. id="crew-unaffected-z1" diff --git a/tests/fm-turnend-guard.test.sh b/tests/fm-turnend-guard.test.sh index 76048d951b..bf1177e176 100755 --- a/tests/fm-turnend-guard.test.sh +++ b/tests/fm-turnend-guard.test.sh @@ -136,7 +136,7 @@ make_crewmate_worktree_dir() { printf '%s\n' "$dir" } -# A secondmate home's OWN child crew/scout worktree: a genuine linked git +# A secondmate home's OWN child crewmate/scout worktree: a genuine linked git # worktree of the secondmate home, so git-dir != git-common-dir exactly as for a # main-home child worktree. A child worktree never carries the gitignored # .fm-secondmate-home marker, so the marker force-include never fires for it and @@ -424,7 +424,7 @@ test_hook_secondmate_reinvoke_recovery_loop() { } # The marker force-include must guard only the secondmate's OWN home, never its -# children: a secondmate's linked crew/scout worktree carries no marker, so it +# children: a secondmate's linked crewmate/scout worktree carries no marker, so it # stays exempt by the same git-dir/git-common-dir test that exempts the main # home's children. test_hook_silent_in_secondmate_child_worktree() {