PR Babysitter

SkillDev tools

Babysit a GitHub pull request after creation by continuously polling CI checks/workflow runs, new review comments, and mergeability state until the PR is ready to merge (or merged/closed). Diagnose failures, retry likely flaky failures up to 3 times, auto-fix and push branch-related issues when appropriate, and stop only when user help is required (e.g. CI infrastructure issues, exhausted flaky retries, or ambiguous/blocking review feedback). Use when the user asks to monitor a PR, watch CI, handle review comments, or keep an eye on failures and feedback on an open PR.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the PR Babysitter skill

What this skill tells your AI

The instructions your AI receives, as published by rock3r/spectre in .agents/skills/babysit-pr/SKILL.md and read by ahel’s review.

Monitor a PR persistently until one of the terminal states is reached:

  • PR merged or closed
  • CI fully green, no unaddressed review comments, no merge conflicts
  • A situation requiring user intervention

Inputs

  • No PR argument — infer from current branch (--pr auto)
  • PR number — e.g. 123
  • PR URL — e.g. https://github.com/ADUX-sandbox/Compose-Pi/pull/123

Core workflow

  1. Before running any script, output a single line so the user knows which PR this conversation is tracking — e.g. Babysitting PR [#123](https://github.com/ADUX-sandbox/Compose-Pi/pull/123). Resolve the PR number/URL from the user's input or the current branch first if needed.
  2. Start with --once (default) — it blocks until something needs your attention, then returns.
  3. Run the watcher to snapshot PR/CI/review state.
  4. Inspect the actions list in the JSON output.
  5. Diagnose CI failures — classify as branch-related (fix and push) vs. flaky (retry).
  6. Process actionable review comments from trusted humans and Codex.
  7. Verify mergeability on each loop.
  8. After any push, relaunch --watch in the same turn.
  9. Continue until a terminal stop condition is reached.

Key commands

# Wait until something needs attention, then return one snapshot (default)
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr auto --once

# Instant snapshot of current state (no waiting)
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr auto --snapshot

# Continuously poll, emitting JSONL snapshots (for streaming-capable consumers)
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr auto --watch

# Trigger a rerun of failed jobs for the current SHA
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr auto --retry-failed-now

# Explicit PR number or URL
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr 42 --once
python3 .agents/skills/babysit-pr/scripts/gh_pr_watch.py --pr https://github.com/ADUX-sandbox/Compose-Pi/pull/42 --snapshot

Stop conditions

actions valueMeaning
stop_pr_closedPR was merged or closed — done
stop_ready_to_mergeCI green, no blocking reviews, no conflicts
stop_exhausted_retriesFlaky reruns hit the retry limit — user must investigate
stop_non_retryable_failureTerminal failure is not in retry-eligible workflows — diagnose/fix before continuing
stop_session_timeout--max-session-minutes elapsed (default 90 min) — stop and report
diagnose_hung_checkA pending check has exceeded its hung threshold (30 min) — stop and report
diagnose_merge_conflictPR is merge-conflicted (CONFLICTING / DIRTY) — resolve conflicts before waiting on checks
diagnose_branch_behindPR head is BEHIND the base branch — update the branch (rebase or merge base) before waiting on checks; stop_ready_to_merge is never emitted while behind
diagnose_skipping_checksOne or more checks completed with neutral/skipping — investigate why
wait_codexCodex is still reviewing (👀 reaction present on the PR) — do not push or merge

Keep polling when CI is running (idle), when new review items arrive (process_review_comment), when Codex is still reviewing (wait_codex), or when CI is green but the PR is awaiting approval.

Post-merge cleanup (when stop_pr_closed and PR is merged)

After a PR is merged, clean up the local environment automatically:

  1. If currently on the PR branch, switch away first (for example to main):

    git checkout main
    
  2. Delete the local branch (squash merges leave it unmerged by default):

    git branch -D <head_branch>
    
  3. Remove the git worktree, if the branch was checked out in one:

    # Find worktrees for this branch
    git worktree list
    # Remove if found (adjust path as needed)
    git worktree remove /path/to/worktree
    

How to detect a worktree: run git worktree list and check if any entry's branch matches the PR's head_branch. If the current working directory IS the worktree, cd to the main checkout first before removing it.

Only delete the local branch and worktree — never touch remote branches (the remote is already deleted by GitHub's "delete branch on merge" setting or the --delete-branch flag used at merge time).

Skip silently if the branch or worktree doesn't exist locally.

Push discipline — batch all fixes before pushing (cost control)

Each push triggers new Codex runs. Never push until all of the following are true:

  1. ./gradlew check passes locally (no CI failures to fix after the push).
  2. Codex is not still reviewing — so its comments, if any, can be collected and fixed in the same push.
  3. You have incorporated all currently visible actionable Codex and human review comments into the pending local fix batch.

After pushing the fix batch, resolve all bot threads on GitHub (or reply + resolve when no code change is needed). No open bot threads should remain when the PR is merged.

Workflow when fixes are needed:

  1. Collect all outstanding issues: failed CI logs + any Codex or human review comments already posted.
  2. Fix everything locally in one pass.
  3. Run ./gradlew check to confirm green.
  4. Only then push — one push per fix cycle.

If a bot finishes while you are mid-fix and posts new comments, incorporate those fixes into the same commit before pushing.

Conflict + review-bot batching strategy (use this when PR shows CONFLICTING/DIRTY)

When GitHub reports merge conflicts while Codex/CI is still running:

  1. Do not push immediately. Wait until Codex is no longer reviewing.
  2. Snapshot latest status/comments.
  3. If conflict remains, rebase branch onto origin/main (or merge main if repo policy prefers).
  4. Resolve conflicts and in the same fix cycle apply all actionable Codex and human review comments.
  5. Run ./gradlew check.
  6. Push once.

Rationale: this avoids paying for multiple Codex reruns and prevents a ping-pong where a conflict-fix push is immediately followed by a second bot-fix push.

Codex merge gate (mandatory)

Never merge until Codex reports clean.

Cursor Bugbot and CodeRabbit have both been removed and no longer gate anything. A leftover check from either on an old PR is now treated like any other check: if it completes neutral/skipping it shows up under diagnose_skipping_checks, not as a dedicated gate. CodeRabbit comments are no longer surfaced as actionable review items either.

Codex (emoji reaction)

Codex does not use a CI check. Instead it uses emoji reactions on the PR:

  • 👀 reaction present from chatgpt-codex-connector[bot] → Codex is actively reviewing. The codex_gate.reviewing field will be true and a wait_codex action will be emitted. Do not push or merge.
  • 👀 reaction removed, no new review comments → Codex is satisfied. Proceed.
  • 👀 reaction removed, review comments posted → Codex found issues. Fix them locally and batch them into the next push (see push discipline).

The watcher automatically detects the 👀 reaction via the PR reactions API and surfaces codex_gate in the snapshot.

Decision rules

See references/heuristics.md for the full classification checklist:

  • Branch-related failure: edit the code, collect all other pending issues (Codex, human reviews), fix everything, run ./gradlew check, then push once.
  • Likely flaky/unrelated: rerun via --retry-failed-now; retry budget defaults to 3 per SHA.
    • The watcher only auto-reruns retry-eligible workflows (currently E2E-style workflows).
    • CI/check workflow failures are treated as diagnose/fix-first by default.
  • Ambiguous or requires product decision: stop and ask the user.

Review bots

The watcher surfaces feedback from:

  • chatgpt-codex-connector[bot] — OpenAI Codex (emoji reaction-based code review)
  • cursor[bot] — retired Cursor Bugbot; its login stays in REVIEW_BOT_LOGIN_KEYWORDS so any leftover comment is still surfaced, but it no longer gates anything
  • Trusted humans: authors with OWNER, MEMBER, or COLLABORATOR association

Note: if additional review bots are enabled on the repo (e.g. GitHub Actions summary bots), add their login keyword to REVIEW_BOT_LOGIN_KEYWORDS in scripts/gh_pr_watch.py.

Worktree gotchas

When working from a git worktree, watch out for ktfmt CLI vs Gradle plugin version mismatches and rebases silently reverting fixes. Always run ./gradlew check before pushing — see the pre-push checklist in AGENTS.md.

Choosing a mode based on harness capabilities

The right mode depends on whether the harness can stream bash tool stdout back to the model while the command is still running, or only delivers the final output after exit.

Harness streams tool output to the model (e.g. Claude Code subagents)

Use --watch. The script runs continuously, emitting JSONL snapshots as events. The model sees each snapshot as it arrives and can act on it (retry, fix, merge) without waiting for the script to exit. The script exits on terminal stop conditions.

Harness only returns output after tool exit (e.g. Pi, most tool-use loops)

Use --once (the default). The script blocks internally, polling every 30 seconds, and only returns to the model when something needs agent attention — a CI failure to diagnose, a review comment to process, a merge readiness signal, etc. The model never sleeps blindly; the script handles all waiting. After acting on the result, the model calls --once again to wait for the next event.

Typical agent loop:

  1. Run --once → script blocks until CI finishes, review arrives, etc.
  2. Model reads the snapshot, acts on actions (fix code, retry, merge).
  3. If not terminal, run --once again → repeat.

Quick debugging / one-off inspection

Use --snapshot for an instant point-in-time view with no waiting.

Output format

All modes emit newline-delimited JSON.

  • --once / --snapshot / --retry-failed-now: emit a top-level snapshot/result object where actions is directly available.
  • --watch: emits event envelopes:
    • {"event":"snapshot","payload":{"snapshot":{...},"state_file":"...","next_poll_seconds":30}}
    • {"event":"stop","payload":{...}}

In --watch, read actions from payload.snapshot.actions for snapshot events and payload.actions for stop events.

blocking_review_items contains actionable unresolved inline review comments. When thread-resolution lookup is unavailable, the watcher fails closed: comments whose resolution state is unknown stay blocking regardless of age or commit. While non-empty, stop_ready_to_merge is not emitted.

Example snapshot payload shape (--once / --snapshot, or --watch under payload.snapshot):

{
  "pr": { "number": 42, "head_sha": "abc123", "mergeable": "MERGEABLE", ... },
  "checks": { "pending_count": 0, "failed_count": 1, "passed_count": 8, "skipping_count": 0, "all_terminal": true },
  "failed_runs": [{ "run_id": 123, "workflow_name": "CI", "conclusion": "failure", "retry_eligible": false, ... }],
  "codex_gate": { "reviewing": false, "status": "idle" },
  "hung_checks": [{ "name": "CI", "elapsed_seconds": 1920, "threshold_seconds": 1800 }],
  "new_review_items": [],
  "blocking_review_items": [],
  "actions": ["diagnose_ci_failure", "stop_non_retryable_failure"],
  "retry_state": { "current_sha_retries_used": 0, "max_flaky_retries": 3 }
}

Signals

GitHub stars
35
Last commit
Sep 2026

ahel review

  • K4blow
    destructive-scoped

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Catalog kind
skill
Gateway key
babysit-pr-rock3r
Source
github.com/rock3r/spectre