Skip to content

feat(bin): run crew launches under each harness's own controls and gate cursor on unattended work - #3507

Open
npayette84 wants to merge 26 commits into
kunchenguid:mainfrom
npayette84:fm/fm-harness-kind-rule-owner-consolidation
Open

feat(bin): run crew launches under each harness's own controls and gate cursor on unattended work#3507
npayette84 wants to merge 26 commits into
kunchenguid:mainfrom
npayette84:fm/fm-harness-kind-rule-owner-consolidation

Conversation

@npayette84

Copy link
Copy Markdown

Intent

Consolidate Cursor and Muse worker-kind restriction ownership in firstmate's shared tracked material - the bounded follow-up deliberately excluded from PR 3384. The harness-adapters router skill stated the Muse kind restriction inline while the broader Cursor unattended-worker rule lived in a harness reference and AGENTS.md; pick one authoritative placement for comparable restriction contracts using the one-owner rule and replace duplicate statements with concise trigger/pointer text. Preserve every existing safety boundary, adapter verification fact, runtime distinction, and trigger. Update deterministic tests and documentation-audience ownership where needed, and do not broaden into unrelated harness restructuring. Accepted placement: each harness's reference page owns its task-kind boundary (as Kimi's primary limit already did), with enforcement owned by fm_control_harness_supports_kind in bin/fm-control-lib.sh; the compressed AGENTS.md section 4 keeps the bar, the two cursor-exemption grants, the route-away directive, and ownership pointers, with its unique grant facts absorbed into references/harness/cursor.md. The branch is stacked on PR 3384's head 995a555 (origin/fm/harden-crew-launch-sandbox) because the contracts it consolidates were introduced there.

What Changed

  • Crew launches now use each harness's native autonomy controls instead of blanket bypass flags: bin/fm-spawn.sh launches Claude with --permission-mode auto plus CLAUDE_CODE_DISABLE_FAST_MODE=1, Codex with -s workspace-write -a never and an explicit sandbox_workspace_write.network_access=true grant, and Cursor with --auto-review --sandbox enabled in place of --yolo/--force.
  • Cursor is refused for ship, scout, and secondmate launches unless the invocation passes --cursor-exemption attended or --cursor-exemption envelope:<name>. The grant is validated per invocation, recorded as cursor_exemption= in the task meta, refused outright on a non-cursor harness, and inherited across a relaunch or --secondmate respawn only in the envelope: form; bin/fm-control.sh relaunch accepts the flag and evaluates the effective grant before it stops the running agent. bin/fm-remote-secondmate-control.sh carries the envelope grant over the wire and refuses attended, and bin/fm-bootstrap.sh reports a schema-valid crew-dispatch file naming cursor as a separate CREW_DISPATCH: advisory rather than as invalid.
  • Kind and grant admissibility moved behind fm_control_harness_supports_kind and its helpers in bin/fm-control-lib.sh, so one predicate answers for both the launch owner and the control plane. Each harness reference under .agents/skills/harness-adapters/references/harness/ now owns its own task-kind boundary (Muse's crewmate/scout limit moved out of the router skill, cursor's grant mechanics into cursor.md), the compressed AGENTS.md section keeps the bar and points at the owners, and the test suites for spawn dispatch, control relaunch, bootstrap, secondmate harness, and the remote trace-context route were extended to cover the new refusals and inheritance rules.

Risk Assessment

✅ Low: Documentation-only consolidation with no executable change; every ownership claim, pointer target, and preserved fact was verified against bin/fm-control-lib.sh, bin/fm-spawn.sh, bin/fm-control.sh, and the named docs, and no fact or safety boundary was lost.

Testing

I ran the six targeted suites that own the contracts this consolidation points at — fm-control, fm-control-relaunch, fm-harness-adapter-references, fm-documentation-audiences, fm-cursor-harness and fm-secondmate-harness — and all passed, then went past unit-level confirmation and drove the real operator CLIs to capture two transcripts: eleven fm-spawn.sh and fm-control.sh invocations showing muse refused as a secondmate but allowed as a scout, cursor refused for unattended ship/scout/secondmate, both exemption grants accepted and recorded in task meta while an ambient exported variable and an unnamed envelope are not, a grant on a non-cursor harness refused rather than recorded, and both refusals landing while the live pane process is still the original agent, which is the pre-stop guarantee AGENTS.md now delegates to docs/agent-control.md. There is no UI surface here — the change is Markdown that firstmate reads plus the CLI refusals it governs — so the reviewer-visible artifacts are CLI transcripts rather than screenshots. One suite, fm-muse-harness, cannot complete on this machine because macOS kills a copied /bin/bash; that is a host limitation unrelated to a documentation-only change, and the muse boundary it would have covered is demonstrated in the transcript instead.

Evidence: Worker-kind boundary — end-user CLI transcript (bin/fm-spawn.sh)

Source: Worker-kind boundary — end-user CLI transcript (bin/fm-spawn.sh)

=== [2] muse secondmate - forbidden kind === $ bin/fm-spawn.sh muse-secondmate-e2 <home> --harness muse --secondmate error: muse is a verified crewmate/scout adapter only and cannot run a secondmate; it has no primary supervision protocol. Select a harness verified for secondmates. [exit status: 1] [harness process launched: no] === [4] cursor scout with CURSOR_EXEMPTION/FM_CURSOR_EXEMPTION exported - grant is never ambient === $ bin/fm-spawn.sh cursor-scout-e4 <project> --scout --harness cursor --model cursor-grok-4.5-high error: cursor is a verified adapter but is refused for an unattended scout launch: ... pass it on the invocation itself with --cursor-exemption attended or --cursor-exemption envelope:<name> ... [exit status: 1] [harness process launched: no] === [5] cursor scout with --cursor-exemption attended - granted === spawned cursor-scout-e5 harness=cursor kind=scout cursor_exemption=attended window=firstmate:fm-cursor-scout-e5 ... [exit status: 0] [recorded task meta] harness=cursor kind=scout cursor_exemption=attended === [8] explicit grant on a non-cursor harness - refused, not recorded === error: --cursor-exemption applies only to a cursor launch, but this spawn resolved harness=claude; drop the flag rather than recording a cursor grant that would outlive it [exit status: 1]

Firstmate worker-kind restriction contract - end-user CLI transcript
repo: /Users/npayette/.no-mistakes/worktrees/337060f4dfd2/01M1GD6X8E151GWZ7D8E685Y49
commit: 4685f73
Every spawn below runs against a fake tmux pane and stub harness binaries,
so the transcript shows exactly the refusal/acceptance an operator would see.

--------------------------------------------------------------------
A. Muse task-kind boundary (owned by references/harness/muse.md)
--------------------------------------------------------------------

=== [1] muse scout - allowed kind ===
$ bin/fm-spawn.sh muse-scout-e1 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/muse-scout/project --scout --harness muse
  spawned muse-scout-e1 harness=muse kind=scout window=firstmate:fm-muse-scout-e1 worktree=/private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/muse-scout/wt
  [exit status: 0]
  [harness process launched: yes]
  [recorded task meta] harness=muse kind=scout 

=== [2] muse secondmate - forbidden kind ===
$ bin/fm-spawn.sh muse-secondmate-e2 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/muse-sm/home --harness muse --secondmate
  error: muse is a verified crewmate/scout adapter only and cannot run a secondmate; it has no primary supervision protocol. Select a harness verified for secondmates.
  [exit status: 1]
  [harness process launched: no]

--------------------------------------------------------------------
B. Cursor unattended bar and per-invocation grant
   (owned by references/harness/cursor.md; AGENTS.md keeps bar + pointers)
--------------------------------------------------------------------

=== [3] cursor scout with no grant - the documented REFUSED example ===
$ bin/fm-spawn.sh cursor-scout-e3 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-bar/project --scout --harness cursor --model cursor-grok-4.5-high
  error: cursor is a verified adapter but is refused for an unattended scout launch: its --auto-review classifier prompts for calls it does not deem safe, the pane has no approver, and the parked pane keeps reading as busy. The bar applies however cursor was selected, INCLUDING when firstmate inherited it by detecting its own runtime, because silently substituting another tool would change which adapter runs the captain's work without saying so. If this home is running inside cursor and resolved it that way, set config/crew-harness to a verified adapter such as codex or claude, or add a crew-dispatch profile eligible for this kind; firstmate will not choose one for you. If a person is in the pane or a proven outer isolation envelope governs this worker, pass it on the invocation itself with --cursor-exemption attended or --cursor-exemption envelope:<name>, which both bin/fm-spawn.sh and bin/fm-control.sh's relaunch verb accept.
  [exit status: 1]
  [harness process launched: no]

(next step exports ambient variables that must NOT act as a grant)

=== [4] cursor scout with CURSOR_EXEMPTION/FM_CURSOR_EXEMPTION exported - grant is never ambient ===
$ bin/fm-spawn.sh cursor-scout-e4 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-ambient/project --scout --harness cursor --model cursor-grok-4.5-high
  error: cursor is a verified adapter but is refused for an unattended scout launch: its --auto-review classifier prompts for calls it does not deem safe, the pane has no approver, and the parked pane keeps reading as busy. The bar applies however cursor was selected, INCLUDING when firstmate inherited it by detecting its own runtime, because silently substituting another tool would change which adapter runs the captain's work without saying so. If this home is running inside cursor and resolved it that way, set config/crew-harness to a verified adapter such as codex or claude, or add a crew-dispatch profile eligible for this kind; firstmate will not choose one for you. If a person is in the pane or a proven outer isolation envelope governs this worker, pass it on the invocation itself with --cursor-exemption attended or --cursor-exemption envelope:<name>, which both bin/fm-spawn.sh and bin/fm-control.sh's relaunch verb accept.
  [exit status: 1]
  [harness process launched: no]

=== [5] cursor scout with --cursor-exemption attended - granted ===
$ bin/fm-spawn.sh cursor-scout-e5 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-attended/project --scout --harness cursor --model cursor-grok-4.5-high --cursor-exemption attended
  spawned cursor-scout-e5 harness=cursor kind=scout cursor_exemption=attended window=firstmate:fm-cursor-scout-e5 worktree=/private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-attended/wt
  [exit status: 0]
  [harness process launched: yes]
  [recorded task meta] harness=cursor kind=scout cursor_exemption=attended 

=== [6] cursor scout with --cursor-exemption envelope:routing-benchmark - granted ===
$ bin/fm-spawn.sh cursor-scout-e6 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-envelope/project --scout --harness cursor --model cursor-grok-4.5-high --cursor-exemption envelope:routing-benchmark
  spawned cursor-scout-e6 harness=cursor kind=scout cursor_exemption=envelope:routing-benchmark window=firstmate:fm-cursor-scout-e6 worktree=/private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-envelope/wt
  [exit status: 0]
  [harness process launched: yes]
  [recorded task meta] harness=cursor kind=scout cursor_exemption=envelope:routing-benchmark 

=== [7] cursor scout with an unnamed envelope grant - refused as unauditable ===
$ bin/fm-spawn.sh cursor-scout-e7 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/cursor-unnamed/project --scout --harness cursor --model cursor-grok-4.5-high --cursor-exemption envelope:
  error: --cursor-exemption must be 'attended' (a person is in the pane) or 'envelope:<name>' where <name> starts with a letter or digit and continues with letters, digits, '.', '_', or '-' (the named outer isolation envelope that governs this worker); 'envelope:' names neither, and a grant that is unnamed, free-form, or carrying a line break could neither be audited later nor written into the task record without displacing another recorded field
  [exit status: 1]
  [harness process launched: no]

=== [8] explicit grant on a non-cursor harness - refused, not recorded ===
$ bin/fm-spawn.sh claude-scout-e8 /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-kind-boundary-evidence.WQIYAN/grant-wrong-harness/project --scout --harness claude --cursor-exemption attended
  error: --cursor-exemption applies only to a cursor launch, but this spawn resolved harness=claude; drop the flag rather than recording a cursor grant that would outlive it
  [exit status: 1]
  [harness process launched: no]

=== transcript complete ===
Evidence: Control-plane pre-stop kind/grant check — end-user CLI transcript (bin/fm-control.sh relaunch)

Source: Control-plane pre-stop kind/grant check — end-user CLI transcript (bin/fm-control.sh relaunch)

=== [1] relaunch a claude secondmate onto muse (crewmate/scout-only adapter) === [before] live pane process: claude | recorded harness: claude $ bin/fm-control.sh sm-e1 relaunch --harness muse error: muse is a verified crewmate/scout adapter only and cannot run a secondmate; it has no primary supervision protocol. ... Relaunching sm-e1 onto it would stop the running agent for a launch that must be refused. [exit status: 1] [after] live pane process: claude | recorded harness: claude === [2] relaunch a ship task onto cursor with no grant === [before] live pane process: claude | recorded harness: claude error: cursor is a verified adapter but is refused for an unattended ship launch ... Relaunching t-e2 onto it would stop the running agent for a launch that must be refused. [exit status: 1] [after] live pane process: claude | recorded harness: claude === [3] relaunch the same ship task onto cursor WITH --cursor-exemption attended === relaunched t-e3 harness=cursor from=claude model=cursor-grok-4.5-high effort=default backend=tmux endpoint=fmses:fm-t-e3 ... [exit status: 0] [after] live pane process: cursor-agent | recorded harness: cursor

Firstmate control-plane pre-stop kind/grant check - end-user CLI transcript
repo: /Users/npayette/.no-mistakes/worktrees/337060f4dfd2/01M1GD6X8E151GWZ7D8E685Y49
commit: 4685f73
The tmux stub models the agent lifecycle: the live pane process becomes
"zsh" the moment the running agent is stopped, so "live pane process:
claude" after a refusal proves the refusal landed BEFORE the stop.

=== [1] relaunch a claude secondmate onto muse (crewmate/scout-only adapter) ===
  [before] live pane process: claude | recorded harness: claude
$ bin/fm-control.sh sm-e1 relaunch --harness muse
  error: muse is a verified crewmate/scout adapter only and cannot run a secondmate; it has no primary supervision protocol. Select a harness verified for secondmates. Relaunching sm-e1 onto it would stop the running agent for a launch that must be refused.
  [exit status: 1]
  [after]  live pane process: claude | recorded harness: claude

=== [2] relaunch a ship task onto cursor with no grant ===
  [before] live pane process: claude | recorded harness: claude
$ bin/fm-control.sh t-e2 relaunch --harness cursor --model cursor-grok-4.5-high
  error: cursor is a verified adapter but is refused for an unattended ship launch: its --auto-review classifier prompts for calls it does not deem safe, the pane has no approver, and the parked pane keeps reading as busy. The bar applies however cursor was selected, INCLUDING when firstmate inherited it by detecting its own runtime, because silently substituting another tool would change which adapter runs the captain's work without saying so. If this home is running inside cursor and resolved it that way, set config/crew-harness to a verified adapter such as codex or claude, or add a crew-dispatch profile eligible for this kind; firstmate will not choose one for you. If a person is in the pane or a proven outer isolation envelope governs this worker, pass it on the invocation itself with --cursor-exemption attended or --cursor-exemption envelope:<name>, which both bin/fm-spawn.sh and bin/fm-control.sh's relaunch verb accept. Relaunching t-e2 onto it would stop the running agent for a launch that must be refused.
  [exit status: 1]
  [after]  live pane process: claude | recorded harness: claude

=== [3] relaunch the same ship task onto cursor WITH --cursor-exemption attended ===
  [before] live pane process: claude | recorded harness: claude
$ bin/fm-control.sh t-e3 relaunch --harness cursor --model cursor-grok-4.5-high --cursor-exemption attended --note captain took the pane; continue the audit task
  warning: /private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-relaunch-prestop-evidence.N7tCuf/cursorgrant/home/data/t-e3/brief.md records no delivery contract line (scaffolded before ship briefs recorded one); launching on the explicit --mode no-mistakes - confirm its definition of done matches
  relaunched t-e3 harness=cursor from=claude model=cursor-grok-4.5-high effort=default backend=tmux endpoint=fmses:fm-t-e3 worktree=/private/var/folders/70/p814fs691f103nxddhx58mhh0000gn/T/fm-relaunch-prestop-evidence.N7tCuf/cursorgrant/wt
  [exit status: 0]
  [after]  live pane process: cursor-agent | recorded harness: cursor

=== transcript complete ===
- Outcome: ⚠️ 1 info across 1 run (17m0s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed (2) ✅
  • ℹ️ AGENTS.md:200 - The compressed line says cursor "stays available only through the per-spawn --cursor-exemption attended or --cursor-exemption envelope:&lt;name&gt; grant". The word "only" is stronger than the implemented behavior: an envelope:&lt;name&gt; grant is inherited from the task's own record on the two restart paths, so firstmate's own secondmate liveness recovery re-runs fm-spawn.sh &lt;id&gt; --secondmate with no flag and succeeds (bin/fm-spawn.sh:1500 and the remote branch at bin/fm-spawn.sh:527, exercised by tests/fm-remote-secondmate-trace-context.test.sh's "recovery: an unflagged respawn inherits the recorded envelope grant"). The removed block stated the inheritance rule explicitly. An agent reading only AGENTS.md would conclude an unflagged enveloped respawn must be refused. Mitigated by the next line pointing at the harness reference for inheritance, and the intent explicitly scopes this block to "the bar, the two cursor-exemption grants, the route-away directive, and ownership pointers" - so this is flagged rather than changed.
  • ℹ️ AGENTS.md:201 - The pointer claims cursor's "grant mechanics, inheritance, and audit rules" are owned by "its harness reference in harness-adapters". Two facts carried by the block this line replaced are not in references/harness/cursor.md: that a LOCAL cursor secondmate is never auto-recovered and is reported as unverified-harness (only docs/configuration.md:313 - cursor.md:73 states the remote-only half but not the local reporting/remedy), and that the pre-stop check is keyed on the effective grant rather than the raw cursor_exemption= record (only docs/agent-control.md:98). No fact was lost from the repository, but a reader following this pointer will not find them where it says they live.

🔧 Fix: scope cursor grant to fresh launches, name distributed owners
3 issues (1 warning, 2 infos) still open:

  • ⚠️ .agents/skills/harness-adapters/references/harness/cursor.md:68 - The line absorbed from AGENTS.md drops a scoping word and becomes self-contradicting: "neither an exported variable nor an earlier launch can exempt a later unattended spawn." Line 72 of the same file states the opposite for envelope grants - "Across a relaunch or a --secondmate respawn ... an envelope:&lt;name&gt; grant is inherited" - and a --secondmate respawn IS a later unattended spawn exempted by an earlier launch's record (bin/fm-spawn.sh:1506-1509 and the remote branch at bin/fm-spawn.sh:528-530). The AGENTS.md text this replaced was precise: "one ATTENDED launch cannot silently exempt a later unattended spawn", and docs/configuration.md:305 scopes it the same way ("cannot leak to a later spawn IN THE SAME SHELL"). As written, the reference that is now the one owner of the grant contract contradicts its own inheritance rule four lines down. Fix: restore the scoping, e.g. "neither an exported variable nor an earlier ATTENDED launch can exempt a later unattended spawn". The exported-variable half is accurate - bin/fm-spawn.sh:323 unconditionally clears CURSOR_EXEMPTION before parsing.
  • ℹ️ AGENTS.md:201 - The sentence widens what fm_control_harness_supports_kind enforces beyond what it does: "Each harness's complete task-kind boundary, including cursor's grant mechanics, restart inheritance, and audit rules, is owned by its harness reference ..., with fm_control_harness_supports_kind ... enforcing IT on every spawn and before a relaunch stops the running agent." The referent of "it" is that whole list, but bin/fm-control-lib.sh:127-136 only answers kind-plus-grant admissibility. Restart inheritance is owned by a different function, fm_control_cursor_exemption_inherited (bin/fm-control-lib.sh:194), applied by bin/fm-spawn.sh:1506; the audit record is written by bin/fm-spawn.sh:747/3045. The refusal of an explicitly passed grant on a non-cursor harness is also a sibling rule inside fm_control_launch_refusal (bin/fm-control-lib.sh:298-301), not inside supports_kind. The pre-existing pointers got this right by keeping the object narrow - docs/configuration.md:315 and cursor.md:20 both say it owns "that rule" (the kind rule) only. Since the whole point of this change is accurate one-owner attribution, consider narrowing "it" to the kind boundary, or naming fm_control_launch_refusal as the composer both spawn routes and the relaunch actually call.
  • ℹ️ AGENTS.md:202 - The fix round's new third sentence does not just name the owners, it restates both facts in full: "a local cursor secondmate never being auto-recovered, reported instead as unverified-harness and brought back only by an explicit relaunch" is docs/configuration.md:313 restated, and "the pre-stop relaunch check being keyed on the grant that will really be in force rather than on the recorded cursor_exemption= value" is docs/agent-control.md:98 restated. That re-creates in AGENTS.md the duplication this change exists to remove, and it partly reinstates two of the eight lines the consolidation deleted. The prompting instruction asked only that the two facts be "findable where they live", which a bare pointer satisfies - e.g. "the harness-support section of docs/configuration.md owns local cursor secondmate recovery, and docs/agent-control.md owns what the pre-stop relaunch check is keyed on." The pointers themselves are accurate: I confirmed line 313 sits under the ## Harness support heading (line 293) and that agent-control.md:98 states exactly the effective-grant keying.

🔧 Fix: scope never-ambient rule to attended, narrow ownership pointers
✅ Re-checked - no issues remain.

⚠️ **Test** - 1 info
  • ℹ️ tests/fm-muse-harness.test.sh:176 - tests/fm-muse-harness.test.sh cannot run to completion on this machine: its first case (test_detects_versioned_process_ancestor) copies /bin/bash to muse-bin-0.1.0-R708.1 and executes it, but macOS SIGKILLs the copy because /bin/bash is an Apple platform binary whose code signature is invalid at a new path (reproduced standalone: exit 137). No non-Apple bash is installed to substitute. This is a host limitation, not a product failure, and is unrelated to this documentation-only change (bin/ and tests/ are untouched by it). The muse secondmate refusal that this change's doc consolidation depends on was instead exercised directly through the fm-spawn.sh CLI and via tests/fm-control.test.sh; remote CI owns the detection coverage.
  • bin/fm-test-run.sh tests/fm-control.test.sh — the one-owner predicate: per-kind capability, muse secondmate refusal, cursor unattended bar and grant token validation (passed)
  • bin/fm-test-run.sh tests/fm-control-relaunch.test.sh — 58 assertions covering the pre-stop refusal invariant, attended-vs-envelope grant inheritance, and grant refusal on a non-cursor target (passed)
  • bin/fm-test-run.sh tests/fm-harness-adapter-references.test.sh — the harness-adapter-routing-v1 artifact is still a normalized map and every reference target resolves after the SKILL.md edit (passed)
  • bin/fm-test-run.sh tests/fm-documentation-audiences.test.sh — documentation-audience classification and "required documentation owner pointers cannot silently disappear" (passed)
  • bin/fm-test-run.sh tests/fm-cursor-harness.test.sh (passed)
  • bin/fm-test-run.sh tests/fm-secondmate-harness.test.sh — includes the attended/unattended cursor secondmate launch contract (passed)
  • bin/fm-test-run.sh tests/fm-muse-harness.test.sh — FAILS on this host only, at the copied-/bin/bash process-ancestry detection case (see finding)
  • Manual CLI evidence run: 8 real bin/fm-spawn.sh invocations (muse scout, muse --secondmate, cursor scout bare / with ambient env vars / --cursor-exemption attended / envelope:routing-benchmark / envelope: / grant on --harness claude) against a fake tmux pane, recording exit status, whether a harness process was launched, and the resulting task meta
  • Manual CLI evidence run: 3 real bin/fm-control.sh &lt;id&gt; relaunch invocations (secondmate onto muse, ship onto cursor bare, ship onto cursor with --cursor-exemption attended) against a lifecycle-modelling tmux stub, recording the live pane process and recorded harness before and after each call
  • grep -n verification that the AGENTS.md ownership pointers resolve to real sections in docs/configuration.md and docs/agent-control.md, and that references/harness/kimi.md still states its own primary limit
⚠️ **Document** - 1 info
  • ℹ️ docs/configuration.md:304 - Ownership contradiction left by the consolidation, worth a follow-up rather than a broader restructuring here. AGENTS.md:201 now declares that each harness reference owns "cursor's grant mechanics, restart inheritance, and audit rules", but docs/configuration.md's "Harness support" section (lines 304-311) still carries a full parallel account of exactly those facts (per-invocation grant, cursor_exemption= recording, envelope charset, non-cursor refusal vs. inherited drop, envelope-vs-attended inheritance), and docs/verification/trace-context.md:22 points back at that section as the owner of "the rule". Nothing is currently wrong, but three surfaces now restate one contract, so the next behavior change has to be applied in all three or one goes stale. Follow-up: decide whether configuration.md's operator-current copy is reduced to the bar plus a pointer to references/harness/cursor.md (keeping only the local-vs-remote recovery asymmetry AGENTS.md assigns to it), and retarget the trace-context.md owner pointer accordingly. Left alone here because the intent explicitly scopes this change to AGENTS.md, the router skill, and the harness references, and forbids broadening into unrelated harness restructuring.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

npayette84 and others added 25 commits September 2, 2026 02:34
Launch Claude with --permission-mode auto, Codex with -s workspace-write
-a never, and Cursor with --auto-review --sandbox enabled, instead of the
three full-bypass flags (--dangerously-skip-permissions,
--dangerously-bypass-approvals-and-sandbox, --yolo). A crewmate now runs
under its harness's own approval, review, and sandbox controls rather than
with them switched off.

Codex's workspace-write confines writes to the task worktree plus /tmp and
$TMPDIR. That is the intended blast radius, but it also denies the
supervision paths a crewmate's contract needs outside its worktree.
Granting those back narrowly is a separate, independently reviewable
change and is deliberately not bundled here.

Refreshes the launch expectations in the three suites that assert the
composed command, and the Cursor adapter reference rows. Other tracked
uses of the bypass flags are one-off CLI invocations in guard docs and
live probes, not spawn output, and are left untouched.
Supersedes an aborted fix round that would have made an auto-detected
cursor silently fall back to another adapter. Silently substituting a
different tool changes which adapter runs the captain's work without
saying so, which is harder to notice than a refusal.

The bar now holds however cursor was selected, explicit or inherited, and
the refusal names the exact remedy: set config/crew-harness to a verified
adapter, or add an eligible crew-dispatch profile. Firstmate does not pick
one on the captain's behalf.

The two exemption grants are no longer interchangeable across relaunch.
envelope:<name> describes a mechanically proven outer isolation envelope
that still governs the replacement agent, so it is inherited and automatic
recovery keeps working. `attended` asserts a person is in the pane right
now; the captain who attested may have left long before stuck-worker
recovery relaunches, so inheriting it would let one attestation authorize
unlimited unattended launches. It is never inherited.

A cursor exemption is refused outright on a non-cursor harness rather than
recorded, so no stale grant can sit in a task's metadata waiting to
authorize a later relaunch onto cursor. Remote secondmate launches forward
only an envelope grant, through self-describing arguments whose
compatibility degradation is stated in the code: an older host misbinds the
token and fails validation there, and a cursor secondmate reaching fm-spawn
without a grant is refused by the bar. Both paths fail closed. An attended
grant cannot describe a worker on another host and is refused for a remote
launch.

Bootstrap now diagnoses a cursor crew-dispatch rule instead of validating
clean and failing later at spawn, since those rules resolve the harness for
crewmate and scout spawns and both are barred.

Also adds a contains mode to the bootstrap row runner with a guard that
fails on an unknown mode; the previous case statement let an unrecognized
mode pass vacuously.
…erences

Each harness reference now owns its task-kind boundary, matching the pattern
Kimi's primary limit already used. Muse's restriction moves from the router's
Non-negotiable safety section into a Task kinds row in the Muse reference, with
the rationale that was split across the router and the maturity section, and
AGENTS.md section 4 compresses the cursor unattended-bar block to the trigger,
the two grants, and the ownership pointer. The grant mechanics the compressed
block carried - never-ambient grants and the local-and-remote refusal scope -
land in the Cursor reference, which already owned the rest. Dispatch's owner
list now names fm_control_harness_supports_kind as the one owner of task-kind
compatibility instead of attributing it to fm-spawn.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T07:56:18.961883Z d558b8e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported remote exemption metadata divergence is corrected by persisting the exemption reported by the live endpoint.

Reviews (2): Last reviewed commit: "no-mistakes: apply CI fixes" | Re-trigger Greptile

Comment thread bin/fm-spawn.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d558b8e3ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/fm-spawn.sh
printf '%s' 'codex __MODELFLAG____EFFORTFLAG__-s workspace-write -a never -c sandbox_workspace_write.network_access=true "$(__OPINPUT__ encode launch-brief < __BRIEF__)"'
else
printf '%s' 'codex __MODELFLAG____EFFORTFLAG__--dangerously-bypass-approvals-and-sandbox -c "notify=[\"bash\",\"-c\",\"touch __TURNEND__\"]" "$(__OPINPUT__ encode launch-brief < __BRIEF__)"'
printf '%s' 'codex __MODELFLAG____EFFORTFLAG__-s workspace-write -a never -c sandbox_workspace_write.network_access=true -c "notify=[\"bash\",\"-c\",\"touch __TURNEND__\"]" "$(__OPINPUT__ encode launch-brief < __BRIEF__)"'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore writable supervisor paths for Codex workers

Captain, for every Codex ship or scout, this template selects workspace-write, while the preceding comment acknowledges that this denies supervision paths outside the task worktree. Generated briefs require writes to $FM_HOME/state/<id>.status, inbox acknowledgement directories, and—for scouts—$FM_HOME/data/<id>/report.md, all outside that worktree. Consequently Codex workers cannot acknowledge steering or publish blocker, completion, or report artifacts, so they can appear permanently silent even when their work ran; grant those paths explicitly or move the durable channels into a writable root.

AGENTS.md reference: AGENTS.md:L519-L520

Useful? React with 👍 / 👎.

Comment thread bin/fm-spawn.sh Outdated
echo "kind=secondmate"
echo "mode=secondmate"
echo "yolo=off"
[ -z "$CURSOR_EXEMPTION" ] || echo "cursor_exemption=$CURSOR_EXEMPTION"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record the actual grant on reused remote endpoints

When an already-alive remote Cursor secondmate is retried with a new envelope grant, the remote cmd_launch returns its existing route without applying the requested grant, and print_route does not report the endpoint's recorded exemption; this line nevertheless publishes the caller's new value into the parent metadata. The parent can therefore claim that an old endpoint—particularly one created before this change—runs under an exemption it never received, and later audits or recovery inherit that false safety posture. Return and record the remote endpoint's actual cursor_exemption, or refuse reuse when it differs from the requested grant.

AGENTS.md reference: AGENTS.md:L200-L201

Useful? React with 👍 / 👎.

Comment thread bin/fm-spawn.sh
# spanning several modes is two invocations rather than a silent mixed dispatch.
[ "$MODE_SET" -eq 0 ] || shared_args+=(--mode "$MODE")
[ "$YOLO_SET" -eq 0 ] || shared_args+=(--yolo "$YOLO")
[ "$CURSOR_EXEMPTION_SET" -eq 0 ] || shared_args+=(--cursor-exemption "$CURSOR_EXEMPTION")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject attended exemptions in batch dispatch

When a batch contains multiple tasks, this line forwards one --cursor-exemption attended token to every child invocation. The token asserts that a person is present in that specific worker pane, but each child creates a separate concurrently live pane and batch dispatch never places the operator in those panes. A single assertion therefore lets every Cursor worker past the unattended bar, leaving classifier prompts in unwatched panes parked indefinitely; reject attended for batch mode or require individual invocations, while continuing to allow a shared durable envelope grant.

AGENTS.md reference: AGENTS.md:L200-L201

Useful? React with 👍 / 👎.

Comment thread bin/fm-control-lib.sh
Comment on lines +302 to +303
if fm_control_harness_family "$harness" >/dev/null 2>&1 &&
! fm_control_harness_supports_kind "$harness" "$kind" "$grant"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detect Cursor behind raw-command wrappers

For a supported raw command such as env -u CLAUDECODE cursor-agent ..., the raw-command parser records the first non-assignment word (env) as the harness. This new conditional then fails to map that wrapper to a known family and skips the kind check entirely, even though the pane subsequently executes Cursor; command, exec, and nice wrappers have the same result. Such launches bypass the unattended grant requirement and also omit Cursor-specific tracking, so resolve past standard wrappers or refuse wrapped commands that execute a verified restricted adapter.

AGENTS.md reference: AGENTS.md:L200-L201

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant