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
8 changes: 8 additions & 0 deletions .agents/skills/project-management/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ The optional `+yolo` posture changes merge authority only and does not change th
Default it off for every project and every posture, and enable it only on the captain's explicit instruction.
`AGENTS.md` section 7 owns the merge-authority contract.

The optional `+external-contract` setting is also independent of delivery and merge posture.
Enable it only for the exact project the captain names, never by analogy or as a registry-wide migration.
Before marking the row, require a non-empty readable private contract at `data/project-contracts/<project>.md`, because `fm-brief.sh` refuses every ship and scout scaffold for a marked project until that file is available in the active home.
`bin/fm-home-seed.sh` carries the contract into a seeded secondmate home alongside the row, and refuses the seed when it cannot, so a home never inherits the marker alone.
Remote provisioning carries the contract in the same manifest record as the row, and refuses before contacting the host when the contract is unavailable, so a remote home is bound by the same rule.
The registry switch belongs here as per-project posture, while the contract content belongs in private `data/` rather than local-choice `config/` or the project's git.
`bin/fm-project-mode.sh`'s header owns the exact annotation and path grammar, and refuses a row carrying any `+token` outside that grammar rather than reading it as unmarked.

## Add or clone an existing project

Confirm the source URL, local project name, delivery posture, and autonomy posture, stating the resolved default for each rather than asking the captain to invent one.
Expand Down
8 changes: 5 additions & 3 deletions .agents/skills/stow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ Approved project-level destinations are not produced by stow: they ship normally
Because this destination is local and untracked, it is also the JIT home for private conditional knowledge that no committed surface may hold.
- An already-existing user-owned local on-demand note with an established trigger, after confirming it is untracked, private, and able to hold the quoted entry.
The pass may add the entry to that existing owner but never creates a new note, skill, or trigger for this purpose.
- A project's existing committed `AGENTS.md`, for project-intrinsic knowledge useful to nearly every session of that project, through a normal crewmate ship task using `bin/fm-ensure-agents-md.sh` and the project's registered delivery mode.
- A project-level skill in the project's own repository, for situation-conditional knowledge within one project, through the same ship-task path.
- An ordinary project's existing committed `AGENTS.md`, for project-intrinsic knowledge useful to nearly every session of that project, through a normal crewmate ship task using `bin/fm-ensure-agents-md.sh` and the project's registered delivery mode.
- An ordinary project's project-level skill, for situation-conditional knowledge within that project, through the same ship-task path.
- For a registry row marked `+external-contract`, neither destination above is allowed; route agent-specific knowledge to firstmate for curation of `data/project-contracts/<project>.md`, and route human-useful facts through normal delivery into human-facing project docs.

