Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b7bf2c
harden crewmate launch defaults to each harness's own controls
npayette84 Aug 31, 2026
92912ac
no-mistakes(review): grant codex network egress, force cursor non-pro…
npayette84 Aug 31, 2026
2466753
no-mistakes(review): restore cursor sandbox and bar it from unattende…
npayette84 Aug 31, 2026
17139fa
no-mistakes(review): widen cursor unattended bar to shared capability…
npayette84 Aug 31, 2026
537898e
no-mistakes(review): make cursor exemption a per-spawn audited flag
npayette84 Aug 31, 2026
616815a
no-mistakes(review): close remote and batch cursor exemption bypasses
npayette84 Aug 31, 2026
bc2f302
no-mistakes(review): test remote cursor bar, correct grok and codex n…
npayette84 Aug 31, 2026
430de8f
apply the captain's explicit-configuration cursor policy
npayette84 Aug 31, 2026
2ae9763
no-mistakes(review): fix cursor exemption inheritance, remote guard, …
npayette84 Aug 31, 2026
96e644e
no-mistakes(review): fix remote launch arg cap, effective-grant guard…
npayette84 Aug 31, 2026
ad38cc7
no-mistakes(review): inherit envelope grant on secondmate recovery, a…
npayette84 Aug 31, 2026
c6e70b2
no-mistakes(review): pin grant charset locale, regate inheritance, ac…
npayette84 Aug 31, 2026
35dd809
no-mistakes(review): accept exemption on relaunch verb, correct wire …
npayette84 Aug 31, 2026
935e146
no-mistakes(review): unify pre-stop and launch refusal behind one pre…
npayette84 Aug 31, 2026
2b093cb
no-mistakes(review): bound pre-stop invariant claim, route remote thr…
npayette84 Aug 31, 2026
cf4e221
no-mistakes(review): name per-kind cursor remedy, generalize environm…
npayette84 Aug 31, 2026
74941e0
no-mistakes(review): condition remote qualifier and secondmate remedy…
npayette84 Aug 31, 2026
4d825a2
no-mistakes(review): stub cursor binary, condition dispatch advisory,…
npayette84 Aug 31, 2026
5d70c98
no-mistakes(test): fix pre-existing bash 3.2 empty-array crash in rem…
npayette84 Aug 31, 2026
6c294cf
no-mistakes(document): document cursor dispatch advisory and detectio…
npayette84 Aug 31, 2026
52e2860
no-mistakes: apply CI fixes
npayette84 Sep 1, 2026
d20bb42
doc: consolidate worker-kind restriction ownership in the harness ref…
npayette84 Sep 2, 2026
ae6f805
no-mistakes(review): scope cursor grant to fresh launches, name distr…
npayette84 Sep 2, 2026
3c36908
no-mistakes(review): scope never-ambient rule to attended, narrow own…
npayette84 Sep 2, 2026
f70f408
no-mistakes(document): document remote cursor secondmate envelope-onl…
npayette84 Sep 2, 2026
927631d
no-mistakes: apply CI fixes
npayette84 Sep 2, 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
4 changes: 3 additions & 1 deletion .agents/skills/bootstrap-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: bootstrap-diagnostics
description: >-
Agent-only handling playbook for session-start bootstrap diagnostics.
Use whenever the session-start digest's bootstrap or network-checks section prints an actionable diagnostic line - MISSING, MISSING_MANUAL, BACKEND_INVALID, NEEDS_GH_AUTH, TANGLE, STARTUP_MEMORY_BUDGET, CREW_DISPATCH invalid, FLEET_SYNC, NETWORK_CHECKS, HOME_SUMMARY, BACKLOG_RECONCILE, SECONDMATE_SYNC, SECONDMATE_LIVENESS, SECONDMATE_HANDOFF, NUDGE_SECONDMATES, or FMX - or reports that an interrupted backlog cleanup may have left an endpoint or local copy, or when a standalone bin/fm-bootstrap.sh or bin/fm-startup-network.sh run prints one of those lines.
Use whenever the session-start digest's bootstrap or network-checks section prints an actionable diagnostic line - MISSING, MISSING_MANUAL, BACKEND_INVALID, NEEDS_GH_AUTH, TANGLE, STARTUP_MEMORY_BUDGET, CREW_DISPATCH, FLEET_SYNC, NETWORK_CHECKS, HOME_SUMMARY, BACKLOG_RECONCILE, SECONDMATE_SYNC, SECONDMATE_LIVENESS, SECONDMATE_HANDOFF, NUDGE_SECONDMATES, or FMX - or reports that an interrupted backlog cleanup may have left an endpoint or local copy, or when a standalone bin/fm-bootstrap.sh or bin/fm-startup-network.sh run prints one of those lines.
A silent bootstrap section, or any other BOOTSTRAP_INFO fact, means no skill load.
user-invocable: false
metadata:
Expand Down Expand Up @@ -35,6 +35,8 @@ When any diagnostic needs captain attention, report the plain consequence and re
- `STARTUP_MEMORY_BUDGET: invalid config/startup-memory-budget - <reason>` - the visible startup-memory budget is not a safe one-line positive decimal file; do not infer the default or propagate it.
Correct the local primary file, then rerun session start so the normal convergence path can deliver the validated value to secondmate homes.
- `CREW_DISPATCH: invalid config/crew-dispatch.json - <reason>` - the optional dispatch profile file exists but failed low-cost bootstrap validation; stop profile-based dispatch, report the actionable error, and require correction of the malformed schema, unverified harness name, or invalid harness/effort pair rather than falling back around it or selecting a bad profile.
- `CREW_DISPATCH: config/crew-dispatch.json - cursor is ineligible for ordinary dispatch here: <detail>` - the file is schema-valid and profile-based dispatch continues, but a rule naming `cursor` resolves a crewmate or scout spawn onto an adapter that is refused for unattended work.
Report it and have the rule name a harness verified for unattended work, unless every spawn that rule routes will pass `--cursor-exemption`; `docs/configuration.md` owns that harness rule and this advisory.
- `FLEET_SYNC: <repo>: skipped: <reason>` - a benign one-off skip (offline, no origin, local-only); bootstrap continued, investigate only if it blocks work.
A skip can also report the bounded fleet-refresh timeout (`FM_FLEET_SYNC_BOOTSTRAP_TIMEOUT`, or a fleet-size-aware default with a 20 second floor); a timeout never blocks startup.
- `FLEET_SYNC: <repo>: recovered: <detail>` - the clone had drifted onto a clean detached HEAD holding no unique commits and the sync self-healed it (re-attached the default branch and fast-forwarded); no action needed, it is reported only so the self-heal is visible.
Expand Down
3 changes: 1 addition & 2 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ For recovery and control, use the exact `harness=` in `state/<id>.meta`; never i
Deliver lifecycle actions only through `../../../bin/fm-control.sh <task-id> interrupt|exit|relaunch`.
Never type an interrupt key or exit command through `fm-send`, where routing-marked lifecycle text becomes chat.
Trust handling is complete only when inspection proves the target started processing its instructions; delivery success alone is not proof.
Muse is verified only for crewmate and scout work, never a secondmate or primary.
A verified adapter is not automatically admitted to every task kind; its harness reference owns that boundary.

