Skip to content

fix: harden worktree cleanup, relaunch, and isolation checks - #11

Open
cisrd wants to merge 11 commits into
mainfrom
fm/fm-lot-cycle-vie-securite
Open

cisrd wants to merge 11 commits into
mainfrom
fm/fm-lot-cycle-vie-securite

Conversation

@cisrd

@cisrd cisrd commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Intent

Le capitaine demande d enchaîner les tâches restantes en les regroupant en lots cohérents plutôt que de produire des dizaines de petites PR. Il autorise maintenant deux ou trois ouvriers supplémentaires, avec un maximum de deux sessions Grok, tout en surveillant la charge de la machine.

Ce lot regroupe quatre défauts déjà mesurés du cycle de vie Firstmate :

  • le nettoyage doit refuser une copie de travail encore revendiquée par un autre ouvrier vivant ;
  • sans lsof, les processus restants doivent tout de même être identifiés et récoltés sans obliger chaque nettoyage à échouer une première fois ;
  • une relance doit vérifier le répertoire réellement occupé avant d arrêter l ancien agent, au lieu de faire confiance au répertoire de lancement rapporté par Herdr ;
  • un projet fourni comme . ne doit pas produire une fausse assertion d isolation ni faire refuser une copie treehouse parfaitement isolée.

Ce brief est en français, ta livraison ne l est pas.

Ajout du capitaine pendant l exécution : « il reste 97% sur grok si ca coupe tu changes switch ». Cette autorisation vise les ouvriers Grok actuellement lancés : si Grok interrompt réellement cette tâche, Firstmate la relancera sur GPT-5.6 Sol en effort élevé sans redemander, dans la même copie et sans perdre le travail.

What Changed

  • Extend cleanup exclusivity checks to all ship/scout worktrees and forced descendant teardown; add /proc process discovery when lsof is absent and protect teardown's invocation chain.
  • Verify the live occupied directory before stopping an agent for relaunch, refusing unverifiable or mismatched paths.
  • Resolve project paths physically and render exact isolation paths in launch briefs, correcting . handling without rebinding secondmate homes.

Risk Assessment

✅ Low: The lifecycle changes are bounded, preserve fail-closed cleanup and relaunch behavior, and introduce no substantiated material defects beyond previously recorded decisions.

Testing

Baseline inspection, targeted CLI regressions, and real Herdr verification passed. An initial socket-path setup failure was fixed and retried successfully. Captured CLI transcripts and the generated launch contract; temporary resources were cleaned up.

Evidence: Lifecycle CLI behavior

Source: Lifecycle CLI behavior

# Lifecycle CLI evidence

Commands ran against disposable git repositories and isolated Firstmate homes. Session-provider fixtures were used except for real-herdr-occupancy.txt. Process-reaping and shared-copy tests used real sleep processes; lsof-present tests used protocol fixtures because lsof is not installed. Watcher warnings in fixture output are expected: these temporary homes intentionally have no supervisor.

# fm-teardown-endpoint-safety

## fm-teardown: a pool slot named by a second task record is never returned, killed, or reset


## fm-teardown: a shared ordinary worktree is refused before any process is signalled


## fm-teardown: a pool slot held by another firstmate home is never returned


## fm-teardown: a task that solely holds its slot still returns it


## fm-teardown: an exact recorded endpoint still tears down after changing cwd outside its worktree


## fm-teardown: a pool slot named by a second task record is never returned, killed, or reset

●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  2 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REFUSED: task stale-task's recorded worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/slot-reuse-home/pool/1/project is also task live-task's recorded worktree.
Returning that copy would kill live-task's processes and reset its work, so nothing was changed - not even with --force.
Reconcile whichever record is wrong (bin/fm-crew-state.sh stale-task; bin/fm-crew-state.sh live-task), then re-run teardown.

## fm-teardown: a shared ordinary worktree is refused before any process is signalled

●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  2 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REFUSED: task stale-task's recorded worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/non-pool-shared/worktree is also task live-task's recorded worktree.
Returning that copy would kill live-task's processes and reset its work, so nothing was changed - not even with --force.
Reconcile whichever record is wrong (bin/fm-crew-state.sh stale-task; bin/fm-crew-state.sh live-task), then re-run teardown.

## fm-teardown: a pool slot held by another firstmate home is never returned

●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REFUSED: task stale-task's recorded worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/slot-reuse-cross-home/pool/1/project is also task secondmate-task's recorded worktree.
Returning that copy would kill secondmate-task's processes and reset its work, so nothing was changed - not even with --force.
Reconcile whichever record is wrong (bin/fm-crew-state.sh stale-task; bin/fm-crew-state.sh secondmate-task), then re-run teardown.

