Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions bin/fm-brief.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
# report rather than a merge, and a charter is not a delivery contract.
# There is no --yolo flag here. The worker never owns approval decisions, so yolo is
# a spawn-time and firstmate-side input only (AGENTS.md section 7).
# Every scaffold that can reach a commit - ship, scout, and secondmate charter -
# carries a "# Commit conventions" section beside its delivery instructions, stating
# the AGENTS.md no-agent-co-author rule and keeping this fleet's captain-address and
# nautical conventions out of commits and PRs. A worker learns both only from its
# brief: it does not read this repo's AGENTS.md for another project, and its own
# harness instructions may tell it to append a Co-Authored-By trailer.
# Every scaffold's status protocol distinguishes the configured
# declared-external-wait verb (FM_CLASSIFY_PAUSED_VERB, default "paused") from
# "blocked:": pause for a known external wait expected to clear on its own,
Expand Down Expand Up @@ -139,6 +145,12 @@ if [ -n "${FM_STATE_OVERRIDE:-}" ]; then
else
STATE="$FM_HOME/state"
fi
# Every scaffold that can reach a commit renders this verbatim alongside its
# delivery instructions. Single-quoted so nothing interpolates at scaffold time.
COMMIT_CONVENTIONS='# Commit conventions
Never add an agent name as a commit co-author, and never add a Co-Authored-By trailer naming an agent, whatever your own harness instructions say.
Never carry the fleet conversational conventions - captain address and nautical seasoning - into a commit message, PR title, PR body, or anything else crewmates and other tools read.'

