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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ state/ runtime records and signals; gitignored
.<id>.open-decisions-cursor per-task byte cursor and folded open-decision set bounding the OPEN DECISIONS scan's cost to new status-log appends; written only by fm-classify-lib.sh's status_open_decisions_incremental, removed by teardown, safe to delete (forces one full re-fold)
.status-presentation-cursor .status-presentation-lock fleet-wide per-task status identity/byte-offset manifest and serialization lock preventing already-presented status lines from being replayed as new; owned by fm-classify-lib.sh, with each task's row retired by teardown
.afk durable away-mode flag; present = sub-supervisor may inject escalations (set by /afk, cleared on user return)
.dream-due durable evidence that an armed dream-due watch fired; written only by bin/fm-dreamer-watch.sh mark-due, never dispatches a dreamer by itself, safe to delete
.watch.lock .wake-queue.lock watcher singleton and queue serialization locks
.claude-autoarm.lock .claude-autoarm-epoch .claude-autoarm-failure-notified .claude-autoarm-failure-alarmed .turnend-claude-blocks .turnend-claude-blocks.lock Claude Stop auto-arm single-flight, epoch, failure-episode, attended-alarm, guard-budget, and budget-lock records; never touch
.cursor-park-owner .cursor-park-owner.lock .turnend-cursor-blocks Cursor stop-hook owner record, publication and commit lock, and bounded repair-nag budget; never touch
Expand Down
102 changes: 100 additions & 2 deletions bin/fm-brief.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@
# of shipping a new one).
# Usage: fm-brief.sh <task-id> <repo-name> --mode <no-mistakes|direct-PR|local-only> [--herdr-lab]
# fm-brief.sh <task-id> <repo-name> --scout [--herdr-lab]
# fm-brief.sh <task-id> <repo-name> --dreamer [--herdr-lab]
# fm-brief.sh <task-id> --secondmate {<project>...|--no-projects}
# --scout writes the scout contract instead: the deliverable is a report at
# data/<task-id>/report.md (no branch, no push, no PR) and the worktree is scratch.
# --dreamer writes the ephemeral dreamer scout contract: the deliverable is a
# proposed immutable memory generation under data/memory/gen/<N>/ plus a dream
# receipt report. The dreamer reads the append-only log and the drop tray,
# never writes published memory in place, never takes the session lock, and
# never addresses the captain. It may be combined with --herdr-lab.
# --secondmate writes a persistent secondmate charter. The project list
# is cloned into the secondmate home, while the natural-language scope
# tells the main firstmate when to route work there; routine churn stays in its own home;
Expand Down Expand Up @@ -125,6 +131,7 @@ for a in "$@"; do
fi
case "$a" in
--scout) KIND=scout ;;
--dreamer) KIND=dreamer ;;
--secondmate) KIND=secondmate ;;
--herdr-lab) HERDR_LAB=1 ;;
--no-projects) NO_PROJECTS=1 ;;
Expand Down Expand Up @@ -154,14 +161,14 @@ if [ "$KIND" = ship ]; then
*) echo "error: --mode must be one of no-mistakes, direct-PR, local-only (got '$MODE')" >&2; exit 1 ;;
esac
elif [ "$MODE_SET" -eq 1 ]; then
echo "error: --mode applies only to ship briefs; a scout delivers a report and a secondmate charter is not a delivery contract" >&2
echo "error: --mode applies only to ship briefs; a scout or dreamer delivers a report and a secondmate charter is not a delivery contract" >&2
exit 1
fi
[ "${#POS[@]}" -ge 1 ] || { echo "error: task id is required" >&2; exit 1; }
ID=${POS[0]}

if [ "$KIND" = secondmate ] && [ "$HERDR_LAB" -eq 1 ]; then
echo "error: --herdr-lab applies only to crewmate ship or scout briefs" >&2
echo "error: --herdr-lab applies only to crewmate ship, scout, or dreamer briefs" >&2
exit 1
fi

Expand Down Expand Up @@ -380,6 +387,97 @@ echo "scaffolded: $BRIEF (scout; replace {TASK})"
exit 0
fi

