Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c21fb7e
feat(bin): add bounded main-home PR delivery loop
hsuperman Aug 18, 2026
0135972
no-mistakes(review): Fix PR review retrieval and wake publication ord…
hsuperman Aug 18, 2026
b0c1c4f
no-mistakes(review): Bind review evidence and preserve post-merge tra…
hsuperman Aug 18, 2026
fae80db
no-mistakes(review): Guard merge heads and retire terminal PR state
hsuperman Aug 18, 2026
4b807f8
no-mistakes(review): Prevent repository state collisions and cursor s…
hsuperman Aug 18, 2026
1959740
no-mistakes(review): Scope PR task authority to matching projects
hsuperman Aug 19, 2026
eef297f
no-mistakes(review): Match project paths and snapshot PR evidence
hsuperman Aug 19, 2026
77ff98c
no-mistakes(review): Harden PR delivery evidence and inventory
hsuperman Aug 19, 2026
bab5a8a
no-mistakes(review): Clarify PR check and review clearance
hsuperman Aug 19, 2026
2f60b1c
no-mistakes(review): Harden reviewer evidence consistency and clearance
hsuperman Aug 19, 2026
7b6868d
no-mistakes(review): Require explicit PR-comment request clearance
hsuperman Aug 19, 2026
6f3f203
no-mistakes(review): Narrow reviewer change-request classification
hsuperman Aug 19, 2026
12d4e32
no-mistakes(review): Hold closed snapshots and broader review requests
hsuperman Aug 19, 2026
38b7752
no-mistakes(review): Hold direct reviewer work-request questions
hsuperman Aug 19, 2026
c451923
no-mistakes(review): Clear review requests with explicit resolutions
hsuperman Aug 19, 2026
bb16b7d
no-mistakes(review): Hold subjectless modal reviewer requests
hsuperman Aug 19, 2026
7d11ebb
no-mistakes(review): Narrow modal reviewer work-request holds
hsuperman Aug 19, 2026
741a5a2
no-mistakes(review): Centralize reviewer work-request detection
hsuperman Aug 19, 2026
68f64d4
no-mistakes(review): Separate imperative reviewer request grammar
hsuperman Aug 19, 2026
eb452ee
no-mistakes(review): Refine reviewer request and clearance classifica…
hsuperman Aug 19, 2026
edb260a
no-mistakes(review): Prune eligible and terminal blocked queue rows
hsuperman Aug 19, 2026
e4493c3
no-mistakes(review): Hold recommendation-form reviewer requests
hsuperman Aug 19, 2026
b79685c
no-mistakes(test): Hold inconsistent PR evidence until next scan
hsuperman Aug 19, 2026
1a2b35a
no-mistakes(document): Document PR delivery loop
hsuperman Aug 19, 2026
8c577d2
no-mistakes(lint): Fix ShellCheck warnings in PR delivery scripts
hsuperman Aug 19, 2026
16d1dec
no-mistakes(review): Fix blocked queue green-check fixture
hsuperman Aug 19, 2026
7bacd41
no-mistakes(review): Remove deferred post-merge delivery monitoring
hsuperman Aug 19, 2026
d0fc039
no-mistakes(review): Record PR heads without local worktrees
hsuperman Aug 19, 2026
a451e20
no-mistakes(review): Bind delivery tasks to recorded PR URLs
hsuperman Aug 19, 2026
4ea956c
no-mistakes(review): Consume completed-scan acceleration markers
hsuperman Aug 19, 2026
d9ee5a7
no-mistakes(review): Enforce PR heads at GitHub merge boundary
hsuperman Aug 20, 2026
b52ed3a
no-mistakes(review): Reject symlinked PR delivery state directories
hsuperman Aug 20, 2026
f2cfd43
no-mistakes(review): Retire closed PR state and hold ambiguity
hsuperman Aug 20, 2026
7f4351c
no-mistakes(document): Document guarded delivery merges and deferred …
hsuperman Aug 20, 2026
866b2d6
no-mistakes(lint): Fix ShellCheck issues in PR delivery loop
hsuperman Aug 20, 2026
2e51ee2
no-mistakes: apply CI fixes
hsuperman Aug 21, 2026
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
39 changes: 39 additions & 0 deletions .agents/skills/pr-delivery/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: pr-delivery
description: Agent-only procedure for handling check: pr-delivery wakes from the bounded main-home PR delivery loop. Use on every check: pr-delivery wake to enumerate merge-eligible PRs, merge under configured authority via fm-pr-merge.sh, then defer post-merge orchestration to its owning flow.
user-invocable: false
metadata:
internal: true
---

# pr-delivery

`bin/fm-pr-delivery.sh` discovers open PRs for merge-capable registered projects and classifies each head with live gh evidence.
The watcher and locked session start run its bounded `scan` adjunct; when a merge-eligible PR exists, they queue `check: pr-delivery` with the scan payload.

This skill owns every handling turn for that wake.
Do not invent a parallel PR poll or merge path.

## On wake

1. Read the wake payload from the drain.
It is `merge-eligible: ...` with `project=`, `repo=`, `pr=`, `task=`, `url=`, and `head=` fields.
2. Run `bin/fm-pr-delivery.sh show` when you need the current reason-coded blocked queue for operator context.

## merge-eligible