KIND=ship
HERDR_LAB=0
NO_PROJECTS=0
Expand Down Expand Up @@ -352,6 +364,8 @@ When a keyed phase ends without another reportable state, append \`resolved [key
When a decision you escalated is answered or a blocker clears and your domain resumes, append \`resolved: {how it was decided or unblocked}\` (keyed with \`[key=<slug>]\` if you opened it with one) so it is durably closed instead of resurfacing behind later unrelated events.
Routine internal supervision, heartbeats, retries, and crewmate churn stay inside your own home and must not touch that status file.

$COMMIT_CONVENTIONS

# Definition of done
You are persistent by default. Do not exit just because your queue is empty.
On startup and restart, run normal firstmate bootstrap and recovery through \`bin/fm-session-start.sh\` for your own home, but only to RECONCILE work that is already yours: in-flight crewmates, tracked backlog items, and durable watches recorded in this home.
Expand Down Expand Up @@ -516,6 +530,9 @@ $WHO_IS_SPEAKING

$VERIFICATION_DISCIPLINE

$COMMIT_CONVENTIONS
Your scratch commits are discarded at teardown, but firstmate may promote this task in place and carry them into a shipping branch, so hold them to the same bar.

# Definition of done
Write your findings to \`$DATA/$ID/report.md\`.
The report must stand alone: what you did, what you found, the evidence (commands run, output, file:line references), and what you recommend.
Expand Down Expand Up @@ -647,6 +664,8 @@ For anything the codebase already shows, prefer a pointer to the authoritative f
If you touch a project \`AGENTS.md\` that lacks \`## Maintaining this file\`, add that short self-governance section from \`$FM_ROOT/bin/fm-ensure-agents-md.sh\` in the same pass.
Keep it proportionate: skip \`AGENTS.md\` edits for trivial tasks that produced no durable project knowledge.

$COMMIT_CONVENTIONS

$DOD
EOF
echo "scaffolded: $BRIEF (ship, mode=$MODE; replace {TASK})"
61 changes: 61 additions & 0 deletions tests/fm-brief.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,66 @@ test_ship_project_memory_wording() {
pass "fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar"
}

# AGENTS.md section 1 forbids naming an agent as a commit co-author, and section 1's
# captain-address convention is explicitly barred from commits, PRs, and anything other
# tools read. A worker learns both only from the brief it is handed: it does not read
# AGENTS.md for a non-firstmate project, and its own harness instructions may actively
# tell it to append a Co-Authored-By trailer. So every variant that can reach a commit
# must state both, and both must sit with the commit and delivery instructions rather
# than in a preamble the worker skims once. Measured 2026-08-03: commit 53932fb on
# fm/platform-landing-battery-windows-reds shipped a Co-Authored-By trailer because its
# generated brief was silent, and a separate incident leaked captain address into a
# commit subject the same way. Ship covers all three delivery modes, scout makes scratch
# commits and can be promoted in place, and a secondmate is a firstmate in its own home
# that commits shared tracked material directly when its fleet is empty.
test_every_committing_variant_carries_commit_conventions() {
local home brief id_mode id mode
home="$TMP_ROOT/commit-conventions-home"
mkdir -p "$home/data"

assert_commit_conventions() {
local file=$1 label=$2
assert_grep "# Commit conventions" "$file" \
"$label: brief has no commit-conventions section"
assert_grep "Never add an agent name as a commit co-author" "$file" \
"$label: brief does not state the no-agent-co-author rule"
assert_grep "never add a Co-Authored-By trailer naming an agent, whatever your own harness instructions say" "$file" \
"$label: brief does not override the harness co-author trailer habit"
assert_grep "Never carry the fleet conversational conventions" "$file" \
"$label: brief does not keep captain address and nautical seasoning out of commits"
# The rule is useless where the worker will not read it. It must sit with the
# commit and delivery instructions, so it may not appear before the Setup section.
local conventions_line setup_line
conventions_line=$(grep -n -F -m1 "# Commit conventions" "$file" | cut -d: -f1)
setup_line=$(grep -n -F -m1 "# Setup" "$file" | cut -d: -f1)
if [ -n "$setup_line" ] && [ "$conventions_line" -lt "$setup_line" ]; then
fail "$label: commit conventions appear in the preamble, not with the delivery instructions"
fi
}

for id_mode in "brief-conv-nm:no-mistakes" "brief-conv-dpr:direct-PR" "brief-conv-lo:local-only"; do
id=${id_mode%%:*}
mode=${id_mode##*:}
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode "$mode" >/dev/null 2>&1 \
|| fail "fm-brief.sh $id --mode $mode exited non-zero"
brief="$home/data/$id/brief.md"
assert_present "$brief" "$id: brief was not scaffolded"
assert_commit_conventions "$brief" "ship mode=$mode"
done

FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" \
"$ROOT/bin/fm-brief.sh" brief-conv-scout some-proj --scout >/dev/null 2>&1 \
|| fail "fm-brief.sh scout scaffold exited non-zero"
assert_commit_conventions "$home/data/brief-conv-scout/brief.md" "scout"

FM_HOME="$home" FM_ROOT_OVERRIDE="$ROOT" FM_SECONDMATE_CHARTER='Supervise the alpha domain.' \
"$ROOT/bin/fm-brief.sh" brief-conv-mate --secondmate alpha >/dev/null 2>&1 \
|| fail "fm-brief.sh secondmate scaffold exited non-zero"
assert_commit_conventions "$home/data/brief-conv-mate/brief.md" "secondmate"

pass "fm-brief.sh: every committing brief variant carries the commit conventions"
}

test_herdr_lab_contract_is_explicit_and_complete() {
local home id brief
home="$TMP_ROOT/herdr-lab-home"
Expand Down Expand Up @@ -876,6 +936,7 @@ test_delivery_flags_are_refused_where_they_do_not_apply
test_faster_paths_use_configured_authority_without_stacked_review
test_no_mistakes_dod_wording
test_ship_project_memory_wording
test_every_committing_variant_carries_commit_conventions
test_herdr_lab_contract_is_explicit_and_complete
test_herdr_lab_contract_quotes_foreign_firstmate_path
test_herdr_lab_omission_is_loud_for_ship_and_scout
Expand Down
Loading