Forbidden destinations: any firstmate-repo-tracked skill per the hard rule; firstmate's own `AGENTS.md`, which is always-loaded for every fleet session; `docs/` alone, which is never agent-loaded on demand, though a skill body may point into docs for depth; and any committed surface for private content.
A local skill exists only in this home, so offloading an entry out of `data/captain-shared.md` removes it from every inheriting home's always-injected memory: the proposal must say so, and the default for shared entries is keep.
Expand Down Expand Up @@ -221,7 +222,8 @@ A local skill exists only in this home, so offloading an entry out of `data/capt
- In a primary home, curate shared captain preferences only under the existing primary-authoritative shared-preference contract.
In a secondmate home, route a newly discovered shared preference to the main firstmate through marked status or a document pointer instead of editing the inherited file.
- Project-intrinsic knowledge never goes directly into a project's `AGENTS.md`.
Route it through a normal ship task so a crewmate records it with `bin/fm-ensure-agents-md.sh` and the project's delivery path.
For an ordinary project, route it through a normal ship task so a crewmate records it with `bin/fm-ensure-agents-md.sh` and the project's delivery path.
For a project marked `+external-contract`, return agent-specific knowledge to firstmate for private-contract curation and route human-useful facts into human-facing project docs through normal delivery; never create a project agent file or skill.
- Knowledge general to every Firstmate user belongs in this repo's shared tracked material through the normal branch, no-mistakes, PR, and captain-merge path.
- For task-scoped notes, inspect the item with `tasks-axi show <id> --full`, classify the change as new, duplicate, superseding, or obsolete, then use a considered replacement body through `tasks-axi update <id> --body-file <path>`.
Use `--archive-body` when recoverability matters.
Expand Down
7 changes: 5 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ data/ personal fleet records; LOCAL, gitignored as a whole
captain.md this home's domain-local captain preferences and working style; LOCAL, gitignored, canonical even if harness memory mirrors it, and updated with inspect-then-update
captain-shared.md main-authoritative shared captain preferences propagated read-only to secondmate homes; LOCAL, gitignored, owned by secondmate-provisioning
learnings.md fleet-local operational facts and gotchas; LOCAL, gitignored; dated, evidence-backed, curated, and updated with inspect-then-update - rewrite and prune rather than append forever, the same contract as captain.md; created lazily, absent until this home has a learning to store
projects.md thin fleet navigation registry recording each project's standing delivery posture; firstmate-private, parsed for mechanical sync and seeding by fm-project-mode.sh (section 6)
projects.md thin fleet navigation registry recording each project's standing delivery posture and opt-in external-contract setting; firstmate-private, parsed by fm-project-mode.sh (section 6)
project-contracts/ complete private contract snapshots for projects opted into external-contract mode; one <project>.md file per marked registry row
secondmates.md local and remote secondmate routing table; firstmate-private, maintained by the secondmate seed helpers (section 6)
<id>/brief.md per-task crewmate brief, or per-secondmate charter brief when kind=secondmate
<id>/report.md scout task deliverable, written by the crewmate; survives teardown
Expand Down Expand Up @@ -257,11 +258,12 @@ Route durable knowledge to its most specific owner:
- Captain preferences shared across secondmate domains belong in the primary home's `data/captain-shared.md` under the `secondmate-provisioning` contract.
- Fleet-local operational facts belong in curated, home-local `data/learnings.md`.
- Task-scoped notes belong with the backlog item, and investigation findings belong in the scout report.
- Knowledge useful to almost every contributor to one project belongs in that project's committed `AGENTS.md`.
- Knowledge useful to almost every contributor to one project belongs in that project's committed `AGENTS.md`, unless that registry row opts into external-contract mode.
- Knowledge general to every firstmate user belongs in this repo's shared tracked surface.

Firstmate never writes a project's `AGENTS.md` directly.
A crewmate creates or updates it lazily through the project's selected delivery path, using `bin/fm-ensure-agents-md.sh` and preferring pointers to authoritative sources over copied detail.
For a project explicitly marked `+external-contract` in `data/projects.md`, the complete private contract lives at `data/project-contracts/<project>.md`; every ship and scout brief embeds its snapshot under an explicit prohibition against reproducing it on any published surface, and refuses generation when it is absent, empty, or unreadable, while durable agent-specific knowledge returns through firstmate instead of entering that project's git.
Keep fleet delivery posture and captain-private strategy out of project memory.
When the captain invokes `/stow`, load the `stow` skill for its memory curation, knowledge routing, and persistence of the open work records this session is holding; it files and corrects only the open work that session is holding, and never reconciles the backlog against repository or PR reality.

Expand Down Expand Up @@ -526,6 +528,7 @@ Keep additions task-specific rather than repeating lifecycle instructions, and a

Every ship brief must retain the worktree-isolation assertion and stop if launched in the primary checkout.
If a ship task touches firstmate's shared tracked material, explicitly require `firstmate-coding-guidelines` before editing.
For an externally contracted project, preserve the scaffold's inline contract snapshot and its instruction to return agent-specific knowledge through firstmate rather than creating project agent files.
If a task will drive Herdr lifecycle behavior, scaffold with `--herdr-lab`; if that need appears after an unguarded scaffold, stop and regenerate rather than adding commands by hand.
The generated Herdr contract must use a named non-`default` isolated lab and its guarded helper for every lifecycle action.

Expand Down
110 changes: 94 additions & 16 deletions bin/fm-brief.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
# omitted contract cannot be silent.
# For ship tasks, --mode is REQUIRED and shapes the definition of done. Firstmate
# resolves it per task at intake (AGENTS.md section 7); data/projects.md holds the
# captain's standing posture as context, and this script never reads it:
# captain's standing delivery posture as context, and this script never reads that
# posture. It reads only the independent +external-contract project setting:
# no-mistakes implement -> /no-mistakes pipeline -> PR -> configured merge authority
# direct-PR implement -> push + open PR via gh-axi (no pipeline) -> configured merge authority
# local-only implement on branch, stop and report "ready in branch" (no push/PR);
Expand All @@ -58,11 +59,18 @@
# Every scaffold also carries the steering-inbox receive-and-ack section:
# process state/<id>.inbox/*.msg in order and acknowledge each by moving it to
# handled/ (record, doorbell, and ladder owned by bin/fm-task-inbox-lib.sh).
# Ship tasks include a project-memory section so durable project-intrinsic
# learnings can be committed to AGENTS.md through the project's delivery path;
# it carries the AGENTS.md authoring bar (widely useful knowledge only, pointers
# over copied detail) and has the crewmate add the fm-ensure-agents-md.sh
# self-governance section when a touched project AGENTS.md lacks it.
# Ship tasks ordinarily include a project-memory section so durable
# project-intrinsic learnings can be committed to AGENTS.md through the project's
# delivery path. For a registry row carrying +external-contract, ship and scout
# briefs instead embed the complete data/project-contracts/<repo>.md snapshot,
# fail before writing the brief when it is absent, empty, or not readable in
# full (a NUL byte or a short read would truncate the snapshot), and the
# ship brief routes durable agent knowledge back through firstmate rather than
# asking the worker to create agent-directed files in the project. The snapshot
# carries an explicit publication prohibition beside it, and a ship brief is only
# left on disk once its delivery marker reads back (through bin/fm-dod-lib.sh, the
# reader bin/fm-spawn.sh uses) as the mode this scaffold was asked for, so no
# contract's bytes can shadow or fake that marker.
# Refuses to overwrite an existing brief.
set -eu

Expand Down Expand Up @@ -179,7 +187,6 @@ fi

BRIEF="$DATA/$ID/brief.md"
[ -e "$BRIEF" ] && { echo "error: $BRIEF already exists" >&2; exit 1; }
mkdir -p "$DATA/$ID"

shell_quote() {
printf "'"
Expand All @@ -204,6 +211,7 @@ EOF
INBOX_SECTION=${INBOX_SECTION%$'\n'}

if [ "$KIND" = secondmate ]; then
mkdir -p "$DATA/$ID"
SECONDMATE_PROJECTS=""
idx=1
while [ "$idx" -lt "${#POS[@]}" ]; do
Expand Down Expand Up @@ -301,6 +309,51 @@ fi

REPO=${POS[1]}

EXTERNAL_CONTRACT_PATH=$(FM_HOME="$FM_HOME" FM_DATA_OVERRIDE="$DATA" \
"$SCRIPT_DIR/fm-project-mode.sh" --external-contract "$REPO") || {
echo "error: could not resolve external-contract setting for project $REPO from $DATA/projects.md" >&2
exit 1
}
refuse_external_contract() {
echo "error: project $REPO is marked +external-contract but its contract is absent, empty, or unreadable at $EXTERNAL_CONTRACT_PATH${1:+ ($1)}" >&2
exit 1
}
PROJECT_CONTRACT_SECTION=
EXTERNAL_CONTRACT=0
if [ -n "$EXTERNAL_CONTRACT_PATH" ]; then
EXTERNAL_CONTRACT=1
if [ ! -f "$EXTERNAL_CONTRACT_PATH" ] || [ ! -r "$EXTERNAL_CONTRACT_PATH" ] || [ ! -s "$EXTERNAL_CONTRACT_PATH" ]; then
refuse_external_contract
Comment on lines +325 to +326

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Seed external contracts into secondmate homes

Captain, when a local or remote secondmate is provisioned with a marked project, fm-home-seed.sh and fm-remote-home-seed.sh copy the registry row—including +external-contract—but never copy or validate data/project-contracts/<project>.md. This lookup therefore resolves a nonexistent destination-home path, and the new preflight rejects every ship and scout brief in an otherwise successfully provisioned home. Copy or explicitly provision and validate the contract atomically with the marked registry row.

AGENTS.md reference: AGENTS.md:L262-L264

Useful? React with 👍 / 👎.

fi
PROJECT_CONTRACT=
# `read -d ''` stops at the first NUL byte and reports SUCCESS when it finds
# one, so a contract carrying a NUL (or a read that ends early for any other
# reason) would otherwise be snapshotted truncated under a heading promising
# the complete text. A complete read instead hits EOF and returns non-zero, so
# a zero return means the contract is not whole readable text: refuse.
IFS= read -r -d '' PROJECT_CONTRACT < "$EXTERNAL_CONTRACT_PATH" \
&& refuse_external_contract "contract is not readable as text: it contains a NUL byte"
CONTRACT_BYTES=$(wc -c < "$EXTERNAL_CONTRACT_PATH")
SNAPSHOT_BYTES=$(printf '%s' "$PROJECT_CONTRACT" | wc -c)
if [ "$((SNAPSHOT_BYTES))" -ne "$((CONTRACT_BYTES))" ]; then
refuse_external_contract "read $((SNAPSHOT_BYTES)) of $((CONTRACT_BYTES)) bytes"
fi
if [ -z "$PROJECT_CONTRACT" ]; then
refuse_external_contract
fi
IFS= read -r -d '' PROJECT_CONTRACT_SECTION <<EOF || true
# Project operating contract
The following is the complete external contract snapshot for project $REPO at brief generation time.
It is firstmate-private and stays inside this task: follow it, but never reproduce, quote, paraphrase, or summarize any part of it, or the fact that it exists, on any surface published outside firstmate.
That covers project files, code, comments, commit messages, branch names, pull request titles and bodies, issues and issue comments, review replies, CI or pipeline inputs, and evidence, fixture, or report files you create or push.
When something in it needs to reach firstmate, say so in your status file, which is firstmate-private; when a task legitimately needs one of its facts in a published artifact, append \`needs-decision:\` and stop rather than deciding to publish it yourself.

$PROJECT_CONTRACT

EOF
fi
mkdir -p "$DATA/$ID"

if [ "$HERDR_LAB" -eq 1 ]; then
HERDR_LAB_HELPER=$(shell_quote "$FM_ROOT/bin/fm-herdr-lab.sh")
# shellcheck disable=SC2016 # single quotes are deliberate: these lines are literal brief text whose backtick-wrapped $(...) and "$HERDR_LAB_SESSION" snippets must reach the reading agent verbatim, not expand at scaffold time; only the '"$VAR"' break-outs interpolate.
Expand Down Expand Up @@ -349,7 +402,7 @@ You are a crewmate: an autonomous worker agent managed by firstmate. Work on you

$TASK_SECTION

$HERDR_SECTION
$PROJECT_CONTRACT_SECTION$HERDR_SECTION

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve external-project rules when promoting scouts

Captain, when a marked scout is promoted in place, its original scaffold contains the contract snapshot but not the # External project knowledge section, while fm-promote.sh adds only generic ship instructions and the definition of done. The resulting ship worker is never told not to modify AGENTS.md, CLAUDE.md, or agent skills, nor to return durable agent knowledge through firstmate, so this supported lifecycle can commit exactly the files external-contract mode is intended to prevent. Include these rules in the marked scout scaffold so they survive promotion, or add them during promotion.

AGENTS.md reference: AGENTS.md:L522-L524

Useful? React with 👍 / 👎.


# Setup
You are in a disposable git worktree of $REPO, at a detached HEAD on a clean default branch.
Expand Down Expand Up @@ -416,12 +469,30 @@ case "$MODE" in
esac
DOD=$(fm_dod_block "$MODE" "$ID") || exit 1

if [ "$EXTERNAL_CONTRACT" -eq 1 ]; then
IFS= read -r -d '' PROJECT_MEMORY_SECTION <<'EOF' || true
# External project knowledge
Do not create or modify `AGENTS.md`, `CLAUDE.md`, agent skills, agent memories, or other agent-directed operating files in this project.
Return durable agent-specific project knowledge to firstmate in your final status so firstmate can route it to the private external contract.
Put human-useful product, developer, operator, and safety facts in the project's human-facing documentation only when that documentation is part of this task's accepted scope.
EOF
else
IFS= read -r -d '' PROJECT_MEMORY_SECTION <<EOF || true
# Project memory
If \`AGENTS.md\` or \`CLAUDE.md\` already exists, or if this task produced durable project-intrinsic knowledge, run \`$FM_ROOT/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\` 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.
EOF
fi

cat > "$BRIEF" <<EOF
You are a crewmate: an autonomous worker agent managed by firstmate. Work on your own; do not wait for a human.

$TASK_SECTION

$HERDR_SECTION
$PROJECT_CONTRACT_SECTION$HERDR_SECTION

# Setup
You are in a disposable git worktree of $REPO, at a detached HEAD on a clean default branch.
Expand Down Expand Up @@ -460,13 +531,20 @@ $RULE1

$INBOX_SECTION

# Project memory
If \`AGENTS.md\` or \`CLAUDE.md\` already exists, or if this task produced durable project-intrinsic knowledge, run \`$FM_ROOT/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\` 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.

$PROJECT_MEMORY_SECTION
$DOD
EOF
# The delivery marker's authority must not depend on the embedded contract's
# bytes. A contract is prose about a project's delivery rules, so it can plausibly
# carry a "Delivery contract: mode=..." line of its own, and bin/fm-spawn.sh
# refuses or agrees on whatever it reads back. Assert here, through the same owner
# (bin/fm-dod-lib.sh) that spawn reads with, that this brief reads back as the mode
# this scaffold was asked for, so no brief whose contract shadows, moves, or fakes
# the marker is ever left on disk for a spawn to find.
RECORDED_MODE=$(fm_brief_delivery_mode "$BRIEF")
if [ "$RECORDED_MODE" != "$MODE" ]; then
rm -f "$BRIEF"
echo "error: refusing to leave $BRIEF on disk: its delivery contract reads back as ${RECORDED_MODE:-none}, not the requested mode=$MODE" >&2
exit 1
fi
echo "scaffolded: $BRIEF (ship, mode=$MODE; replace {TASK} and {FIRSTMATE_SPEC})"
Loading