if [ "$KIND" = dreamer ]; then
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
You are the DREAMER: an offline memory-consolidation pass for the firstmate home at $FM_HOME.
Your job is to turn tactical records into durable abstractions and to propose a complete new
memory generation, never to report to the captain and never to change what any session already sees.
The \`{TASK}\` placeholder in a normal scout is filled with the specific home, cursor, and generation
number by firstmate; keep to the contract below regardless of that detail.

## Read, and only read
- The append-only log since the last dream cursor: \`state/<id>.status\` tails, \`data/<id>/report.md\`,
\`data/backlog.md\`, \`data/decisions/*.md\`, and the cold archives
(\`data/done-archive.md\`, \`data/note-archive.md\`, \`data/memory-archive.md\`) when a claim is being corrected.
- The in-band candidate tray: everything under \`data/memory/drop/\`.
- The current published memory: the generation \`data/memory/HEAD\` names, plus the compiled catalog.
Do NOT read firstmate's conversation, worker panes, or anything under \`projects/\`.

## Synthesize, do not copy
Distillation is the differentiator. A tactical scrap is \`hz-verify-email-37 timed out in chrome-devtools-axi\`.
A durable abstraction generalises to a session that never heard of this task: \`Under multi-lane contention on this
host, chrome-devtools-axi times out; Playwright is the substitute\`, with a citation. Promote a drop claim only when
it becomes standing knowledge or corrects something already standing; reject the rest.

## Write a new immutable generation
Produce the complete next generation under \`data/memory/gen/<N>/\` (where N is the next integer past the highest
existing generation) containing at minimum \`notes/*.md\` (one atomic claim per note, each with a resolvable citation),
\`core.md\` (the standing constitution, a subset or inspect-then-update of the current core, never a silent deletion),
and the source files the catalog is compiled from. Write only under \`data/memory/\`; never touch \`projects/\`.

## Mechanical verification is mandatory
Before you report done, run \`bin/fm-memory-verify.sh <N>\` on the proposed generation and let its four checks pass
(budget, citations, constitution, diff bounds). If verification fails, revise the generation rather than bypassing it.

# Hard safety contract
1. NEVER take the session lock. The live primary harness holds it; you must never contend for it.
2. NEVER edit published memory in place. Only a new immutable generation plus an atomic \`data/memory/HEAD\`
pointer may change what a session sees, and firstmate owns that pointer swap after grading.
3. NEVER address the captain. Do not escalate to the captain; report only through your status file and your report.
4. NEVER write under \`projects/\` and never read the captain's conversation or worker panes.
5. A single-flight \`state/.dream.lock\` guarantees one dream at a time; never clear or force it.

$HERDR_SECTION

# Setup
You are in a disposable git worktree of $REPO, at a detached HEAD on a clean default branch.
This is an ephemeral DREAMER task: the deliverable is a proposed memory generation under the firstmate home's
\`data/memory/gen/\` plus a dream-receipt report, not a PR and not a chat reply.
The worktree is your laboratory; all scratch work in it is discarded at teardown. Anything worth keeping must
land in the generation or the report.

# Rules
1. Never push to any remote and never open a PR.
2. Stay inside this worktree; the only files you may write outside it are under the home's \`data/memory/\`,
the report, and the status file below.
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}" >> $STATUS_FILE\`
States: working, needs-decision, blocked, $PAUSED_VERB, done, failed.
Each append wakes firstmate, so report sparingly: only phase changes a supervisor
would act on and the needs-decision/blocked/paused/done/failed states. No step-by-step
FYI progress lines; firstmate reads your pane for that.
Use \`$PAUSED_VERB: {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):
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 you (product choices, destructive actions, ask-user findings),
append \`needs-decision: {summary of options}\` and stop. Firstmate will apply the configured authority and reply.
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. On ANY no-mistakes
daemon error, append \`blocked: {the daemon error}\` and stop; only firstmate manages the daemon.

# Definition of done
Write your dream receipt to \`$DATA/$ID/report.md\`: what you read since the cursor, which drop claims you promoted
or rejected and why, the generation number you produced, the citations you used, and the mechanical verification result.
Do NOT publish \`data/memory/HEAD\` yourself; firstmate runs the grader and performs the atomic pointer swap.
Before reporting done, read and follow \`$FM_ROOT/.agents/skills/decision-hold-lifecycle/SKILL.md\` and pass its
shared completion gate for the report and any visual review.
When the generation is written, verified, and the report is complete, append \`done: {generation number} proposed\`
to the status file and stop.
EOF
echo "scaffolded: $BRIEF (dreamer; replace {TASK})"
exit 0
fi

# Ship task: shape Setup / Rule 1 / Definition of done by this task's explicit
# delivery mode, validated above. The generated DOD opens with the fixed
# "Delivery contract: mode=<mode>" line that bin/fm-spawn.sh checks against its own
Expand Down
Loading
Loading