Skip to content

fix(bin): forbid agent co-author commit trailers in every generated brief - #4352

Open
NicholasACTran wants to merge 15 commits into
kunchenguid:mainfrom
NicholasACTran:fm/fm-brief-must-forbid-agent-coauthor-trailer
Open

NicholasACTran wants to merge 15 commits into
kunchenguid:mainfrom
NicholasACTran:fm/fm-brief-must-forbid-agent-coauthor-trailer

Conversation

@NicholasACTran

Copy link
Copy Markdown

Intent

Crewmate briefs must forbid the agent co-author commit trailer. Add a hard, unmissable prohibition to the bin/fm-brief.sh scaffold so every generated brief tells the worker never to add a Co-Authored-By agent trailer, phrased so it also reaches how the worker instructs the no-mistakes pipeline agent committing on its behalf (since pipeline-authored fix commits on the worker's branch carry the trailer too). Cover the case where a worker already made such a commit: it may rewrite its OWN unmerged task branch to strip it, but must never touch anything that has reached the default branch. Add a test asserting the scaffold carries this prohibition (asserting the shape, not the exact sentence), since briefs here are generated. Do not rewrite history on any project's default branch (six such commits already merged to landvera main are the captain's call, not this ticket). Do not change no-mistakes itself. One sentence per line in Markdown, plain dash not em dash, shellcheck-clean shell.

What Changed

  • Added fm_commit_attribution_block to bin/fm-dod-lib.sh as the single owner of a hard "Commit attribution" prohibition on agent co-author trailers, rendered into all three ship modes' Definition of done plus the scout and secondmate scaffolds in bin/fm-brief.sh; each arm is tailored to branch ownership - direct-PR and local-only get a mode-specific check point and an authorization to rewrite only the task's own unmerged fm/<id> branch, no-mistakes additionally tells the worker to carry the ban into --intent and axi respond fix instructions, forbids any rewrite while a run owns the branch, and routes a surviving post-run trailer to a note: line before the terminal done: line. Never rewriting the default branch is absolute in every arm, and fm_brief_intent_overlay now carries the ban through the overlay that otherwise supersedes earlier --intent instructions.
  • Declared note: as a status verb in the scout and ship brief state lists and classified it in bin/fm-classify-lib.sh as nonterminal and not captain-relevant, so a disclosure whose prose contains a legacy free-text token such as merged neither escalates nor clears a pane's possible-wedge aging.
  • Added tests covering the prohibition's shape (not its wording) in the ship, scout, and secondmate scaffolds, the ban's survival into the assembled launch-brief.md, and the note: verb's nonterminal wedge-aging behavior; updated docs/architecture.md and docs/scripts.md to record the new verb classification and fm-dod-lib.sh's ownership of the ban.

🤖 Generated with Claude Code

Risk Assessment

✅ Low: The change adds worker-facing prose to generated briefs plus one narrow, correctly-placed classifier exclusion for the note: verb; it conforms to the stated intent, renders cleanly in every brief kind, and its behavioral change is covered by a genuine regression test at the shared boundary both daemon call sites already route through.

Testing

I stood up isolated firstmate homes and ran the brief scaffolder, the spawn, and the scout promotion the way firstmate does, then read the Markdown the worker actually receives. All five generated brief kinds now carry the hard co-author trailer ban: the three ship modes each name their own check point, the no-mistakes arm is phased (strip pre-run, never touch the branch while a run owns it, disclose afterwards on a note: line) and carries the --intent and axi respond levers, while the scout and secondmate arms carry the ban with no branch, pipeline, or check-point prose. The assembled launch-brief.md keeps the ban and states its substance inline in the intent overlay rather than dangling a reference, and a promoted scout receives the same block. Adversarially, a note: line whose prose says "merged" or "PR ready" reads neither terminal nor captain-relevant and leaves the possible-wedge marker aging, the note: line still surfaces as unread status, and the prescribed disclosure shape leaves done: PR &lt;url&gt; checks green fully parseable by the reconciler while the forbidden folded-into-done: variant loses the URL - which is exactly why the instruction places it on its own line. The change has no graphical surface; the end-user artifact is generated Markdown, so evidence is the rendered brief files themselves plus the CLI transcripts. Targeted suites for brief, task delivery, and daemon classification all pass, and the new brief tests fail against the pre-change scaffold and pass against this change.

  • Live validation: ✅ go - 9 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Firstmate scaffolds a no-mistakes ship brief and the worker reads a phased co-author trailer ban naming its pipeline levers ✅ pass live FM_HOME=&lt;tmp&gt; ./bin/fm-brief.sh live-no-mistakes some-proj --mode no-mistakes; rendered block in evidence file brief-ship-no-mistakes.md shows the HARD RULE heading, the --intent/axi respond levers,…
Firstmate scaffolds direct-PR and local-only briefs and each carries the same ban with its own check point and no pipeline prose ✅ pass live ./bin/fm-brief.sh ... --mode direct-PR|local-only; attribution-blocks-all-brief-kinds.txt shows "Before you push this branch and before you open or update its PR" and "Before you report this branch…
A scout brief forbids the trailer on scratch commits without borrowing ship-path branch, pipeline or check-point prose ✅ pass live ./bin/fm-brief.sh live-scout some-proj --scout; brief-scout.md block names "the scratch commits discarded at teardown" and contains no branch/pipeline/--intent/check-point clause
A secondmate charter forbids the trailer on every commit it writes, including a merge under standing merge authority ✅ pass live ./bin/fm-brief.sh live-sm --secondmate some-proj; brief-secondmate-charter.md block names "a merge you perform yourself under standing merge authority" with no ship-path clauses
The ban survives into launch-brief.md, the artifact the worker is actually launched with, and the intent overlay names it as a standing exception stating its substance inline ✅ pass live ./bin/fm-spawn.sh live-launch &lt;proj&gt; claude --mode no-mistakes --yolo off; launch-brief-no-mistakes-assembled.md carries the full block and an overlay sentence that spells out the Co-Authored-By rul…
A promoted scout receives the same ban in its delivered ship instructions ✅ pass live ./bin/fm-promote.sh promote-live-b --mode no-mistakes --yolo off with a capture stub for fm-send.sh; promoted-scout-ship-instructions.md contains the identical no-mistakes attribution block
Adversarial: a note: disclosure whose prose contains captain free-text tokens does not read terminal and does not clear the pane's possible-wedge aging ✅ pass live Live calls to status_is_terminal_verb/status_is_captain_relevant on 'note: rebased onto merged #76', 'note: waiting on PR ready upstream', 'note: checks green upstream' (note-disclosure-and-wedge-driv…
Adversarial: following the brief's disclosure instruction leaves the terminal done: line machine-parseable, while the forbidden folded variant loses the PR URL ✅ pass live note-disclosure-and-wedge-drive.txt: the reconciler extractor returns https://github.com/o/r/pull/12 from the untouched done: line and returns empty when the disclosure is appended to it; the note: li…
Regression: the scaffold before this change carried no such prohibition, and the new test detects that ✅ pass live Base tree b518a25 exported with git archive: briefs render 0 co-author mentions and the new tests/fm-brief.test.sh fails there with "brief did not mention the co-author trailer ban at all"; the same…
Evidence: Attribution block as rendered in all five brief kinds

Source: Attribution block as rendered in all five brief kinds

=============== live-no-mistakes ===============
## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
The pipeline commits on your behalf, so carry this ban to it through the two channels you already drive: state it in the `--intent` you pass `no-mistakes axi run`, and restate it in every fix instruction you send with `no-mistakes axi respond`.
Before you start a no-mistakes run, while `fm/live-no-mistakes` is still yours alone, check every commit on this branch for that trailer; if you find one, rewrite ONLY this task's own unmerged branch to strip it, and say in your report that you did.
While a run is active the pipeline owns `fm/live-no-mistakes`: never rebase, amend, filter, force-push, or hand-commit on it, not even to strip a trailer.
Once the run is terminal, check the branch again and report a surviving trailer instead of rewriting the pushed PR head: append a `note:` line naming those commits immediately before your terminal `done:` line, leave that `done:` line in its exact required shape, and let firstmate decide before merge.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
=============== live-direct-PR ===============
## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
Before you push this branch and before you open or update its PR, check this branch's commits for that trailer.
If you find one, rewrite ONLY this task's own unmerged branch (`fm/live-direct-PR`) to strip it, and say in your report that you did.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
=============== live-local-only ===============
## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
Before you report this branch ready for the merge authority, check this branch's commits for that trailer.
If you find one, rewrite ONLY this task's own unmerged branch (`fm/live-local-only`) to strip it, and say in your report that you did.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
=============== live-scout ===============
## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit you write here, including the scratch commits discarded at teardown.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
=============== live-sm ===============
## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit you write, including a merge you perform yourself under standing merge authority.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
Evidence: Rendered no-mistakes ship brief (full)

Source: Rendered no-mistakes ship brief (full)

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
{TASK}

## Firstmate spec
{FIRSTMATE_SPEC}

# 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 some-proj, at a detached HEAD on a clean default branch.

**Verify isolation before anything else.** Run `pwd -P` and `git rev-parse --show-toplevel`; both must resolve to the disposable task worktree you were launched in, such as a treehouse pool path or an Orca-managed worktree, not the primary checkout firstmate operates from.
The path check is authoritative: `git rev-parse --git-dir` and `git rev-parse --git-common-dir` can help inspect the repo, but they do not prove you are outside the primary checkout.
If the top-level path is the primary checkout or not the worktree you were launched in, 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/live-no-mistakes`
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}" >> '/tmp/fmlive.ROG33f/state/live-no-mistakes.status'`
   States: working, needs-decision, blocked, paused, done, failed, note.
   Use `note: {fact}` for a supervisor-actionable fact that is not a state change; it never replaces a state line.
   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 `/tmp/fmlive.ROG33f/data/live-no-mistakes/nm-<run>-findings.txt`, then report the gate with
   `needs-decision [key=nm-<run>-<step>]: ask-user findings=<id1>,<id2>,... file=/tmp/fmlive.ROG33f/data/live-no-mistakes/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 '/tmp/fmlive.ROG33f/state/live-no-mistakes.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '/tmp/fmlive.ROG33f/state/live-no-mistakes.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '/tmp/fmlive.ROG33f/state/live-no-mistakes.inbox'/NNN.msg '/tmp/fmlive.ROG33f/state/live-no-mistakes.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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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.

## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
The pipeline commits on your behalf, so carry this ban to it through the two channels you already drive: state it in the `--intent` you pass `no-mistakes axi run`, and restate it in every fix instruction you send with `no-mistakes axi respond`.
Before you start a no-mistakes run, while `fm/live-no-mistakes` is still yours alone, check every commit on this branch for that trailer; if you find one, rewrite ONLY this task's own unmerged branch to strip it, and say in your report that you did.
While a run is active the pipeline owns `fm/live-no-mistakes`: never rebase, amend, filter, force-push, or hand-commit on it, not even to strip a trailer.
Once the run is terminal, check the branch again and report a surviving trailer instead of rewriting the pushed PR head: append a `note:` line naming those commits immediately before your terminal `done:` line, leave that `done:` line in its exact required shape, and let firstmate decide before merge.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.

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, plus the standing commit-attribution ban above, which belongs in every run's intent because the pipeline commits on your branch and only you can tell it that rule.
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.
Evidence: Rendered direct-PR ship brief (full)

Source: Rendered direct-PR ship brief (full)

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
{TASK}

## Firstmate spec
{FIRSTMATE_SPEC}

# 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 some-proj, at a detached HEAD on a clean default branch.

**Verify isolation before anything else.** Run `pwd -P` and `git rev-parse --show-toplevel`; both must resolve to the disposable task worktree you were launched in, such as a treehouse pool path or an Orca-managed worktree, not the primary checkout firstmate operates from.
The path check is authoritative: `git rev-parse --git-dir` and `git rev-parse --git-common-dir` can help inspect the repo, but they do not prove you are outside the primary checkout.
If the top-level path is the primary checkout or not the worktree you were launched in, 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/live-direct-PR`

# Rules
1. Never push to the default branch (push only your `fm/live-direct-PR` 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}" >> '/tmp/fmlive.ROG33f/state/live-direct-PR.status'`
   States: working, needs-decision, blocked, paused, done, failed, note.
   Use `note: {fact}` for a supervisor-actionable fact that is not a state change; it never replaces a state line.
   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.

   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 '/tmp/fmlive.ROG33f/state/live-direct-PR.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '/tmp/fmlive.ROG33f/state/live-direct-PR.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '/tmp/fmlive.ROG33f/state/live-direct-PR.inbox'/NNN.msg '/tmp/fmlive.ROG33f/state/live-direct-PR.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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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=direct-PR
This task ships **direct-PR**: you raise the PR yourself, without the no-mistakes pipeline.
The task is complete only when committed on your branch.
When it is implemented and committed, push your branch and open a PR with `gh-axi`, then append `done: PR {url}` to the status file and stop.
Do NOT run /no-mistakes. The configured merge authority decides whether to merge the PR; firstmate relays the outcome.

## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
Before you push this branch and before you open or update its PR, check this branch's commits for that trailer.
If you find one, rewrite ONLY this task's own unmerged branch (`fm/live-direct-PR`) to strip it, and say in your report that you did.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
Evidence: Rendered local-only ship brief (full)

Source: Rendered local-only ship brief (full)

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
{TASK}

## Firstmate spec
{FIRSTMATE_SPEC}

# 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 some-proj, at a detached HEAD on a clean default branch.

**Verify isolation before anything else.** Run `pwd -P` and `git rev-parse --show-toplevel`; both must resolve to the disposable task worktree you were launched in, such as a treehouse pool path or an Orca-managed worktree, not the primary checkout firstmate operates from.
The path check is authoritative: `git rev-parse --git-dir` and `git rev-parse --git-common-dir` can help inspect the repo, but they do not prove you are outside the primary checkout.
If the top-level path is the primary checkout or not the worktree you were launched in, 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/live-local-only`

# Rules
1. Never push to any remote and never open a PR. Work only on your `fm/live-local-only` branch; firstmate handles the merge into local `main`.
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}" >> '/tmp/fmlive.ROG33f/state/live-local-only.status'`
   States: working, needs-decision, blocked, paused, done, failed, note.
   Use `note: {fact}` for a supervisor-actionable fact that is not a state change; it never replaces a state line.
   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.

   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 '/tmp/fmlive.ROG33f/state/live-local-only.inbox'.
When a terminal message says an instruction is waiting there - and at any natural checkpoint when you are unsure - list '/tmp/fmlive.ROG33f/state/live-local-only.inbox'/*.msg, read and act on each message in numeric order, then acknowledge each handled message by moving it: `mv '/tmp/fmlive.ROG33f/state/live-local-only.inbox'/NNN.msg '/tmp/fmlive.ROG33f/state/live-local-only.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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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/ae70dfc3be15/01M2CKY033M7SZR3MB094PJ9T5/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=local-only
This task ships **local-only**: no remote, no PR, no pipeline.
The task is complete only when committed on your branch `fm/live-local-only`. Do NOT push, do NOT open a PR, do NOT merge.
Keep your branch a clean fast-forward onto the current default branch - if `main` has advanced, rebase onto it so the eventual merge stays a fast-forward.
When it is implemented and committed, append `done: ready in branch fm/live-local-only` to the status file and stop.
The configured merge authority approves the ready branch, then firstmate merges it into local `main` through the guarded fast-forward path.

## Commit attribution - HARD RULE, no exceptions
NEVER put an agent name as a commit co-author trailer (for example `Co-Authored-By: Claude ... <noreply@anthropic.com>`) on any commit on this branch.
Before you report this branch ready for the merge authority, check this branch's commits for that trailer.
If you find one, rewrite ONLY this task's own unmerged branch (`fm/live-local-only`) to strip it, and say in your report that you did.
Never rewrite a commit that has already reached the default branch; that is the captain's call, not yours.
Evidence: note: disclosure shape and wedge-classification drive

Source: note: disclosure shape and wedge-classification drive

--- worker status file as the brief instructs ---
note: commits a1b2c3, d4e5f6 carry an agent co-author trailer
done: PR https://github.com/o/r/pull/12 checks green
reconciler PR extracted from terminal line : 'https://github.com/o/r/pull/12'
note: line surfaces as UNREAD STATUS       : yes
note: reads terminal                       : no
done: still reads terminal                 : yes

--- adversarial: disclosure folded into the done: line (the shape the brief forbids) ---
done: PR https://github.com/o/r/pull/12 checks green - commits a1b2c3 carry Co-Authored-By: Claude
reconciler PR extracted                    : '' (URL lost - why the disclosure must not go here)

--- adversarial: note: prose containing captain free-text tokens ---
note: rebased onto merged #76
  captain-relevant (would clear wedge)     : no
  terminal                                 : no
note: waiting on PR ready upstream
  captain-relevant (would clear wedge)     : no
  terminal                                 : no
note: checks green upstream, still working
  captain-relevant (would clear wedge)     : no
  terminal                                 : no
Evidence: Regression: new brief tests before vs after the change

Source: Regression: new brief tests before vs after the change

Regression reproduction: new brief test file run against the pre-change (base b518a25) scaffold

ok - fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly
not ok - brief-coauthor-nm: brief did not mention the co-author trailer ban at all (missing: 'co-author')
--- output ---


Same test file against the change (0ccf7d0):
/private/var/folders/6w/ghhdhb9n40q6969qp9wymyzc0000gn/T/fm-brief.d18Dte/heredoc-in-substitution.sh:2
ok - fm-brief.sh: no heredoc is nested inside a command substitution (Bash 3.2 parse-safe)
ok - fm-brief.sh: --help renders the complete header
ok - fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly

(after-run tail)
ok - fm-brief.sh: every ship mode forbids an agent co-author commit trailer
ok - fm-brief.sh: a scout brief forbids an agent co-author commit trailer too
ok - fm-brief.sh: a secondmate charter forbids an agent co-author commit trailer too

Pipeline

Updates from git push no-mistakes

... (7 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)

⚠️ **Review** - 1 info

🔧 Fix applied.
1 warning still open:

  • ⚠️ bin/fm-dod-lib.sh:153 - The --intent exception added in round 4 is overridden by the last section of the brief the worker actually reads. bin/fm-spawn.sh:2371-2377 appends fm_brief_intent_overlay to launch-brief.md for EVERY KIND=ship/MODE=no-mistakes spawn, after the whole Definition of done, and that overlay opens by declaring "This section supersedes every earlier brief instruction about constructing --intent, but not later clarifications actually supplied by the captain" (bin/fm-dod-lib.sh:152), then gives an exhaustive construction rule: "Use the serialized captain intent below plus any later words the captain actually supplied as --intent" (line 153). The DOD's newly amended sentence ("...plus the standing commit-attribution ban above, which belongs in every run's intent", bin/fm-dod-lib.sh:289) is precisely an "earlier brief instruction about constructing --intent", and the ban is not a later captain clarification, so the overlay's two-part rule displaces the three-part one. Concrete sequence: firstmate scaffolds a no-mistakes ship brief, fm-spawn.sh renders launch-brief.md, the worker reads the file top-down, reaches the explicitly-superseding final section, and builds --intent from the serialized captain intent alone. The pipeline then never receives the ban, its fix commits carry Co-Authored-By: Claude ..., and the worker is simultaneously forbidden from amending the branch while the run is active (bin/fm-dod-lib.sh:270). That defeats the intent's required phrasing "so it also reaches how the worker instructs the no-mistakes pipeline agent committing on its behalf" for the only mode where a pipeline commits at all. This is the same class of conflict the round-3 decision fixed, but at the stronger, explicitly-superseding site; the fix round only edited the DOD sentence. The narrow remedy is to carry the ban into fm_brief_intent_overlay's construction sentence (and update the wording assertions at tests/fm-task-delivery.test.sh:511,545). Note that the existing brief-shape test cannot see this: tests/fm-brief.test.sh asserts on brief.md, never on the rendered launch-brief.md that contains the overlay. This is worker-facing generated contract prose and the placement is the author's call, so ask-user rather than a reviewer rewrite.

🔧 Fix applied.
3 issues (2 warnings, 1 info) still open:

  • ⚠️ bin/fm-brief.sh:285 - The User intent requires the prohibition in "the bin/fm-brief.sh scaffold so every generated brief tells the worker never to add a Co-Authored-By agent trailer". bin/fm-brief.sh generates three brief kinds; the change adds fm_commit_attribution_block to the ship scaffold (bin/fm-dod-lib.sh:259, :273, :283) and the scout scaffold (bin/fm-brief.sh:425), but the secondmate charter (the if [ &#34;$KIND&#34; = secondmate ] scaffold at bin/fm-brief.sh:217-330) carries no attribution rule at all. A secondmate is not a passive router: its own charter tells it to report "a merge you performed yourself under standing merge authority" (bin/fm-brief.sh:280), and it writes docs under its home, so it can author a commit - including a merge commit onto a default branch - with a hand-written message carrying Co-Authored-By: Claude ... &lt;noreply@anthropic.com&gt;, and nothing in its brief forbids it. The gap is also the one place where the change's own rendered note:/States updates were applied selectively (bin/fm-brief.sh:383 and :475 gained note, line 285 did not), so the omission reads as unexamined rather than deliberate. Whether "every generated brief" was meant to include the secondmate charter, or whether the intent's title ("Crewmate briefs") deliberately scopes it to ship and scout only, is the author's call - a secondmate is consistently distinguished from a crewmate elsewhere in this scaffold (see test_herdr_lab_contract_applies_to_scouts_but_not_secondmates). The remedy either adds a secondmate arm to fm_commit_attribution_block (extending the change to a third brief kind) or records that the charter is intentionally out of scope; both are scope decisions, not a mechanical correction.
  • ⚠️ tests/fm-brief.test.sh:465 - Simplification: the change introduces a second, exact-sentence copy of a rule the new shape-level test already asserts. assert_grep &#34;plus the standing commit-attribution ban above&#34; at tests/fm-brief.test.sh:465 pins a literal fragment of bin/fm-dod-lib.sh:289, while tests/fm-brief.test.sh:276-281 already asserts the same fact at shape level (the --intent-restricting sentence must affirmatively admit the attribution ban, and must not name it only to exclude it). The User intent explicitly asks for the opposite of an exact pin: "Add a test asserting the scaffold carries this prohibition (asserting the shape, not the exact sentence), since briefs here are generated." No intent requirement needs the literal-fragment copy, and keeping it means any future rewording of that sentence breaks two tests for one contract, one of which fails with a message about wording rather than about the rule. I note the surrounding test_no_mistakes_dod_wording is itself a pre-existing wording-pinning test, so adding a line there follows local convention - which is why this is the author's call rather than a reviewer fix. Recommended remedy is removing tests/fm-brief.test.sh:465 and leaving the shape-level assertion as the single owner, not hardening or documenting the duplicate.
  • ℹ️ bin/fm-dod-lib.sh:154 - The new overlay sentence is a pointer, not a statement: "The Definition of done's commit-attribution ban is the one standing exception to that supersession: carry it into --intent as well". It never says what the ban is. bin/fm-spawn.sh:2369-2379 re-renders launch-brief.md from the stored brief.md on every spawn AND every relaunch, and brief.md is scaffolded once and never regenerated - so a no-mistakes task scaffolded before this change and relaunched after it gets an overlay pointing at a "Definition of done's commit-attribution ban" that is absent from the assembled file. The worker then has a dangling reference and no ban text to carry, which is no worse than the pre-change status quo (the ban simply does not reach --intent), so this is transitional rather than a regression; the new test at tests/fm-task-delivery.test.sh:799 cannot see it because it scaffolds a fresh brief. The narrow remedy is to make the overlay sentence self-sufficient by stating the ban's substance inline (one clause naming the Co-Authored-By agent trailer) rather than only referencing it, which is worker-facing generated prose and therefore the author's wording call.

🔧 Fix applied.
2 issues (1 warning, 1 info) still open:

  • ⚠️ bin/fm-dod-lib.sh:217 - Simplification: the shared ship-mode preamble renders "This holds whether you write the commit yourself or a pipeline step writes it on your behalf while applying a fix." into all three ship modes, including two whose own Definition of done in the same brief states that no pipeline ever runs. A direct-PR brief reads "This task ships direct-PR: you raise the PR yourself, without the no-mistakes pipeline." and "Do NOT run /no-mistakes." (bin/fm-dod-lib.sh:260, :264); a local-only brief reads "This task ships local-only: no remote, no PR, no pipeline." (bin/fm-dod-lib.sh:271). No pipeline step ever commits on those branches, so the sentence describes a case that cannot occur and sits three lines below a flat prohibition on the pipeline it invokes.

The User intent scopes this clause to no-mistakes only: "phrased so it also reaches how the worker instructs the no-mistakes pipeline agent committing on its behalf (since pipeline-authored fix commits on the worker's branch carry the trailer too)". No intent requirement needs the clause in direct-PR or local-only. The component was introduced by fix round 2's mode split (7992c99), not by the author, and the new test at tests/fm-brief.test.sh:249 pins it into all three modes, so the clause cannot be narrowed without also narrowing that assertion.

Narrower form that satisfies the intent: move the pipeline sentence into the no-mistakes) arm (alongside the existing "The pipeline commits on your behalf..." line at bin/fm-dod-lib.sh:225) and move the corresponding assertion out of the shared ship-mode loop into the no-mistakes-specific block at tests/fm-brief.test.sh:258. The remedy removes a component the intent does not require rather than hardening it, so it is the author's call.

  • ℹ️ bin/fm-brief.sh:285 - The note verb was added to the declared state set in the ship brief (bin/fm-brief.sh:385) and the scout brief (bin/fm-brief.sh:477), each with the explanatory sentence "Use note: {fact} for a supervisor-actionable fact that is not a state change; it never replaces a state line." The secondmate charter's own states list at bin/fm-brief.sh:285 was left as "States: working, needs-decision, blocked, $PAUSED_VERB, done, failed."

This is not currently reachable as a defect: the secondmate arm of fm_commit_attribution_block (bin/fm-dod-lib.sh:210-212) deliberately carries no branch, pipeline, or check-point clause and therefore never instructs a secondmate to append a note: line, so nothing in this change makes a secondmate emit the verb it was not told about. note: is nonetheless a real verb on the parent channel a secondmate writes to (status_line_is_unread_surface, bin/fm-classify-lib.sh:1474), so the asymmetry is worth a deliberate yes-or-no rather than an accident. Noting only; no action required unless the author intended "every generated brief" to include the charter's states list.

🔧 Fix applied.
1 warning still open:

  • ⚠️ bin/fm-dod-lib.sh:222 - Simplification: the no-mistakes arm now states pipeline coverage of the ban twice. Round 6's selected fix moved the formerly shared preamble sentence "This holds whether you write the commit yourself or a pipeline step writes it on your behalf while applying a fix." (line 222) into the no-mistakes) case, where it lands directly above "The pipeline commits on your behalf, so carry this ban to it through the two channels you already drive: state it in the --intent you pass no-mistakes axi run, and restate it in every fix instruction you send with no-mistakes axi respond." (line 223). Both sentences assert the same fact - the ban reaches a commit a pipeline step authors on the worker's branch - so the arm carries a parallel copy of one rule, which is exactly the second-definition shape this pass is asked to name. The User intent requires the ban be "phrased so it also reaches how the worker instructs the no-mistakes pipeline agent committing on its behalf"; line 223 alone satisfies that, and it is the only one of the two that gives the worker the actual lever. No intent requirement needs line 222 once the clause is mode-scoped - it only existed to carry the fact into the two modes that no longer receive it. The narrower form is deleting line 222. The new assertion grep -Eiq &#34;pipeline.*on your behalf&#34; at tests/fm-brief.test.sh is satisfied by line 223 by itself, as are the --intent and respond|fix instruction|gate lever assertions, so no test needs changing. This is worker-facing generated prose introduced by a prior fix round, so the wording call is the author's.

🔧 Fix applied.
1 info still open:

  • ℹ️ tests/fm-brief.test.sh:225 - The new test's header comment states "The captain has banned an agent co-author commit trailer outright, and nothing else enforces that ban". That is inaccurate: bin/fm-spawn.sh:1539 already carries an attribution-off policy in every claude launch's per-launch --settings JSON (&#34;attribution&#34;:{&#34;commit&#34;:&#34;&#34;,&#34;pr&#34;:&#34;&#34;,&#34;sessionUrl&#34;:false}), documented again at bin/fm-spawn.sh:325, which suppresses the Co-Authored-By trailer for spawned claude workers. The brief-level ban is still justified and required by the intent - it is the only control that reaches non-claude backends (the codex launch template at bin/fm-spawn.sh:1553 carries no such settings) and the no-mistakes pipeline agent committing on the worker's branch - but the comment overstates the gap and would mislead a future reader into thinking the settings policy does not exist. Noting only; the code and the assertions are correct.
✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 9 of 9 scenarios driven live against the product
Scenario Result Live Evidence
Firstmate scaffolds a no-mistakes ship brief and the worker reads a phased co-author trailer ban naming its pipeline levers ✅ pass live FM_HOME=&lt;tmp&gt; ./bin/fm-brief.sh live-no-mistakes some-proj --mode no-mistakes; rendered block in evidence file brief-ship-no-mistakes.md shows the HARD RULE heading, the --intent/axi respond levers,…
Firstmate scaffolds direct-PR and local-only briefs and each carries the same ban with its own check point and no pipeline prose ✅ pass live ./bin/fm-brief.sh ... --mode direct-PR|local-only; attribution-blocks-all-brief-kinds.txt shows "Before you push this branch and before you open or update its PR" and "Before you report this branch…
A scout brief forbids the trailer on scratch commits without borrowing ship-path branch, pipeline or check-point prose ✅ pass live ./bin/fm-brief.sh live-scout some-proj --scout; brief-scout.md block names "the scratch commits discarded at teardown" and contains no branch/pipeline/--intent/check-point clause
A secondmate charter forbids the trailer on every commit it writes, including a merge under standing merge authority ✅ pass live ./bin/fm-brief.sh live-sm --secondmate some-proj; brief-secondmate-charter.md block names "a merge you perform yourself under standing merge authority" with no ship-path clauses
The ban survives into launch-brief.md, the artifact the worker is actually launched with, and the intent overlay names it as a standing exception stating its substance inline ✅ pass live ./bin/fm-spawn.sh live-launch &lt;proj&gt; claude --mode no-mistakes --yolo off; launch-brief-no-mistakes-assembled.md carries the full block and an overlay sentence that spells out the Co-Authored-By rul…
A promoted scout receives the same ban in its delivered ship instructions ✅ pass live ./bin/fm-promote.sh promote-live-b --mode no-mistakes --yolo off with a capture stub for fm-send.sh; promoted-scout-ship-instructions.md contains the identical no-mistakes attribution block
Adversarial: a note: disclosure whose prose contains captain free-text tokens does not read terminal and does not clear the pane's possible-wedge aging ✅ pass live Live calls to status_is_terminal_verb/status_is_captain_relevant on 'note: rebased onto merged #76', 'note: waiting on PR ready upstream', 'note: checks green upstream' (note-disclosure-and-wedge-driv…
Adversarial: following the brief's disclosure instruction leaves the terminal done: line machine-parseable, while the forbidden folded variant loses the PR URL ✅ pass live note-disclosure-and-wedge-drive.txt: the reconciler extractor returns https://github.com/o/r/pull/12 from the untouched done: line and returns empty when the disclosure is appended to it; the note: li…
Regression: the scaffold before this change carried no such prohibition, and the new test detects that ✅ pass live Base tree b518a25 exported with git archive: briefs render 0 co-author mentions and the new tests/fm-brief.test.sh fails there with "brief did not mention the co-author trailer ban at all"; the same…
  • FM_HOME=&lt;tmp&gt; ./bin/fm-brief.sh live-&lt;mode&gt; some-proj --mode no-mistakes|direct-PR|local-only then read the rendered ## Commit attribution - HARD RULE, no exceptions block in each brief.md
  • FM_HOME=&lt;tmp&gt; ./bin/fm-brief.sh live-scout some-proj --scout and ./bin/fm-brief.sh live-sm --secondmate some-proj, checking each arm carries the ban and borrows no branch/pipeline/check-point prose
  • ./bin/fm-spawn.sh live-launch &lt;proj&gt; claude --mode no-mistakes --yolo off (fake tmux, FM_GATE_REFUSE_BYPASS=1 harness hatch) to render launch-brief.md and read the ban plus the self-contained intent-overlay exception
  • ./bin/fm-promote.sh promote-live-b --mode no-mistakes --yolo off with a capture stub for fm-send.sh, reading the ship instructions actually delivered to the promoted worker
  • Live drive of status_is_captain_relevant, status_is_terminal_verb, status_line_is_unread_surface and the reconciler's done: PR &lt;url&gt; checks green extractor with the brief's prescribed note:/done: pair and with adversarial note: prose containing "merged", "PR ready", "checks green"
  • ./tests/fm-brief.test.sh
  • ./tests/fm-task-delivery.test.sh
  • ./tests/fm-daemon.test.sh (includes test_note_line_is_nonterminal_and_keeps_wedge_aging, which drives classify_stale/handle_wake/housekeeping)
  • Regression reproduction: new tests/fm-brief.test.sh run against a git archive of base b518a25 (fails) versus the change (passes)
⚠️ **Document** - 1 info
  • ℹ️ .agents/skills/firstmate-codexapp/SKILL.md:64 - Judgment call, left unchanged: .agents/skills/firstmate-codexapp/SKILL.md:64 gives a Codex Desktop thread template listing status prefixes (working, needs-decision, blocked, paused, done, failed) without note. I read it as still accurate because it scopes itself to "prefixes for status changes" and note: is explicitly not a state change, and because a Desktop companion thread is not a generated crewmate brief. If the author intends the advertised verb set to be uniform across every worker-facing surface, that line is the remaining place to add it.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

The captain banned auto-adding an agent name as a commit co-author, but
nothing enforced it: six of the last eight merged landvera commits carried
the trailer, and bin/fm-brief.sh never mentioned it.

Add the hard prohibition to fm-dod-lib.sh's fm_dod_block, the single owner
shared by fm-brief.sh and fm-promote.sh, so every ship mode and a promoted
scout's ship instructions all carry it. It covers commits a pipeline step
makes on the worker's behalf, not just hand-written ones, and it authorizes
stripping the trailer only from the task's own unmerged branch, never from
anything already on the default branch.
tiago-peixoto added a commit to tiago-peixoto/firstmate that referenced this pull request Sep 25, 2026
…time (#57)

Cursor injects the trailer after the typed message, and a per-machine
cli-config opt-out is not a fleet contract. Every spawn now gives the
pane a commit-msg hook that strips known AI trailers at the commit object,
chaining the repository's own hooks at run time, failing closed on
non-git launches, and cleaning up its read-only strip directory on abort
and teardown. A secondmate home must be a git checkout so the strip
cannot be skipped there; the upstream worker-account fixture is taught
that.

Fork patch. No upstream thread of this fleet's own tracks it; the
nearest upstream threads are other contributors' brief-rule PRs kunchenguid#1379
and kunchenguid#4352 (open) and kunchenguid#4523 (closed by its author as a mistaken target).
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