Babysit a PR (nubjs/nub)

SkillDev tools

Lets your agent take one pull request through review fixes and CI until it is ready to merge.

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 Babysit a PR (nubjs/nub) skill

About this capability

Bring one nubjs/nub pull request to merge-readiness — pull the inline reviews, verify each finding against the code, re-verify every fix round locally, fix CI, and loop. Invoke (via the Skill tool) when asked to babysit a PR, to get one merge-ready, or when you own a PR and are waiting on reviews or

What this skill tells your AI

The instructions your AI receives, as published by nubjs/nub in .claude/skills/babysit/SKILL.md and read by ahel’s review.

Loop: pull reviews → verify each finding → fix → re-verify locally → push → repeat. CI comes ONCE, at the end: PR CI is opt-in, so a push starts nothing and the run is requested with gh pr edit <n> --add-label ci when the head is final.

Babysit ends at merge-ready. Report that state and stop; the merge is the maintainer's. Only an instruction to babysit it to merge authorizes one — and that phrasing delegates the readiness judgment too, so decide against the criteria below instead of asking.

Reviews

Two bots review within minutes of every push: pullfrog, which posts a top-level review plus inline threads with a <details> write-up per finding, and copilot-pull-request-reviewer. The maintainer outranks both. A PR carrying no review was merged before they ran rather than approved by them, and only the review list distinguishes those.

The gh pr view --json reviews,comments form silently omits inline pulls/{n}/comments, which is where the actionable findings are. Use scripts/pr-reviews.ts — one GraphQL round trip for reviews, inline threads (id, resolved/outdated state, file:line) and PR conversation:

nub scripts/pr-reviews.ts <pr> | jq '.reviewThreads[] | select(.isResolved | not)'

Triage

Skip resolved and outdated threads first — an outdated one anchors a line a later push already rewrote.

Every finding is a hypothesis. Verify it against the code before acting; a confident write-up is the one that gets acted on unchecked. Null guards, "just in case" branches, and try/catch around code that cannot throw are the slop shape AGENTS.md names — reject those by default.

Reject with one factual line on the thread saying what you checked. Never ignore silently, and never reply conversationally to a bot. Load the prose-writing skill before writing any comment. Resolve each thread you address:

gh api graphql -f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' -F id=<thread-id>

Fix rounds

A review-driven fix earns the same gate as the original change. Run make verify. For a behavior change, sweep adversarial fixtures against the branch's MERGE-BASE build (ad-hoc-test) — a run that only re-confirms the reported case tests your intent, not your fix. Escalate to the impact-analysis skill when the fix widened the blast radius. A one-line typo fix skips both.

Then push. Pushing is free — PR CI is opt-in and nothing fires until it is asked for — so push each round as it lands and hold the CI request until the review loop is done. A requested run is roughly five workflows across eight platforms, and asking round after round is what starves the shared runner pool.

CI

Ask for the run, then watch it. Both steps — the request is not optional, and until it lands the pull request has no checks at all:

gh pr edit <N> --add-label ci      # requests CI against the current head; the label is removed again immediately
nub scripts/ci-watch.ts --pr <N> --required "CI gate" --timeout 90

Push a further commit after that and the run you were watching is stale — its checks belong to the old head, so ask again. ci-watch will not cover for a forgotten request: an empty or all-skipped rollup reports as pending, never green.

The CI gate job is an if: always() aggregator over every path-gated job, so it registers LAST: fifty green checks with it still pending means the run is not done. A raw gh pr checks --watch exits 0 while the run is queued with no jobs registered, so watch through scripts/ci-watch.ts.

Diagnose red with ci-triage; a run whose rollup is cancelled can hold a job that failed, so the run-level conclusion misses real red.

Fix only what this PR caused, and never edit a workflow to make a check pass. A merge-blocking failure that looks unrelated is often a stale base — merge main in and re-run. The heavy legs fail for environment reasons too, so read the job log before calling one a regression:

Docker smoke · Windows matrix · daily-driver · native-deps

Stacked PR. After a rebase plus gh pr edit --base main, a LOW check count is a FALSE green. The --base edit fires no synchronize event, so every workflow gated on pull_request: branches: [main] never runs. Force the real matrix with gh pr close <N> && gh pr reopen <N>, then wait for it — a Rust PR carries around sixty checks.

Merge-ready

  • Mergeable: no conflicts, base current.
  • The CI gate check is green, or every failure is investigated and written up as unrelated.
  • Every valid finding is addressed, or rejected with reasoning on the thread.
  • Threads resolved.
  • The body carries Closes #N if the PR resolves an issue. Without it the issue stays silently open after the merge; gh pr edit <N> --body fixes it.

Report that state and stop here, unless the instruction was to merge.

Merging

The Main ruleset blocks update on main, so a plain merge fails with the base branch policy prohibits the merge, and auto-merge is disabled repo-wide. That ruleset sets no required status checks either, so nothing server-side stops a red merge. The flag below bypasses the protection rule, not the judgment — confirm CI gate yourself first.

gh pr merge <N> --squash --admin
git -C <shared-tree> fetch origin && git -C <shared-tree> merge --ff-only origin/main  # never pull --ff-only
make install-dev                                                                       # skip only if the diff was docs-only
git push origin --delete <branch> && git branch -D <branch>
git worktree remove <dir> --force

The shared tree always carries a sibling's uncommitted work, so pull --ff-only runs rebase's precondition check and aborts on any dirty file. For a queue of approved PRs, scripts/merge-cascade.ts does all of the above per entry.

Signals

GitHub stars
4k
Forks
60
Last commit
Sep 2026
Hacker News mentions
6
Advanced
Catalog kind
skill
Gateway key
babysit-nubjs
Source
github.com/nubjs/nub