From dev-tasks
Orchestrator-side merge-polling loop for any PR the main session didn't push itself — subagent-produced PRs (most common), multi-agent fan-out (parallel subagents), or recovery from a prior session. Single-agent main-session work uses /ship-pr Phase 6.6 autonomous merge instead.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dev-tasks:babysit-prsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Read `.claude/project-config.json`. Extract `git.defaultBase` (PRs polled here) and `git.hotfixBase` (PRs here require human merge).
Read .claude/project-config.json. Extract git.defaultBase (PRs polled here) and git.hotfixBase (PRs here require human merge).
Subagents can't poll CI — they're one-shot. After a subagent runs /ship-pr and hands off, someone must handle the merge. That's this skill, run by the main session.
Three use cases per .claude/rules/agent-autonomy.md:
/ship-pr → SendMessage handoff → main session runs /babysit-prs.Single-agent main-session work uses /ship-pr Phase 6.6 autonomous merge — no /babysit-prs needed.
$hotfixBase (human merge per release-flow.md)gh pr list --base $defaultBase --state open --json number,title,headRefName,updatedAt,mergeStateStatusstate=MERGED → skipstate=OPEN + mergeStateStatus=CLEAN → ready to mergeOPEN + UNSTABLE → CI/checks in flight; inspect via gh pr view {N} --json reviews,comments (often = required-check missing rather than failed)OPEN + BLOCKED → real CI failure or missing approvalOPEN + DIRTY → merge conflict; needs rebaseOPEN + UNKNOWN → recheck in 30sFor each PR at CLEAN (or UNSTABLE-but-ready per latest review verdict):
gh pr view {N} --json comments — latest claude author comment. Positive verdicts: "ship-ready", "ship as-is", "no BLOCKERs", "all checks pass", "Self-Review PASSED", "verdict: green", or 🟢. If BLOCKERs surfaced → Phase 2b.gh pr view {N} --json body | grep "Monday\.com Task".gh pr merge {N} --admin --squash. NEVER --delete-branch — gh tries to delete the local tracking branch by switching cwd's checkout to $defaultBase, which fails with fatal: '$defaultBase' is already used by worktree and can corrupt the active task's branch state in a worktree session.git fetch --prune origin. Drops the stale ref. Safe from any worktree.gh pr view {N} --json mergeCommit --jq .mergeCommit.oid.Triage per finding:
| Finding | Action |
|---|---|
| <10 lines, low-risk, single-file | Inline fix from orchestrator in .claude/worktrees/feat-<slug>/ |
| Multi-file, requires tests, or > ~30min | Spawn fixup subagent via Agent({ run_in_background: true }) with surgical brief |
| Genuinely incorrect Claude verdict | Decline via gh pr comment {N} --body ... |
| Architectural — needs human input | TASK_STUCK + SendMessage user OR file retro |
Inline-fix flow: cd to worktree → edit → quick sanity check → git add . && git commit -m "fix: address round-N BLOCKER — <summary>" → git push → re-arm Phase 6 Monitor for round N+1.
Fixup subagent: write a surgical prompt naming the worktree path, branch, PR, the BLOCKER excerpt, the fix directive, and standard rules (no /pickup-task, no merge, no full /ship-pr cycle — just fix + push + report). Spawn with Agent({ subagent_type: 'general-purpose', run_in_background: true }). Estimate 5–15 min.
After fixup pushes, re-arm Phase 6 Monitor for round N+1. Loop terminates when round-K is READY.
For each freshly-merged PR (if MCP up):
getTask({ itemId: taskId, format: "json" }) — read state.sprints lacks active sprint: updateTask({ itemId, sprintId: <active> }) (via listSprints({ activeOnly: true })).updateTask({ itemId, prLink, branch, githubLink, demoUrl }).Waiting for UAT:
createTaskUatDoc({ taskId, markdown }) from PR body + ACmanageSubtasks({ parentItemId, operations }) with actualHourscreateUpdate({ itemId, body: HTML }) summarizing merge.MCP down: capture state inline as checklist; defer reconciliation; catch up immediately on recovery.
For each merged PR:
branch.replace('/', '-') → .claude/worktrees/feat-<slug>git worktree remove --force <path> (--force because remote branch deleted by merge)git branch -D <branch>Batch: bash .claude/scripts/worktree-audit.sh --remove -y cleans every DONE worktree.
For each subagent whose PR merged: SendMessage({ to: <agent>, message: { type: "shutdown_request", reason: "PR #{N} merged at {time}. Work complete." } }).
More PRs/subagents pending → stay. Queue empty + no agents working → end session.
Use a Monitor that evaluates current state on first iteration (so an already-posted verdict is matched immediately) and continues watching for new comments. Match either the ship-ready predicates (READY → orchestrator merges) or BLOCKER predicates (BLOCKER → fix inline or send back). Also break on state=MERGED. Set last_seen="" on init — seeding it with the current latest makes the Monitor watch for a SECOND comment that may never come.
A wait condition that ignores current state and only watches future events is broken — always evaluate current state on first iteration. Don't wait for mergeStateStatus=CLEAN — it can be permanently UNSTABLE from secondary workflow noise.
See plugin/rules/monitor-predicate-pattern.md for the two patterns that govern Monitor emission cadence (transition-only) + post-success action timing (act in the same response — don't narrate between Monitor returning and the merge call).
gh pr merge --auto — flaky against this repo's CI (UNSTABLE noise blocks auto-merge). Use --admin --squash.main — hotfix PRs require human merge.| Symptom | Cause | Fix |
|---|---|---|
gh pr merge "branch is checked out" | Worktree still has the branch | Force-remove worktree, then merge with admin |
| "PR already merged" | Status update lag from prior tick | Verify via gh pr view --json state; skip to reconciliation if MERGED |
updateTask 404 on subtask IDs | Subtasks on different board | Use manageSubtasks({ parentItemId, operations }) |
| Monday MCP "Server not found" | OAuth session switched | Defer; capture queue inline; retry on MCP recovery |
CLEAN but --admin fails | Branch protection requires a check the agent didn't see | Check gh pr checks {N} for blocker; add via PR body edit |
Keep status lines short:
Sweeping PR queue (N open targeting staging):
#283 feat/foo — CLEAN → merging
#285 feat/bar — UNSTABLE (claude-review pending) → skipping
#286 feat/baz — DIRTY (conflict) → escalating
Merged: #283 at {SHA}, Monday #2915513137 → Waiting for UAT
Next sweep: 5min, or when agent notifies
/ship-pr Phase 6.6 — main-session autonomous merge.claude/rules/release-flow.md — branching + merge policy.claude/rules/task-lifecycle.md — status transitions.claude/scripts/worktree-audit.sh — batch worktree cleanupnpx claudepluginhub step-network/dev-tasks --plugin dev-tasksGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.