PR babysitter
GitHub auto-merge holds a PR until readiness is green AND the branch is
up-to-date — but it never updates a BEHIND branch itself (allow_update_branch
only permits the update; nothing calls it). Every squash-merge re-BEHINDs the PRs
queued behind it, so a merge train stalls after the first car unless someone keeps
nudging. That someone is this skill. It is the tail of /automerge, not a
replacement — it never merges anything itself.
One pass
1. Snapshot the board
gh pr list --state open --json number,title,isDraft,mergeStateStatus,autoMergeRequest,statusCheckRollup
2. Per open non-draft PR, in this order
- CONFLICTING → surface it for the human. Never resolve or force anything.
- BEHIND →
gh pr update-branch <N>. If the update errors (usually a
conflict with the new base) → surface as CONFLICT.
- No auto-merge enabled (
autoMergeRequest == null) → check whether a prior
/automerge round left P1 comments with no push since
(gh pr view <N> --json comments,commits):
- P1s still standing → surface, skip. The human fixes; a new push makes it
eligible again.
- Otherwise → run the full
automerge skill pipeline on it (classify →
exempt-enable or gate-review→refute). This may spawn Opus reviewer/refuter
agents — that's the point; classification still fails toward GATE.
- Checks failing (any
statusCheckRollup conclusion FAILURE) → surface with
the failing check's name. Don't auto-fix, don't re-run blindly.
3. Post-merge housekeeping
For PRs that merged since the previous pass (first pass: since session start —
gh pr list --state merged --limit 10 --json number,mergedAt,files):
- Backend delta — if a merged PR touched
functions/**, security/**, or
firestore.indexes.json, run bash tool/pending_deploy.sh rihla-safar. If it
reports pending, say so and point at the deploy-ceremony skill. NEVER
deploy from here — the ceremony needs the user's Firebase auth and their eyes
on the delta.
- Worktree GC —
git worktree list. A non-main worktree is removable ONLY
when ALL of:
- its branch's PR is merged:
gh pr list --head <branch> --state merged --json number,headRefOid is non-empty;
- the worktree HEAD equals that PR's
headRefOid (squash-merge means branch
commits are never ancestors of main — comparing SHAs is the only safe test;
a differing HEAD = commits made after the merge → surface, don't remove);
git -C <worktree> status --porcelain is empty.
Then git worktree remove <path> and delete the local branch. Anything dirty,
unmerged, or ambiguous: leave it and report. Never --force.
4. Report the board
One line per PR: number, title, state, action taken this pass, what it's waiting
on. Plus any pending-deploy reminder and worktrees GC'd/skipped.
/loop pacing
- Any tracked PR has CI running or was just updated → wake in ~270s (stay inside
the prompt-cache window).
- Everything waiting on the human (P1s, conflicts, red CI) or nothing in flight →
1200s+.
- No open PRs, no pending deploy → end the loop and say the board is clear.
Non-negotiables
- Never
gh pr merge without --auto. Only the automerge pipeline enables
merging; this skill never bypasses it — not for "obviously safe" PRs either.
- Never override a P1 stop. A new push = a NEW
/automerge round with fresh
agents (never continue the old reviewer).
- Conflicts, red CI, and deploys belong to the human — surface, don't fix.
- Worktree removal requires merged PR + HEAD==merged SHA + clean tree. When in
doubt, report instead of removing.
1---2name: pr-babysitter3description: Owns the merge tail for Rihla PRs — the stretch between "auto-merge enabled" and "actually merged" that GitHub never finishes on its own. Each pass updates BEHIND branches (auto-merge never self-updates them), runs /automerge on open PRs that lack it, surfaces P1-commented / red-CI / conflicted PRs, checks for pending backend deploys after merges, and GCs worktrees whose PR merged. Use when asked to "babysit the PRs", "watch the merge queue", "/pr-babysitter", or under /loop to run until the board is clear.4---56# PR babysitter78GitHub auto-merge holds a PR until `readiness` is green AND the branch is9up-to-date — but it **never updates a BEHIND branch itself** (`allow_update_branch`10only permits the update; nothing calls it). Every squash-merge re-BEHINDs the PRs11queued behind it, so a merge train stalls after the first car unless someone keeps12nudging. That someone is this skill. It is the tail of `/automerge`, not a13replacement — it never merges anything itself.1415## One pass1617### 1. Snapshot the board1819```bash20gh pr list --state open --json number,title,isDraft,mergeStateStatus,autoMergeRequest,statusCheckRollup21```2223### 2. Per open non-draft PR, in this order2425- **CONFLICTING** → surface it for the human. Never resolve or force anything.26- **BEHIND** → `gh pr update-branch <N>`. If the update errors (usually a27 conflict with the new base) → surface as CONFLICT.28- **No auto-merge enabled** (`autoMergeRequest == null`) → check whether a prior29 `/automerge` round left P1 comments with no push since30 (`gh pr view <N> --json comments,commits`):31 - P1s still standing → surface, skip. The human fixes; a new push makes it32 eligible again.33 - Otherwise → run the full **`automerge`** skill pipeline on it (classify →34 exempt-enable or gate-review→refute). This may spawn Opus reviewer/refuter35 agents — that's the point; classification still fails toward GATE.36- **Checks failing** (any `statusCheckRollup` conclusion FAILURE) → surface with37 the failing check's name. Don't auto-fix, don't re-run blindly.3839### 3. Post-merge housekeeping4041For PRs that merged since the previous pass (first pass: since session start —42`gh pr list --state merged --limit 10 --json number,mergedAt,files`):4344- **Backend delta** — if a merged PR touched `functions/**`, `security/**`, or45 `firestore.indexes.json`, run `bash tool/pending_deploy.sh rihla-safar`. If it46 reports pending, say so and point at the **`deploy-ceremony`** skill. NEVER47 deploy from here — the ceremony needs the user's Firebase auth and their eyes48 on the delta.49- **Worktree GC** — `git worktree list`. A non-main worktree is removable ONLY50 when ALL of:51 1. its branch's PR is merged: `gh pr list --head <branch> --state merged --json number,headRefOid` is non-empty;52 2. the worktree HEAD equals that PR's `headRefOid` (squash-merge means branch53 commits are never ancestors of main — comparing SHAs is the only safe test;54 a differing HEAD = commits made after the merge → surface, don't remove);55 3. `git -C <worktree> status --porcelain` is empty.56 Then `git worktree remove <path>` and delete the local branch. Anything dirty,57 unmerged, or ambiguous: leave it and report. Never `--force`.5859### 4. Report the board6061One line per PR: number, title, state, action taken this pass, what it's waiting62on. Plus any pending-deploy reminder and worktrees GC'd/skipped.6364## /loop pacing6566- Any tracked PR has CI running or was just updated → wake in ~270s (stay inside67 the prompt-cache window).68- Everything waiting on the human (P1s, conflicts, red CI) or nothing in flight →69 1200s+.70- No open PRs, no pending deploy → end the loop and say the board is clear.7172## Non-negotiables7374- **Never `gh pr merge` without `--auto`.** Only the `automerge` pipeline enables75 merging; this skill never bypasses it — not for "obviously safe" PRs either.76- **Never override a P1 stop.** A new push = a NEW `/automerge` round with fresh77 agents (never continue the old reviewer).78- Conflicts, red CI, and deploys belong to the human — surface, don't fix.79- Worktree removal requires merged PR + HEAD==merged SHA + clean tree. When in80 doubt, report instead of removing.