1. Reconcile the named task with `bin/fm-crew-state.sh` when current state matters.
2. Confirm the PR URL, task id, project, and expected head still match the payload and the blocked queue does not show a stronger hold.
3. Decide merge authority:
- With standing or task `yolo=on`, merge when the scan classified the PR as eligible.
- Otherwise escalate to the captain for explicit merge approval before calling `bin/fm-pr-merge.sh`.
4. Merge only through `bin/fm-pr-merge.sh <task-id> <full-pr-url> --expected-head <payload-head>`.
If the expected-head guard refuses, leave the PR unmerged and let the delivery scan classify the new head.
Never call `gh` or `gh-axi pr merge` directly around that helper.
5. After a successful merge, stop this delivery handling turn.
Project and secondmate fleet sync, validation and ready reporting, and teardown remain outside this delivery loop.

## Holds this scan respects

The scan already blocks on checks, mergeability, review issues, active task blockers, migration evidence, unresolved authority decisions, destructive or real-contact decisions, and missing task linkage.
Do not override a hold the scan reported without new evidence or captain authority.
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,10 @@ Handle actionable wakes as follows:
1. For `signal:`, read the listed event lines first, then reconcile current state only where action depends on it.
2. For `stale:`, inspect the recorded endpoint and load `stuck-crewmate-recovery` for a stopped, looping, confused, or unresponsive worker; a deep-inspection reason also requires current-state and validation-log inspection.
3. For `check:`, act on the named poll result, including merges, Relay events, process-to-event source results, and captain inbox notes; a handled inbox note is also acknowledged with `bin/fm-inbox.sh drain --ack <id>`, or it stays counted as still waiting for firstmate.
`pr-delivery` obligations are handled by loading the `pr-delivery` skill.
4. For `heartbeat:`, review the whole fleet from the structured fleet view, reconcile suspicious tasks and PR state, update the backlog, and never report an unchanged fleet as progress.

When any wake reports a merged PR for a project cloned in this home, refresh that clone through the guarded fleet-sync path.
When a non-`pr-delivery` wake reports a merged PR for a project cloned in this home, refresh that clone through the guarded fleet-sync path.
When Relay-linked work reaches a milestone or terminal state, load `fmx-respond`; before terminal teardown, use its promised-final reconciliation when a typed public commitment exists, otherwise post the final completion follow-up so the link clears even if earlier follow-ups were spent.

A secondmate's idle endpoint is healthy, and parent supervision relies on its routed status rather than treating a quiet pane as stale.
Expand Down Expand Up @@ -538,6 +539,7 @@ These skills are not captain-invocable; load them only at their precise triggers
- `captain-hold-lifecycle` - load before treating an investigation or visual review as complete, before ending a visual review that exposed a captain decision, when recording or routing the captain's answer, and on any `RECORD DIVERGENCE` line from the wake drain.
- `process-event-sources` - load before arming a long-polling source, before registering a deterministic condition->action watch (do X as soon as Y is true), and on any `procevent <adapter> <source-id> <sequence>` check wake.
Never run a registered source's blocking command yourself in a conversational turn.
- `pr-delivery` - load on a `check: pr-delivery` wake to handle a merge-eligible PR from the bounded PR delivery scan.
- `fmx-respond` - load on an `x-mention <request_id>` `check:` wake to handle the mention, on an `x-mode-error ...` `check:` wake to report the Relay configuration blocker, on a `public-followup ...` `check:` wake or a startup-surfaced public commitment, and on any milestone or terminal wake for a Relay-linked task before posting its completion follow-up; relevant only when Relay is on.
- `firstmate-codexapp` - load before coordinating a visible Codex Desktop thread, evaluating a Codex App backend request, or reconciling Codex Desktop host-tool smoke evidence for Firstmate work.
- `firstmate-coding-guidelines` - load before changing firstmate's shared, tracked material, as defined by section 1's list, whether editing directly or briefing a crewmate for a firstmate-repo task.
Expand Down
12 changes: 6 additions & 6 deletions bin/fm-pr-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ fi
"$FM_ROOT/bin/fm-guard.sh" || true

# pr_head is recorded only when the forge's CLI can supply it. gh exposes the
# head commit as a selectable field; plain glab exposes it only inside its JSON
# output, which would need a JSON processor firstmate does not require, so a
# GitLab task records no pr_head. Both consumers already treat it as optional:
# head commit as a selectable field and accepts the canonical PR URL without a
# local repository. Plain glab exposes it only inside its JSON output, which
# would need a JSON processor firstmate does not require, so a GitLab task
# records no pr_head. Both consumers already treat it as optional:
# bin/fm-teardown.sh reads the head from the forge at teardown rather than from
# metadata and falls back to its provider-agnostic content check, and
# bin/fm-review-diff.sh resolves the head from the remote when none is recorded.
# bin/fm-pr-merge.sh reads a GitLab head live at merge time for the same reason,
# and treats a recorded value that disagrees as stale rather than authoritative.
WT=$(grep '^worktree=' "$META" | tail -1 | cut -d= -f2- || true)
PR_HEAD=
if [ "$PROVIDER" = github ] && [ -n "$WT" ] && [ -d "$WT" ] && command -v gh >/dev/null 2>&1; then
if REMOTE_HEAD=$(cd "$WT" && gh pr view "$URL" --json headRefOid -q .headRefOid 2>/dev/null) \
if [ "$PROVIDER" = github ] && command -v gh >/dev/null 2>&1; then
if REMOTE_HEAD=$(gh pr view "$URL" --json headRefOid -q .headRefOid 2>/dev/null) \
&& fm_pr_head_valid "$REMOTE_HEAD"; then
PR_HEAD=$REMOTE_HEAD
fi
Expand Down
Loading
Loading