## Detection

Expand All @@ -52,7 +52,6 @@ A new adapter's verified marker and command name must land in `../../../bin/fm-h
Every emitted plan appends the selected or recorded harness reference after the named common references.
The `harness-adapter-routing-v1` object is the machine-readable and human-visible selection contract: choose the operation, choose the scenario within it, then append the selected harness reference.
`default` is the normal scenario when no narrower scenario applies.
Kimi establishes its unsupported primary boundary in its selected harness reference; Muse follows Non-negotiable safety above.
A new tool remains undispatchable until the `verify` plan, its harness entry, every named owner, and the live checks land.

```json harness-adapter-routing-v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The inherited dispatch file applies the same best-fit profiles there.

## Owners

`../../../bin/fm-spawn.sh` owns launch, autonomy, concrete flags, task-kind compatibility, and worker turn-end wiring.
`../../../bin/fm-spawn.sh` owns launch, autonomy, concrete flags, and worker turn-end wiring, and asks `fm_control_harness_supports_kind` in `../../../bin/fm-control-lib.sh`, the one owner of task-kind compatibility.
Natural-language rules stay with firstmate, while scripts receive concrete axes.

`../../../bin/fm-busy-lib.sh` owns semantic busy trust.
Expand Down
20 changes: 18 additions & 2 deletions .agents/skills/harness-adapters/references/harness/claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,25 @@ Busy hooks verified 2026-07-28 on Claude Code 2.1.220.
| Skill | `/<skill>`, for example `/no-mistakes`. |
| Model | `--model <model>`; discover through the interactive `/model` picker, with alias or full-name shape documented by `claude --help`. |
| Effort | `--effort <low\|medium\|high\|xhigh\|max>`, verified on 2.1.196. |
| Autonomy | `--permission-mode auto`, so the worker runs under Claude's own classifier rather than `--dangerously-skip-permissions`, which bypassed every check. The spawn also sets `CLAUDE_CODE_DISABLE_FAST_MODE=1`; see "Auto mode" below. |

Fresh-worktree or first-machine launch may show trust or bypass-permissions confirmation.
Inspect within about 20 seconds, accept the required choice with `FM_HOME=<active-home> ../../../bin/fm-send.sh <window> --key Enter` unless already bound, and verify instructions started.
Fresh-worktree or first-machine launch may show the workspace-trust confirmation.
That is the only launch surface that still requires a keypress: inspect within about 20 seconds, accept the required choice with `FM_HOME=<active-home> ../../../bin/fm-send.sh <window> --key Enter` unless already bound, and verify instructions started.
The bypass-permissions confirmation can no longer appear, because Firstmate no longer passes `--dangerously-skip-permissions`.
Claude's auto-mode entry warning and its auto-mode-unavailable notice are transcript NOTIFICATIONS, not choices, and they need no acknowledgement.
Never send Enter for either one: the pane is already running, so that keystroke lands in the worker's composer.

## Auto mode

Auto mode is not unconditional, and the residual risk below is knowingly accepted rather than mitigated in code.
On 2.1.251 the session falls back to the prompting `default` mode when auto mode is unavailable for the account's plan, unavailable for the session model, disabled by settings, blocked because fast mode is on, or when the classifier transcript grows too long.
The fallback target is hardcoded to the prompting mode, so no setting redirects it to a non-prompting one, and a forced-unavailable run printed no warning at all.
An unattended crewmate has nobody to answer the permission prompt it falls back to, and the `claude-hook` busy fold keeps that pane reading as busy rather than surfacing a hold.
Even while auto mode IS in force the classifier can require confirmation for an individual call or block it outright, so a `git push` or `gh pr create` is not guaranteed to complete unattended.
The spawn sets `CLAUDE_CODE_DISABLE_FAST_MODE=1` to remove the one trigger a launch command controls, so a captain's own `/fast on` cannot degrade a running crewmate.
The plan, model, settings, and classifier-transcript triggers all remain server-controlled and are not launch-controllable, so a server-side degradation can still strand an unattended Claude worker.
It looks like a pane that stops progressing with no status write and no turn-end while still classified busy, so peek any such pane for a permission prompt before assuming it is working.
Firstmate threads an arbitrary `--model` from the dispatch profile into this same launch, so a model without auto-mode support is the most likely local cause.

## Composer ghost

Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/harness-adapters/references/harness/codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Verified on 2026-06-11 with codex-cli 0.139.0 unless a fact gives a newer versio
| Model flag | `--model <model>`. |
| Effort flag | `-c 'model_reasoning_effort="<low\|medium\|high\|xhigh>"'`, verified on codex-cli 0.142.1 whose installed schema contains `model_reasoning_effort`, active config uses it, and bundled catalog advertises only these four values while omitting `max`. |
| Model discovery | Open the current interactive session's `/model` picker. |
| Autonomy | `-s workspace-write -a never` with `-c sandbox_workspace_write.network_access=true`, so the worker runs under codex's own sandbox and never prompts, rather than with both switched off as `--dangerously-bypass-approvals-and-sandbox` did. Verified on codex-cli 0.150.1. |
| Sandbox | `workspace-write` confines the worker's writes to the task worktree plus `/tmp` and `$TMPDIR`. The explicit `network_access` grant is a separate axis, because that sandbox otherwise denies network egress by default and a crewmate could not push, use `gh`, or install dependencies. |

A directory trust dialog appears on the first run for a repository root: "Do you trust the contents of this directory?"
Accept it with Enter and verify the instructions begin processing.
Expand Down
22 changes: 17 additions & 5 deletions .agents/skills/harness-adapters/references/harness/cursor.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ Cross-harness provider and credential identity is owned by `references/common/mo
| Fact | Value |
|---|---|
| Binary | `fm_cursor_resolve_binary` in `../../../bin/fm-cursor-lib.sh` resolves stable launcher `cursor-agent` or legacy `agent`, never `cursor`; both symlink into `~/.local/share/cursor-agent/versions/<version>/cursor-agent`, whose target auto-update replaces. |
| Launch | Positional instructions with `--trust`, `--yolo`, optional `--model <model>`, and `--workspace <absolute-task-worktree>`, after clearing foreign primary markers. |
| Launch | Positional instructions with `--trust`, `--auto-review`, `--sandbox enabled`, optional `--model <model>`, and `--workspace <absolute-task-worktree>`, after clearing foreign primary markers. |
| Models | Use current-account `cursor-agent --list-models` or legacy `agent --list-models`; the drifting observed list had only `cursor-grok-4.5-high` and `cursor-grok-4.5-high-fast` for Grok plus several `xhigh` ids, so choose a returned reasoning id and never assume low or medium Grok. |
| Busy state | `../../../bin/fm-busy-lib.sh` folds the per-conversation transcript as `cursor-transcript`: `role:user` opens and typed `turn_ended` closes success or abort, covering manual interrupt; nothing is armed or seeded, and this backend-agnostic source was identical on tmux and Herdr. |
| Exit command | `/exit`. |
| Interrupt | Single Escape returns the placeholder with no clear key; control makes no cancellation claim because an aborted transcript close appeared within seconds in some runs and not within twenty in others. |
| Skill invocation | `/<skill>`, for example `/no-mistakes`; Cursor discovers Firstmate's user skills. |
| Resume | No verified native pane resume; use deterministic relaunch. |
| Autonomy | `--yolo`, documented alias for `--force`; footer `Run Everything`. |
| Trust | `--trust` suppresses the dialog; `--yolo` does not, and every task has a fresh path. |
| Autonomy | `--auto-review --sandbox enabled`, so the worker runs under Cursor's own review and sandbox controls. This replaced `--yolo` (the documented `--force` alias, footer `Run Everything`), which switched both off. Measured on 2026.08.25: `--sandbox enabled` genuinely confines writes under `--auto-review`, but `--force` overrides that confinement at any flag order, so Firstmate never passes `--force` or `--yolo`. |
| Trust | `--trust` suppresses the dialog; the autonomy flags do not, and every task has a fresh path. |
| Unattended work | Cursor is REFUSED for EVERY ordinary unattended kind: ship, scout, AND secondmate. `--auto-review` prompts for whatever its classifier does not deem safe, an unattended pane has no approver, and the `cursor-transcript` fold keeps a parked pane reading as working, so the stall never surfaces as a hold; a secondmate is the worst case because a whole Firstmate instance stalls invisibly. `fm_control_harness_supports_kind` in `../../../bin/fm-control-lib.sh` owns the rule for both the launch owner and the control plane, so a relaunch is refused before the running agent is stopped. The only opt-in is the per-spawn flag `--cursor-exemption attended` (a person is in the pane) or `--cursor-exemption envelope:<name>` (the named outer isolation envelope that governs the worker), which is recorded as `cursor_exemption=` in the task meta; use Codex or Claude for ordinary unattended work. |
| Marker | `CURSOR_INVOKED_AS=cursor-agent` on agent and children, plus `CURSOR_AGENT=1` on child or tool processes; other `CURSOR_*` variables are not identity markers. |
| Effort | No verified flag; `references/common/model-and-effort.md` owns unsupported-value handling. |
| Composer | Bare borderless row with `→` (U+2192); de-emphasized placeholders `Plan, search, build anything` when fresh and `Add a follow-up` later. |
Expand Down Expand Up @@ -57,12 +58,23 @@ Reverse-video placeholder remnants and Herdr half-block edges belong to `../../.
`../../../docs/verification/runtime-backends.md` owns captures.
Refresh with `FM_HARNESS_LIVENESS_DRIFT=1 ../../../bin/fm-test-run.sh ../../../tests/fm-harness-liveness-drift-live-e2e.test.sh`.

## Worktree boundary
## Worktree boundary and exemption grants

Firstmate enters its acquired worktree and passes the same absolute path through `--workspace`.
Never pass Cursor `-w` or `--worktree`, which allocates a second copy under `~/.cursor/worktrees` and breaks isolation.
The CLI supports repeatable `--add-dir`, but the adapter adds none; positional instructions need no grant to their private directory.
Example: `../../../bin/fm-spawn.sh <task-id> <project> --scout --harness cursor --model cursor-grok-4.5-high`.
Example of the ordinary case, which is REFUSED because nobody is watching a scout pane: `../../../bin/fm-spawn.sh <task-id> <project> --scout --harness cursor --model cursor-grok-4.5-high`.
Pass a grant only when it is true of this launch, because `attended` is an attestation that a person is sitting in the pane and `envelope:<name>` names the outer isolation envelope an audit can go check.
The grant is per invocation and never ambient, so neither an exported variable nor an earlier attended launch can silently exempt a later unattended spawn.
A captain who will watch the pane themself adds `--cursor-exemption attended`; a worker running inside the approved routing benchmark adds `--cursor-exemption envelope:routing-benchmark` instead.
An envelope name is bounded to letters, digits, `.`, `_`, and `-` starting on a letter or digit, so a grant cannot be unauditable or carry a line break into the task record.
An explicitly passed grant is refused on a non-cursor harness rather than recorded, on the local and remote spawn routes alike, while one inherited from a task's own record is dropped when that task restarts onto another harness.
Across a relaunch or a `--secondmate` respawn, the two paths that restart a task from its own record, an `envelope:<name>` grant is inherited while an `attended` one is not, because the person who attested may be gone by the time stuck-worker recovery relaunches; a fresh spawn always needs the flag.
A remote `--secondmate` route accepts `envelope:<name>` only and refuses `attended`, because that attestation describes a person at this pane and says nothing about a worker started on another host.
A remote host that finds its endpoint already alive returns that route without applying a newly passed grant, so the parent records the grant the endpoint reports back rather than the one it requested and says on stderr that the request did not take effect; recovery then inherits the envelope that actually governs the running worker.
Automatic recovery of an enveloped cursor secondmate works on the remote route only, since the local liveness sweep does not act on a cursor endpoint.
A relaunch that needs a fresh attestation takes the grant on the verb itself: `../../../bin/fm-control.sh <id> relaunch --cursor-exemption attended`.
Without that flag the spawn is refused, so route ordinary unattended scouting to Codex or Claude instead.

## Primary integration

Expand Down
5 changes: 2 additions & 3 deletions .agents/skills/harness-adapters/references/harness/muse.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Muse Code

Verified 2026-08-05 on Muse Code 0.1.0-R708.1, build sha 427a430436.
The router owns Muse's task-kind boundary.

## Operating facts

| Fact | Value |
|---|---|
| Task kinds | Crewmate and scout ONLY, never a secondmate or primary. `../../../bin/fm-spawn.sh` refuses a `--secondmate` launch, and `fm_control_harness_supports_kind` in `../../../bin/fm-control-lib.sh` owns the rule for the launch owner and the control plane, so an incompatible relaunch is refused before the running agent is stopped. Muse has no primary integration at all: the plugin engine (its only hook surface) is disabled in the default build, the Claude-compatible hook dialect names `asyncRewake` and model reawakening as explicitly unsupported - exactly what a primary's turn-end supervision needs - and no supervision protocol exists under `../../../docs/supervision-protocols/`, so a primary detected as muse falls back to the `unknown` protocol. |
| Binary | Absolute `muse` from `PATH`, refused if absent; launcher `~/.local/bin/muse` execs versioned `muse-bin-<version>`, so live process name changes on update. |
| Launch | Positional instructions, like Grok or Pi. |
| Models | `--model <model>`; only provider `meta`. |
Expand Down Expand Up @@ -62,9 +62,8 @@ Native children use per-child worktrees only with opt-in `--subagent-worktree-is
It excludes `.claude/settings.local.json` because Firstmate writes it, but Muse scratch is worker output and must refuse cleanup when uncommitted.
Inspect, never force past, that refusal.

## Maturity and primary limit
## Maturity

Muse 0.1.0 is day-zero beta; its hourly channel poll can replace the binary and process name.
The captain accepted this, so Firstmate does not set `MUSE_NO_AUTO_UPDATE=1`; a fleet may set it without adapter change.
Plugins report unavailable unless `MUSE_EXPERIMENTAL_PLUGINS=on`, so busy state uses logs.
The compatibility dialect explicitly lacks `asyncRewake` and model reawakening; the router owns the resulting primary boundary.
Loading