## fm-teardown: a task that solely holds its slot still returns it

teardown sole-task complete (window firstmate:fm-sole-task, worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/slot-sole/worktree)
Backlog: sole-task just finished (this home keeps no backlog at ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/slot-sole/home/data/backlog.md). Update ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-teardown-endpoint-safety.xH7BnY/slot-sole/home/data/backlog.md - move sole-task to Done, keep Done to the 10 most recent, then re-scan Queued and dispatch only work whose blockers are gone and date is due.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  2 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the guarded operation WILL still run.
●  repair a missing or failed watcher cycle with the Pi tool fm_watch_arm_pi, or restart Pi with -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-turnend-guard.ts -e ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.pi/extensions/fm-primary-pi-watch.ts if the extensions are not loaded.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

## fm-teardown: an exact recorded endpoint still tears down after changing cwd outside its worktree

teardown moved-task complete (window firstmate:fm-moved-task, worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQ

... [18033 bytes truncated] ...

point is in '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.O7fpk2/wrongcwd-3405/proj', not its recorded worktree '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.O7fpk2/wrongcwd-3405/wt'; refusing to relaunch an agent outside the copy holding its work

## fm-control relaunch: a same-harness relaunch replaces the agent in the same endpoint and worktree
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/same-11588/home/data/rl1/launch-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 rl1 harness=claude from=claude model=default effort=default backend=tmux endpoint=fmses:fm-rl1 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/same-11588/wt

## fm-control relaunch: switching harness is one ordinary relaunch, and the old wiring goes with the old agent
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/switch-27141/home/data/rl4/launch-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 rl4 harness=codex from=claude model=default effort=default backend=tmux endpoint=fmses:fm-rl4 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/switch-27141/wt

## fm-control relaunch: the progress note lands in the instructions the replacement reads
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/note-12188/home/data/rl2/launch-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 rl2 harness=claude from=claude model=default effort=default backend=tmux endpoint=fmses:fm-rl2 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-control-relaunch.uMOqPv/note-12188/wt

# fm-tangle-guard

## fm_git_primary_workdir: a linked worktree resolves to the primary checkout


## fm_primary_tangle_branch: feature branch alarms; default/detached/non-git stay silent


## fm-guard: bordered tangle banner fires only for a feature branch and suppresses repair commands in read-only mode
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WORKTREE TANGLE - PRIMARY CHECKOUT IS ON A FEATURE BRANCH
●  ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/guard-repo is on 'fm/tangle-aa1', not its default branch 'main'.
●  A crewmate likely branched/committed in the primary instead of its own worktree.
●  The work is SAFE on the 'fm/tangle-aa1' ref.
●  This read-only session must leave restore work to a session with verified fleet-lock ownership.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

## fm-bootstrap: TANGLE problem line fires only for a feature branch and suppresses repair commands in detect-only mode
TANGLE: primary checkout on feature branch 'fm/tangle-bb2' (expected 'main'); the work is safe on that ref - read-only session must leave restore work to the session holding the fleet lock

## fm-brief: ship brief asserts worktree isolation before the branch step


## fm-brief: a project of '.' labels the repository and leaves every path to the launch contract


## fm-spawn: aborts unless the resolved worktree is a genuine, isolated worktree
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-home/data/ok-isolated-ff6/launch-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
spawned ok-isolated-ff6 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-ok-isolated-ff6 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-wt

## fm-spawn: project '.' from a linked worktree keeps that copy as the project and accepts a genuine isolated worktree
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-dot-home/data/spawn-dot-ii9/launch-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
spawned spawn-dot-ii9 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-spawn-dot-ii9 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-dot-other

## fm-spawn: project '.' still refuses the repository primary checkout
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-dot-primary-home/data/spawn-dot-jj0/launch-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
error: treehouse get did not enter an isolated worktree within 60s (last seen '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-dot-primary-proj': it is the repository's primary checkout (its git dir is the spawning project's common git dir); spawning project '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-dot-primary-linked'); inspect window firstmate:fm-spawn-dot-jj0

## fm-spawn: the launch brief carries the exact worktree and primary paths, not a repo label
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-label-home/data/spawn-label-kk1/launch-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
spawned spawn-label-kk1 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-spawn-label-kk1 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-label-wt

## fm-spawn: a dot-scaffolded brief carries only the launching project's primary path
spawned dot-scaffold-mm3 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-dot-scaffold-mm3 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-wt

