Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
67130f1
feat(bin): make the ship-branch prefix configurable per project (#2648)
wesleymatosdev Sep 24, 2026
795e4b5
feat(bin): send dispatch router only the brief's task sections and ad…
zachlandes Sep 24, 2026
9284978
feat: add opt-in Claude away supervision host (#5488)
kunchenguid Sep 24, 2026
d4f3b78
docs: correct the Grok harness reference on folder trust, training op…
Courtneyezra Sep 24, 2026
5842d42
fix(bin): bound the startup-network worker's lock waits by its budget…
karotkriss Sep 24, 2026
e1d6cf9
fix(bin): make the ps-fallback watcher identity immune to terminal wi…
karotkriss Sep 24, 2026
474c6ee
fix(bin): ignore fenced and indented Captain lines when extracting au…
karotkriss Sep 24, 2026
0d983d2
fix(bin): forbid administering the shared worktree pool in crewmate b…
karotkriss Sep 24, 2026
977a81e
fix(bin): refuse tasks-axi add/create --start so In flight always has…
karotkriss Sep 24, 2026
e1b7f4f
feat: extend opt-in away supervision to non-Pi primaries (#5503)
kunchenguid Sep 24, 2026
d1ce6b6
fix: auto-relaunch dead secondmates during supervision (#5496)
kunchenguid Sep 24, 2026
31c47af
fix(bin): start a successor when the Claude Stop-hook arm's attached …
karotkriss Sep 24, 2026
b42d4fa
fix(bin): report a Lavish source armed only after its listener is run…
tiago-peixoto Sep 24, 2026
52e679b
fix(bin): stop repeating unknown-wake escalations that were already d…
tiago-peixoto Sep 25, 2026
c6e816f
fix(bin): keep a stated default-key retraction from cancelling a keyl…
tiago-peixoto Sep 25, 2026
a8572f6
fix(bin): terminate a remote job worker that lost ownership on TERM (…
tiago-peixoto Sep 25, 2026
4be8a40
docs: make configuration settings easier to find and understand (#5589)
tmchow Sep 25, 2026
b52d401
fix: limit project memory edits to factual corrections (#5636)
kunchenguid Sep 25, 2026
ca8c293
feat: permit gate lifecycle calls against disposable lab homes (#5635)
kunchenguid Sep 25, 2026
b575497
fix(bin): evict a watcher whose beacon stalls past a hard bound inste…
karotkriss Sep 25, 2026
5cec4e2
fix(pi): hide queued Firstmate inputs under Calm only when the sessio…
tiago-peixoto Sep 25, 2026
756f64e
fix(bin): refuse teardown when a required source disappears (#5548)
tiago-peixoto Sep 25, 2026
4e99de7
docs: make supervision-host easier to read (#5605)
tmchow Sep 25, 2026
660fa4a
docs: make the Herdr backend guide easier to read (#5606)
tmchow Sep 25, 2026
5323582
docs: make pi-supervision-branch easier to read (#5607)
tmchow Sep 25, 2026
d18a220
docs: make watcher-continuity easier to read (#5608)
tmchow Sep 25, 2026
70e41a8
docs: make sessionstart-nudge easier to read (#5609)
tmchow Sep 25, 2026
7c501a1
docs: make captain-hold-lifecycle easier to read (#5610)
tmchow Sep 25, 2026
c60f0ab
docs: make remote-secondmates easier to read (#5612)
tmchow Sep 25, 2026
683b3eb
fix(bin): bound the away digest and log why a delivery failed (#5554)
Sophylax Sep 25, 2026
dbe124d
test: add a gated harness seam and stabilize lifecycle fixtures (#5638)
kunchenguid Sep 25, 2026
1a814e4
fix(bin): refuse watchers from disposable checkouts and exit when the…
karotkriss Sep 25, 2026
84362f6
fix(bin): surface unrecognized status prefixes instead of reading the…
tiago-peixoto Sep 25, 2026
e97390a
fix(bin): report the failing item when remote inheritance fails (#5658)
karotkriss Sep 25, 2026
c643b57
fix(bin): stand down the Claude Stop auto-arm on pi-code-delivered pa…
karotkriss Sep 25, 2026
28c05cc
feat: bind host reports to wake rows
jazz127 Sep 25, 2026
fbd45fa
feat: keep routine branch outcomes out of chat
jazz127 Sep 25, 2026
9f610a6
fix: serialize branch report receipts
jazz127 Sep 25, 2026
aa6be75
merge: bring upstream main into house
jazz127 Sep 25, 2026
54e170f
merge: add wake-row reports to house
jazz127 Sep 25, 2026
5cbe8bd
merge: add routine outcome rules to house
jazz127 Sep 25, 2026
ee737f5
Merge branch 'housefeature/branch-report-receipt-lock' into fm/firstm…
jazz127 Sep 25, 2026
8225121
fix: reconcile house merge integration
jazz127 Sep 25, 2026
06676d5
no-mistakes(test): Expose wake row bindings to supervision engine
jazz127 Sep 25, 2026
5aa0472
no-mistakes(document): Clarify supervision host report scoping
jazz127 Sep 25, 2026
cd643c5
no-mistakes(lint): Removed unused jq assignment from remote doctor test
jazz127 Sep 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions .agents/skills/afk/SKILL.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,5 @@ The tracked hook anchors to `pwd -P`, verifies that root is Firstmate-shaped and

Codex's primary watcher protocol is `../../../bin/fm-watch-checkpoint.sh --seconds "${FM_CODEX_WATCH_CHECKPOINT:-180}"`, not `../../../bin/fm-watch-arm.sh`.
Codex cannot reason while a foreground tool call is running, so the checkpoint is deliberately foreground and bounded to return control regularly for user messages and queued notifications.
In a home with `config/supervision-host` the checkpoint runs the supervision host instead of the watcher, with Claude's print mode as its headless engine, and holds for at least an hour while away; [`supervision-host.md`](../../../../../docs/supervision-host.md) owns the host and that bound.
Codex's PreToolUse watcher-arm seatbelt blocks directly through its project hook.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Example: `../../../bin/fm-spawn.sh <task-id> <project> --scout --harness cursor
## Primary integration

Primary supervision is the stop-hook park in `../../../docs/supervision-protocols/cursor.md` through tracked `.cursor/hooks.json`; primary and secondmate launches require `--trust` or hooks do not load.
In a home with `config/supervision-host` the park runs the supervision host instead of `../../../bin/fm-watch-arm.sh`, with Claude's print mode as its headless engine; [`supervision-host.md`](../../../../../docs/supervision-host.md) owns the host.
Cursor exposes 20 project events plus a Claude-Code compatibility map that loads `.claude/settings.json`.
Tracked hooks register `stop`, `sessionStart`, and two `preToolUse` seatbelts through `$CURSOR_PROJECT_DIR`; Claude entries stand down on Cursor payloads under `../../../docs/turnend-guard.md`.

Expand Down
1 change: 1 addition & 0 deletions .agents/skills/harness-adapters/references/harness/grok.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,5 @@ The exact running Stop payload selects same-process continuation on 0.2.112; 0.2
Grok also loads Claude project settings, so Claude entries for Grok-covered events stand down under `GROK_AGENT` or `GROK_HOOK_EVENT`; that owner records the exact set and why `GROK_SESSION_ID` is excluded.
Project-local hooks require launch-time `--trust`; without it the guard steps aside and `../../../bin/fm-guard.sh` is the next-command alarm.
Watcher supervision remains tracked background notification around `../../../bin/fm-watch-arm.sh`, not Pi-style extension ownership.
In a home with `config/supervision-host` the session-start block renders that background call as `../../../bin/fm-supervision-host.sh park`, with Claude's print mode as its headless engine; [`supervision-host.md`](../../../../../docs/supervision-host.md) owns the host.
PreToolUse blocks directly, but every `$VAR` in a hook command needs inline `:-default` or Grok refuses the hook.
2 changes: 1 addition & 1 deletion .agents/skills/harness-adapters/references/harness/omp.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ There is no `agent_settled` event; `agent_end` plus `willContinue` replaces it.
The omp primary follows the Pi extension-owned watcher model through `../../../docs/supervision-protocols/omp.md`: `.omp/extensions/fm-primary-omp-watch.ts` arms `bin/fm-watch-arm.sh --restart` through the `fm_watch_arm_omp` tool and owns every successor, and `.omp/extensions/fm-primary-turnend-guard.ts` answers omp's blocking `session_stop` hook by forcing one continuation when `../../../bin/fm-turnend-guard.sh` returns 2, bounded per turn by omp's `stop_hook_active` flag.
The same file ports the `tool_call` seatbelts and delivers the session-start digest through `before_agent_start` on the Run tier; omp's `session_start` carries no reason, so the source is derived (first start `startup` or `resume` from the launch line, later in-process starts `clear`, `session_compact` as `compact`).
omp has no asynchronous Stop-hook equivalent, so the Claude auto-arm model does not apply; `fm_supervision_model` classifies omp as `extension`, and `fm_omp_extension_owns_supervision` in `../../../bin/fm-wake-lib.sh` is the ownership proof that tolerates the extension's own watcher hand-off.
The Pi supervision branch is out of scope for omp; every actionable wake is delivered to main.
The Pi supervision branch does not run on omp; without the supervision host every actionable wake is delivered to main, and in a home with `config/supervision-host` the watch extension spawns the host instead of the arm, with Claude's print mode as its headless engine ([`supervision-host.md`](../../../../../docs/supervision-host.md)).
Launch a primary with plain `omp` inside the home (`FM_OMP_HARNESS=omp omp` when starting from a Claude pane); `../../../bin/fm-session-start.sh` prints `OMP_WATCH_EXTENSION: not loaded` when the running session has not loaded both tracked extensions.
`FM_OMP_LIVE_E2E=1 ../../../tests/fm-omp-primary-live-e2e.test.sh` is the opt-in live guard; `../../../tests/fm-omp-harness.test.sh` is the portable regression.
A secondmate registered with `remote=1` in `data/secondmates.md`, spawned through the ordinary `../../../bin/fm-spawn.sh <id> <home> --secondmate` path, is refused on omp until a remote host verifies it, as is `../../../bin/fm-remote-secondmate-control.sh launch`; there is no `--remote` flag.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The primary integration was verified on 2026-07-08 with OpenCode 1.17.6.
`.opencode/plugins/fm-primary-turnend-guard.js` listens for `session.idle`.
Throwing from `session.idle` does not block `opencode run`, so the primary adapter treats the event as passive and uses `client.session.promptAsync` to force one follow-up turn when `../../../bin/fm-turnend-guard.sh` returns 2.
The follow-up was verified in the interactive TUI.
In a home with `config/supervision-host` the watch-arm plugin spawns the supervision host instead of `../../../bin/fm-watch-arm.sh`, with Claude's print mode as its headless engine; [`supervision-host.md`](../../../../../docs/supervision-host.md) owns the host.
`opencode run` can exit before displaying a queued follow-up, so the adapter steps aside in headless mode.
On native Windows, the operational-input adapter runs its Bash helper through `bash`; macOS and Linux invoke it directly.

Expand Down
4 changes: 3 additions & 1 deletion .agents/skills/process-event-sources/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ Posting that reply is best effort: a rare crash while the listener consumes the
A terminal round is never re-armed: the board stays yours until you acknowledge it with `bin/fm-procevent.sh handled <source-id> <sequence>`, which retires it, and until then `retire` refuses the board too.
Never arm a board that a live task hosts; follow the crew-hosted Lavish board contract in [`docs/configuration.md`](../../../docs/configuration.md#crew-hosted-lavish-review-boards).

Registering a source is not the same fact as listening to it: arming records the source, and a separate runner still has to pick it up.
Registering a source is not the same fact as listening to it.
Lavish `arm` waits until this registration's listener is confirmed running and does not report ready without that evidence; other adapters still record the source for the watcher's next reconcile.
When an earlier registration's listener still holds the board as the confirm window ends, Lavish `arm` prints `still-listening` instead of `armed`; that listener keeps serving the board, and the new registration takes effect only after you retire the source and arm it again.
After arming by hand, confirm `bin/fm-procevent.sh list` reports that source as `live`, and run `bin/fm-procevent.sh reconcile` when it does not.
Reconcile reports every launch that did not prove it took its claim within the confirm window as `failed=` and exits non-zero, so a source that cannot be started says so instead of looking armed, and it wakes you once per failure episode about it because the watcher discards that count; `start` does not fix that - if the source stays unowned, run `start` attached to read the runner's refusal, then check the source command and adapter binary the registration names, and if a later reconcile finds the source owned the episode closes on its own.
A source `list` reports as `orphaned` is one reconcile will not relaunch, because something may still be polling it; reconcile wakes you once about it, and that wake's payload says which of two recoveries applies.
Expand Down
10 changes: 5 additions & 5 deletions .agents/skills/stow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ Approved project-level destinations are not produced by stow: they ship normally
Because this destination is local and untracked, it is also the JIT home for private conditional knowledge that no committed surface may hold.
- An already-existing user-owned local on-demand note with an established trigger, after confirming it is untracked, private, and able to hold the quoted entry.
The pass may add the entry to that existing owner but never creates a new note, skill, or trigger for this purpose.
- A project's existing committed `AGENTS.md`, for project-intrinsic knowledge useful to nearly every session of that project, through a normal crewmate ship task using `bin/fm-ensure-agents-md.sh` and the project's registered delivery mode.
- A project-level skill in the project's own repository, for situation-conditional knowledge within one project, through the same ship-task path.
- A project-level skill in the project's own repository, for situation-conditional knowledge within one project, through a normal ship task and the project's registered delivery mode.
A project's committed `AGENTS.md` is never an offload destination: crewmates correct it but only humans extend it (AGENTS.md section 6).

Forbidden destinations: any firstmate-repo-tracked skill per the hard rule; firstmate's own `AGENTS.md`, which is always-loaded for every fleet session; `docs/` alone, which is never agent-loaded on demand, though a skill body may point into docs for depth; and any committed surface for private content.
A local skill exists only in this home, so offloading an entry out of `data/captain-shared.md` removes it from every inheriting home's always-injected memory: the proposal must say so, and the default for shared entries is keep.
Expand All @@ -190,7 +190,7 @@ A local skill exists only in this home, so offloading an entry out of `data/capt

1. Reduce non-pinned material now.
For each eligible non-pinned candidate, record its first line, source file, estimated tokens, one-line trigger, live destination, privacy and visibility verdict, and actual budget relief in the completion receipt.
Autonomously relocate it only by adding it to an already-existing allowed JIT note, or by routing it through a project's established delivery path to its existing owning `AGENTS.md`, then confirming that destination holds the quoted entry before removing the memory entry.
Autonomously relocate it only by adding it to an already-existing allowed JIT note, or by routing it through a project's established delivery path to an already-existing allowed project-level destination, then confirming that destination holds the quoted entry before removing the memory entry.
A destination that needs creation, uncompleted project delivery, or any other future work is not live and cannot count as relief, so continue with the next archival or eviction rung instead of leaving an over-budget proposal pending.
2. Propose pinned relocation only.
For a pinned candidate, append a `proposed-offload` section with the same fields to the completion receipt, create or refresh one durable backlog item with `bin/fm-tasks-axi.sh add`, `bin/fm-tasks-axi.sh show <id> --full`, and `bin/fm-tasks-axi.sh update <id> --body-file <path>` as appropriate, then hold it through `bin/fm-captain-hold.sh hold`.
Expand Down Expand Up @@ -220,8 +220,8 @@ A local skill exists only in this home, so offloading an entry out of `data/capt
Create `data/learnings.md` only for a genuinely new local learning with no stronger owner.
- In a primary home, curate shared captain preferences only under the existing primary-authoritative shared-preference contract.
In a secondmate home, route a newly discovered shared preference to the main firstmate through marked status or a document pointer instead of editing the inherited file.
- Project-intrinsic knowledge never goes directly into a project's `AGENTS.md`.
Route it through a normal ship task so a crewmate records it with `bin/fm-ensure-agents-md.sh` and the project's delivery path.
- Project-intrinsic knowledge never goes into a project's `AGENTS.md` through this fleet: a crewmate edits those files only to correct factually wrong information (AGENTS.md section 6), so no ship task carries an addition.
Keep the candidate in `data/learnings.md` or surface it in the completion receipt so the captain can extend the file by hand.
- Knowledge general to every Firstmate user belongs in this repo's shared tracked material through the normal branch, no-mistakes, PR, and captain-merge path.
- For task-scoped notes, inspect the item with `bin/fm-tasks-axi.sh show <id> --full`, classify the change as new, duplicate, superseding, or obsolete, then use a considered replacement body through `bin/fm-tasks-axi.sh update <id> --body-file <path>`.
Use `--archive-body` when recoverability matters.
Expand Down
4 changes: 3 additions & 1 deletion .no-mistakes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# no-mistakes review/fix/document/test/lint/pr/rebase/ci agent never adopts that
# identity or drives the fleet. Trusted-only: a pushed branch cannot turn this off,
# so it is honored only from the default-branch copy of this file. Layered above
# the NO_MISTAKES_GATE lifecycle refusal (bin/fm-gate-refuse-lib.sh) and the
# gate-context lifecycle boundary (bin/fm-gate-refuse-lib.sh) and the
# HEAD-continuity guard; see docs/architecture.md "No-mistakes gate authority boundary."
disable_project_settings: true

Expand Down Expand Up @@ -40,6 +40,8 @@ test:
Run live Herdr scenarios only through bin/fm-herdr-lab.sh with a named non-default fm-lab-* session, following that helper's prepare, provision, run, and teardown contract exactly.
Never touch the live default Herdr session or fleet panes.
Prefer a throwaway lab for spawn, long-launch, and Claude-path proofs, and tear it down in the same evidence turn.
To run a real primary inside the gate, mint a disposable lab home: `LAB=$(mktemp -d "${TMPDIR:-/tmp}/fm-lab.XXXXXX")` then `bin/fm-lab-home.sh create "$LAB"` and `mkdir -p "$LAB/tmux"`; write the scenario's opt-in flag (e.g. `touch "$LAB/config/supervision-host"`), and remove the lab in the same evidence turn with `rm -rf "$LAB"`. Lifecycle calls against any other home stay refused.
Start the harness CLI as the session command on the lab's private tmux socket, from the run worktree: `env -u NO_MISTAKES_GATE -u FM_GATE_REFUSE_BYPASS -u FM_ROOT_OVERRIDE -u FM_STATE_OVERRIDE -u FM_DATA_OVERRIDE -u FM_CONFIG_OVERRIDE -u FM_PROJECTS_OVERRIDE TMUX_TMPDIR="$LAB/tmux" tmux -L fm-lab new-session -d -s primary -c "$PWD" -e FM_HOME="$LAB" <cli>`, where <cli> is the harness's own launch command using the machine's existing login: claude -> `claude`, codex -> `codex`, cursor -> `cursor-agent`, opencode -> `opencode`, grok -> `grok`, omp -> `omp`. Drive, inspect, and stop that primary only through the same socket - `TMUX_TMPDIR="$LAB/tmux" tmux -L fm-lab send-keys -t primary ...`, `TMUX_TMPDIR="$LAB/tmux" tmux -L fm-lab capture-pane -p -t primary`, `TMUX_TMPDIR="$LAB/tmux" tmux -L fm-lab kill-server` - never the default tmux server; the firstmate scripts the primary runs inherit $TMUX from its pane, which names that same fm-lab socket inside the lab. The lab primary's scripts run from the gate worktree, whose git-common-dir triggers the gate check, and the marked lab home permits lifecycle without a bypass; the `env -u` list keeps inherited fleet-path overrides out of the fixture primary's environment so all paths resolve inside the lab. For a Herdr primary use a named non-default fm-lab-* session via bin/fm-herdr-lab.sh instead. If the harness CLI is absent or its login is unavailable, report the scenario untested; never fake the CLI, the login, or the evidence.
Do not mutate the operator primary checkout, real fleet FM_HOME state, or production credentials, and keep git changes otherwise inside the run worktree.
Read docs/herdr-backend.md and the bin/fm-herdr-lab.sh header as the owners of Herdr lab mechanics rather than reproducing that manual here.
Ship or scout briefs that will drive Herdr lifecycle still require --herdr-lab at scaffold time; these Test-agent instructions are not a substitute for that brief flag.
Expand Down
Loading
Loading