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
10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,17 +427,25 @@ Empty polls, elapsed waiting time, and "still no change" are tool bookkeeping, n
bin/fm-watch-arm.sh # safe verified re-arm; run as harness-tracked background; no-ops if healthy
bin/fm-watch-arm.sh --restart # home-scoped forced restart; never a broad pkill
bin/fm-watch.sh # the watcher itself; exits with: signal|stale|check|heartbeat
bin/fm-supervise.sh # read-only operational checklist and firstmate.supervision.v1 JSON model
bin/fm-wake-drain.sh # drain queued wake records at turn start
```

`bin/fm-supervise.sh` is passive and may be used during heartbeat review or recovery when current next actions are unclear.
It reads state/status files, tmux liveness, treehouse status, git worktree state, and GitHub PR/status data through `gh-axi`, then emits either text, `--json`, or `--schema`.
It must not be treated as approval or automation: it never drains wakes, edits backlog, sends tmux input, changes git or treehouse state, arms the watcher, tears down work, merges PRs, or changes GitHub.
Use `--include-ok` only when routine watch items are useful, `--no-default-reminders` to omit the built-in Firstmate PR `https://github.com/kunchenguid/firstmate/pull/68`, and repeat `--external-pr <url>` for extra external PR reminders.
The JSON contract is `firstmate.supervision.v1` with `read_only: true`, source health, summary counts, checklist items, task records, worktree records, and external reminders.
GitHub read failures are model data, not command failure: affected PRs become unknown and `sources.github.ok=false`.

On wake, in order of cheapness:

1. Read the reason line and drain queued wake records with `bin/fm-wake-drain.sh`.
2. `signal:` read the listed status files first; a wake lists every signal that landed within the coalescing grace window (e.g. a status write plus the same turn's turn-end marker), and each is ~30 tokens and usually sufficient.
3. `stale:` the crewmate stopped without reporting; peek the pane (`bin/fm-peek.sh <window>`) to diagnose.
If the pane is waiting, looping, confused, or unresponsive, load `stuck-crewmate-recovery`.
4. `check:` a per-task poll fired (usually a merge); act on it.
5. `heartbeat:` review the whole fleet: skim each window's status file, peek panes that look off, check PR-ready tasks for merge, reconcile data/backlog.md, then re-arm the watcher.
5. `heartbeat:` review the whole fleet: skim each window's status file, run `bin/fm-supervise.sh` when a read-only checklist would clarify next actions, peek panes that look off, check PR-ready tasks for merge, reconcile data/backlog.md, then re-arm the watcher.
A heartbeat with no captain-relevant change is internal; do not report that the fleet is unchanged.

Heartbeats back off exponentially while they are the only wakes firing (600s doubling to a 2h cap - an idle fleet stops burning turns); any signal, stale, or check wake resets the cadence to the base interval.
Expand Down
55 changes: 55 additions & 0 deletions bin/fm-supervise.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# Print a read-only Firstmate operational supervision checklist.
set -eu

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=bin/fm-supervision-model.sh
. "$SCRIPT_DIR/fm-supervision-model.sh"

MODE=text
INCLUDE_OK=0
DEFAULT_REMINDERS=1
EXTERNAL_PRS=""

while [ "$#" -gt 0 ]; do
case "$1" in
--text)
MODE=text
;;
--json)
MODE=json
;;
--schema)
MODE=schema
;;
--include-ok)
INCLUDE_OK=1
;;
--no-default-reminders)
DEFAULT_REMINDERS=0
;;
--external-pr)
shift
if [ "$#" -eq 0 ]; then
fm_supervision_usage >&2
exit 2
fi
EXTERNAL_PRS="${EXTERNAL_PRS:+$EXTERNAL_PRS }$1"
;;
--help|-h)
fm_supervision_usage
exit 0
;;
*)
fm_supervision_usage >&2
exit 2
;;
esac
shift
done

export FM_SUPERVISE_INCLUDE_OK="$INCLUDE_OK"
export FM_SUPERVISE_DEFAULT_REMINDERS_ENABLED="$DEFAULT_REMINDERS"
export FM_SUPERVISE_EXTERNAL_PRS="$EXTERNAL_PRS"

fm_supervision_collect_and_emit "$MODE"
Loading