## fm-spawn: appends windows by session-colon, pins the name, and targets the window id
warning: ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-rec-home/data/rec-win-gg7/launch-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
spawned rec-win-gg7 harness=codex kind=ship mode=no-mistakes yolo=off window=firstmate:fm-rec-win-gg7 worktree=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/spawn-rec-wt
Evidence: Real Herdr preserves agent on cwd mismatch

Source: Real Herdr preserves agent on cwd mismatch

$ herdr pane get <fixture-pane> (launch cwd versus foreground cwd)
{"id":"cli:pane:get","result":{"pane":{"agent":"fixture","agent_status":"idle","cwd":"~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/other","focused":true,"foreground_cwd":"~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/other","pane_id":"w1:p1","revision":0,"scroll":{"max_offset_from_bottom":0,"offset_from_bottom":0,"viewport_rows":23},"tab_id":"w1:t1","terminal_id":"term_65afb7b3e97eb1","workspace_id":"w1"},"type":"pane_info"}}
$ fm-control.sh hsmoke relaunch --note "must not stop"
error: task hsmoke's live shell is in ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/other, not its recorded worktree ~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/wt; refusing to stop the agent
After refusal: agent=alive; task metadata byte-identical; recorded worktree preserved=yes
$ herdr pane get <fixture-pane> (after refusal)
{"id":"cli:pane:get","result":{"pane":{"agent":"fixture","agent_status":"idle","cwd":"~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/other","focused":true,"foreground_cwd":"~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/other","pane_id":"w1:p1","revision":0,"scroll":{"max_offset_from_bottom":0,"offset_from_bottom":0,"viewport_rows":23},"tab_id":"w1:t1","terminal_id":"term_65afb7b3e97eb1","workspace_id":"w1"},"type":"pane_info"}}
Evidence: Generated dot-project launch brief

Source: Generated dot-project launch brief

You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.

# Task
## Captain's intent
Ship the dot-scaffold fixture.

## Firstmate spec
Exercise the launch contract.

# Herdr lifecycle declaration - NOT ENABLED
**HARD SAFETY GATE:** this scaffold cannot inspect the task text filled in above.
If the task will start, stop, delete, restart, profile, or otherwise drive Herdr lifecycle behavior, stop and regenerate the brief with `--herdr-lab` before dispatch.
Do not add Herdr lifecycle commands to this unguarded brief by hand.

# Setup
You are in a disposable git worktree of dot-scaffold-repo, at a detached HEAD on a clean default branch.

**Verify isolation before anything else.** Run `pwd -P`. It must be exactly the path named in this brief's `# Worktree isolation` section, which firstmate renders at launch: your own disposable copy (a treehouse pool path, an Orca-managed worktree, or another isolated worktree), never the project's primary checkout.
Equality of `pwd` and `git rev-parse --show-toplevel` does not prove isolation: both name the current worktree root in the primary checkout and in a linked worktree alike. Compare the physical paths instead.
If `pwd -P` is not that exact worktree path, STOP - do not branch or commit here - append `blocked: launched in primary checkout, not an isolated worktree` to the status file and stop.

1. First action: create your branch: `git checkout -b fm/dot-scaffold-mm3`
2. Run `no-mistakes doctor`; if it reports the repo is not initialized here, run `no-mistakes init`.

# Rules
1. Never push to the default branch. Never merge a PR.
2. Stay inside this worktree; modify nothing outside it.
3. Use gh-axi for GitHub operations and chrome-devtools-axi for browser operations.
4. Report status by appending one line:
   `echo "{state}: {one short line}" >> '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/state/dot-scaffold-mm3.status'`
   States: working, needs-decision, blocked, paused, done, failed.
   Each append wakes firstmate, so report sparingly: only phase changes a supervisor
   would act on (setup done, bug reproduced, fix implemented, validation passed) and the
   needs-decision/blocked/paused/done/failed states. No step-by-step FYI progress lines;
   firstmate reads your pane for that.
   Whenever you mention a PR anywhere - a status line, your terminal, a summary - write its full
   https:// URL exactly as the forge printed it, never a bare number such as "PR 108"; firstmate
   copies that URL from your line rather than assembling one.
   A mid-task `working:` line (including setup complete) is nonterminal: do not end the
   turn after it; continue the same stage until a defined `done:` gate under Definition of done.
   Use `paused: {why}` - distinct from `blocked:` - ONLY when you are deliberately idling on a
   known external wait you expect to clear on its own (an upstream release, a rate-limit reset,
   a scheduled window): firstmate then leaves your idle pane alone and rechecks it on a long
   cadence instead of treating it as a possible wedge. Use `blocked:` when you are stuck and need help.
