Skip to content
Closed
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
23 changes: 22 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ state/ volatile runtime signals; gitignored
.watch.lock .wake-queue.lock watcher singleton and queue serialization locks
.hash-* .count-* .stale-* .seen-* .last-* .heartbeat-streak watcher internals; never touch
.last-watcher-beat watcher liveness beacon, touched every poll; fm-guard.sh reads it
sweep.log recurring review sweep run log (cron appends here; section 8)
sweep/ per-run scratch for the review sweep (transient plan files)
.sweep.lock flock guard so two review sweeps never overlap
.no-mistakes/ local validation state and evidence; gitignored
```

Expand Down Expand Up @@ -175,7 +178,8 @@ If a pane shows the exit banner, relaunch with `--continue` to resume the sessio

pi has no permission system - crewmates are always autonomous.
Keep the brief as ONE positional argument - multiple positional args become separate queued messages (fm-spawn's template does this correctly).
Project trust dialog can appear on the first pi run in any not-yet-trusted directory (observed even on clean worktrees); accept with Enter - the decision persists per path in `~/.pi/agent/trust.json`, so later spawns in the same worktree slot skip it.
The launch template passes `--approve`, so pi trusts project-local files for each run and a spawned crewmate never blocks on pi's project-trust dialog - this is what lets the unattended review sweep dispatch pi headlessly.
A pi you launch by hand still shows that dialog on the first run in a not-yet-trusted directory (observed even on clean worktrees); accept with Enter - the decision persists per path in `~/.pi/agent/trust.json`, so later manual runs in the same path skip it.
fm-spawn keeps the turn-end extension in `state/`, outside the worktree, because project-local extension files make the trust gate strictly worse (and pollute the project).
The extension must listen for pi's `turn_end` event, not `agent_end`, so the watcher wakes after each completed turn instead of only when the whole agent run exits.
Environment marker for harness detection: pi sets `PI_CODING_AGENT=true` for its children.
Expand Down Expand Up @@ -448,6 +452,23 @@ Silence is the correct state while a healthy background watcher is waiting.
The worktree and commits persist; this is cheap.
5. Second relaunch fails too: write `failed` to backlog, tell the captain with evidence.

### Recurring review sweep (cron)

`bin/fm-review-sweep.sh` is a standalone, unattended sweep that reviews every open fleet PR on a fixed cadence, independent of the live supervisor. It is designed to run from cron (no firstmate session is required to be live):

```sh
0 */8 * * * /home/boks/Projects/firstmate/bin/fm-review-sweep.sh >> /home/boks/Projects/firstmate/state/sweep.log 2>&1
```
Firstmate installs the crontab line after merge; the script never installs it itself.

Each run: enumerate every open PR across the fleet repos (resolved from `data/projects.md`), exclude drafts and already-approved PRs (`reviewDecision=APPROVED`), fetch CI status per PR, and dispatch a `review-rectify-pi` review in `--push` mode — **review-only, no code edits or fixes** — to each kept PR as a crewmate via `bin/fm-spawn.sh`, bounded to `FM_SWEEP_CONCURRENCY` (default **3**) concurrent reviews. The sweep is flock-guarded (no overlapping runs), best-effort per PR (a single PR's failure never aborts the run; `set -uo pipefail`, no `-e`), and logs a run summary to `state/sweep.log`.

Failing-CI PRs are **kept** (not skipped): their review brief adds an instruction to investigate the CI failure root cause and include a `## CI Failure` section in the posted comment naming the failing job and error.

The `review-rectify-pi` skill already deletes its prior `Review Findings - Rectification Status` comment and posts the fresh one (Phase 9); the sweep relies on that and does not re-implement comment deletion. After each review lands its comment, the sweep parses the recommendation: on a **clean APPROVE** (not CONDITIONAL APPROVE), it transitions the PR's linked Jira ticket (the `MILE-\d+` key from the title/body) to "In Review" via `jira issue move` — composing with the standing Jira rule. Status-only; it never merges.

`--dry-run` enumerates, filters, and prints the plan without dispatching; `--one <owner>/<name>` restricts the run to a single fleet repo (for testing). `FM_SWEEP_CONCURRENCY` and `FM_SWEEP_TASK_TIMEOUT` (default 1800s) tune the run; a review that overruns the timeout is abandoned and left for inspection (window `fm-sweep-*`, worktree, meta) rather than torn down, so an unattended overrun may need manual cleanup. Because it dispatches headlessly, it depends on `fm-spawn`'s headless-launch reliability - `--approve` to clear pi's project-trust gate, stable-worktree detection, and a post-launch verify that the harness binary is actually running (section 4).

## 9. Escalation and captain etiquette

**Talk in outcomes, not mechanics.**
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ The first mate drives these; you rarely need to, but they work by hand too.
| `fm-project-mode.sh` | Resolve a project's delivery mode and `+yolo` flag from `data/projects.md` |
| `fm-merge-local.sh` | Fast-forward a `local-only` project's local default branch after approval |
| `fm-review-diff.sh` | Review a crewmate branch against the authoritative base, with optional `--stat` output |
| `fm-review-sweep.sh` | Unattended cron sweep: review every open fleet PR (review-rectify-pi `--push`, review-only), bounded concurrency, Jira tie-in |
| `fm-watch.sh` | Singleton-safe one-shot watcher; blocks until supervision work is due, queues it durably, then exits with one reason line |
| `fm-wake-drain.sh` | Atomically drain queued watcher wakes before handling supervision work |
| `fm-send.sh` | Send one literal line (or `--key Escape`) to a crewmate window |
Expand Down Expand Up @@ -168,6 +169,8 @@ FM_SIGNAL_GRACE=30 # seconds to coalesce nearby status and turn-end signals
FM_FLEET_SYNC_BOOTSTRAP_TIMEOUT=20 # seconds allowed for bootstrap's best-effort clone refresh
FM_FLEET_PRUNE=1 # set to 0 to skip pruning local branches whose upstream is gone
FM_BUSY_REGEX='esc (to )?interrupt|Working\.\.\.' # busy-pane signatures, extend per harness
FM_SWEEP_CONCURRENCY=3 # max concurrent reviews in the recurring review sweep
FM_SWEEP_TASK_TIMEOUT=1800 # seconds allowed per review in the recurring review sweep
```

## Development
Expand Down
Loading