5. If you hit the same obstacle twice, append `blocked: {why}` and stop; firstmate will help.
6. If a decision belongs above the implementation worker (product choices, destructive actions),
   append `needs-decision: {summary of options}` and stop. Firstmate will reply with the decision.
   For a no-mistakes ask-user gate specifically, escalate all ask-user findings as one event plus one snapshot file, using that same shape even when the gate holds only a single ask-user finding: write only the ask-user findings, verbatim and unparaphrased (id, severity, file, line, description, authority), to `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/data/dot-scaffold-mm3/nm-<run>-findings.txt`, then report the gate with
   `needs-decision [key=nm-<run>-<step>]: ask-user findings=<id1>,<id2>,... file=~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/data/dot-scaffold-mm3/nm-<run>-findings.txt`
   naming every ask-user finding id from that gate. The status line only points at the file; it never restates or summarizes a finding's content.
   A decision or blocker you opened stays open until a `resolved` line carrying its exact key lands; a later `done:` or `working:` line never closes it, even when the answer is what started that work.
   Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append `resolved: {how it cleared}` yourself (same `[key=<slug>]` if you opened it with one) as you resume.
7. Never stop, restart, or update the shared `no-mistakes` daemon - it is one instance serving
   every lane/home, so restarting it kills other lanes' in-flight pipeline runs; only firstmate
   manages the daemon.
   Before you append `blocked:` about the pipeline, run `no-mistakes daemon status` and
   `no-mistakes axi status`. If the daemon socket refuses connections or is missing, append
   `blocked: {the daemon error}` and stop even when the local run record still says running or
   fixing, because that record can be stale after the daemon exits. A run record failed with a
   daemon error is also a real block.
   Only after ruling out socket refusal, if the run is still running or fixing, reattach and keep
   going. A drive-call error, timeout, slow read, or generic unreachability is NOT a daemon error:
   the daemon accepts `respond` immediately and runs the round in the background, so a killed or
   timed-out call was only waiting for a read while the run kept working.

# Firstmate instruction inbox
Firstmate steers you through durable message files in '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/state/dot-scaffold-mm3.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/state/dot-scaffold-mm3.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/state/dot-scaffold-mm3.inbox'/NNN.msg '~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-home/state/dot-scaffold-mm3.inbox'/handled/`.
The move IS the acknowledgement: without it firstmate rings again and eventually treats you as stuck. An empty or absent inbox needs no action.

# Project memory
If `AGENTS.md` or `CLAUDE.md` already exists, or if this task produced durable project-intrinsic knowledge, run `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/bin/fm-ensure-agents-md.sh .` in the worktree.
Record only project knowledge useful to almost every future session.
For anything the codebase already shows, prefer a pointer to the authoritative file, command, or doc over copying the detail.
If you touch a project `AGENTS.md`, follow `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/bin/fm-ensure-agents-md.sh`'s self-governance contract in the same pass.
Keep it proportionate: skip `AGENTS.md` edits for trivial tasks that produced no durable project knowledge.

# Definition of done
Delivery contract: mode=no-mistakes
The task is complete only when committed on your branch.
When you believe it is complete, append `done: {summary}` to the status file and stop.
Firstmate will then instruct you to run /no-mistakes to validate and ship a PR.

You drive no-mistakes by responding to its gates, not by implementing fixes.
Follow the guidance no-mistakes itself provides for the mechanics: it loads when you invoke /no-mistakes, and `no-mistakes axi run --help` plus the `help` lines in each `axi` response are authoritative and version-matched to the installed binary.
When starting no-mistakes, pass `--intent` as only this brief's `## Captain's intent` subsection plus any later words the captain actually said.
For a legacy brief with no such subsection, include only words explicitly labeled `Captain:`, `Captain's words:`, `Captain's ask:`, or `Captain's intent:`; never copy its mixed `# Task` wholesale. If it has no provenance-marked captain words, stop and ask firstmate instead of starting no-mistakes.
Do not include `## Firstmate spec`, later Firstmate build constraints, or your own decisions and tradeoffs.
The `--intent` string you pass must be self-sufficient: that string plus the codebase must let a reader reconstruct roughly the same specification, without depending on a separate report, a PR, or context that lives only in this conversation.
When the captain's intent refers to a report, decision, or PR ("do items 1, 2, 3, and 7 of the report"), write the substance of the referenced items into `--intent` in the captain's terms, not only the pointer; that substance is the captain's ask by reference, while Firstmate's build instructions and your own decisions still stay out.
This replaces the no-mistakes skill's advice to enrich `--intent` with decisions and tradeoffs; that advice does not apply to Firstmate-dispatched work.
Do not hand-edit, commit, or fix findings yourself while a run is active - the pipeline applies every fix.

One drive call blocks until the next gate or outcome, which routinely outlives what your harness lets a single command run: Claude Code kills a command at ten minutes maximum, while one fix round is capped around thirty minutes and up to three rounds chain.
So background the drive call and poll `no-mistakes axi status` from a separate call instead of sitting in one blocking hold your harness will kill.
Where a harness's own command limit is not established, assume it bounds commands and use that same background-and-poll shape.
A killed or timed-out call is never evidence the daemon died: the daemon accepts your response immediately and runs the round in the background, so the call was only ever waiting for a read while the run kept working.
Reattach and keep going rather than reporting the pipeline blocked; rule 7 owns the checks that decide when a pipeline block is real.

Two firstmate-specific rules layer on top of that guidance:
- ask-user findings are never yours to answer: escalate to firstmate using rule 6's ask-user format and stop.
  Firstmate applies `ask-user-authority` and obtains any required captain decision.
  When the decision comes back, feed it to the gate with `no-mistakes axi respond` and let the pipeline apply it - do not route the question to "the user" or implement the fix yourself.
- NEVER pass `--yes` (or `-y`) to `no-mistakes axi run` or `no-mistakes axi respond`. It is banned fleet-wide.
  It auto-resolves every gate including ask-user findings with no escalation, and answering your own ask-user finding is a hard rule violation.

After /no-mistakes reports CI green (the CI-ready return point - do not wait for it to keep monitoring in the background until merge), append `done: PR {url} checks green` and stop. You are finished.

# Current worker role contract
When this task works on Firstmate itself, this section supersedes every earlier brief instruction about your role and identity.
When this task works on Firstmate itself, the repository root `AGENTS.md` (also imported by `CLAUDE.md`) is the primary/secondmate supervisor's contract: follow this brief instead of that supervisor contract.
For that Firstmate task, do the assigned work yourself and report to firstmate; do not adopt the supervisor identity, delegate the task, run fleet supervision, or address the captain.
This exception preserves this brief's safety and authority boundaries and applicable contributor guidance, including `CONTRIBUTING.md` and `firstmate-coding-guidelines` for Firstmate changes.
Other projects retain their own instructions unchanged.

# Current no-mistakes intent contract
This section supersedes every earlier brief instruction about constructing `--intent`, but not later clarifications actually supplied by the captain.
Use the serialized captain intent below plus any later words the captain actually supplied as `--intent`; never include Firstmate specification or other mixed Task content.

## Captain intent authorized for --intent
Ship the dot-scaffold fixture.

Firstmate-authored constraints, acceptance criteria, implementation details, decisions, and tradeoffs are specification, not captain intent.
The Definition of done's rule that `--intent` must be self-sufficient still governs the string you pass: resolve any report, decision, or PR the intent above refers to into its substance rather than passing the pointer.

# Worktree isolation
Your task worktree is `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-wt`.
The project's primary checkout is `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-other`; it is never yours to work in.
Before anything else run `pwd -P`. If it is not exactly `~/.no-mistakes/worktrees/a03e7f5d4084/01M20Y4MQY0P971881N5Y09JGN/.local-test/tmp/fm-tangle-guard.i1YrIS/dot-scaffold-wt`, STOP - do not branch or commit here - append `blocked: launched in primary checkout, not an isolated worktree` to the status file and stop.

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • git status --short and git diff --stat d42016a 2222e33; inspected changed implementation and regression tests.
  • Executed selected backend, relaunch, shared-worktree, secondmate-descendant, and teardown regressions using temporary runners; exact selectors recorded in verification-steps.txt.
  • Executed all tests/fm-tangle-guard.test.sh cases and captured the generated dot-project launch brief.
  • Verified real leftover-process reaping without lsof, outsider survival, and invoking-shell protection with both discovery paths.
  • Ran an isolated real Herdr server: moved a registered-agent pane outside its recorded worktree, invoked relaunch, and verified refusal preserved agent, metadata, and worktree.
  • Stopped the private server, removed temporary runners and fixtures, and confirmed git status --short was clean.
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix: Annotate intentional literal Markdown backticks for ShellCheck
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

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