Babysit your own open GitHub pull requests as a tiered fleet loop. The safe default discovers YOUR PRs under the current repo's owner, checks readiness, fixes clear branch-owned issues, and reports, it never resolves threads or merges. Explicit 'worker' tier adds auto-resolving outdated bot threads and gate-proven merges; explicit 'autopilot' adds all authors under the watched owners. Use when asked to babysit, watch, or advance open pull requests as a fleet (the safe tier), to run the worker or autopilot tier by name, or when pairing with /loop for continuous coverage; not for the single-PR lifecycle: prep, create, monitor one PR, or merge (use /pull-request).
Current login: !gh api user --jq .login 2>/dev/null || echo "unknown"
Own open PRs here: !gh pr list --state open --author "@me" --limit 200 --json number --jq 'length' 2>/dev/null || echo "unknown"
Branch and working tree: gather with two separate Bash calls, git branch --show-current then git status --porcelain; treat a failure as an unknown value and carry on. Keep them out of the pre-computed block above: the harness composes that block into one shell invocation, and a worktree-isolated agent refuses a git-bearing compound command. The dated record for that composition claim is the worktree skill's reference/gather-block.md, "The pre-compute block runs as one shell invocation".
Purpose
Keep pull requests moving without taking unsafe GitHub actions. Guarantees are enforced in
deterministic gate scripts; judgment stays with the agent. The safe default discovers your own
open PRs, author is one of your self logins, under the current repo's owner (or the configured
watched owners), works each to readiness, and reports. The safe tier never resolves threads
and never merges; merging exists only behind the explicit worker/autopilot opt-in and a
deterministic merge gate. Designed for /loop /source-control:babysit-prs continuous coverage.
The per-PR review discipline (finding extraction, per-finding D1–D7 verification gates,
self-reply filtering) is the plugin-scope seam shared with /source-control:pull-request:
${CLAUDE_PLUGIN_ROOT}/reference/review-discipline.md.
Read it before processing findings; dispatched workers cite it directly.
Modes and arguments
An invocation is [mode] [scope]; mode and scope are orthogonal. Combine them freely (worker owner/repo, worker #87, etc.).
Mode
What it does
(none), the configured default_tier (safe unless the consumer changed it)
Safe tier: discover in-scope PRs (your own, under the current repo's owner by default), check readiness, fix clear branch-owned issues and push, report blockers and the next cadence. Never resolves threads or merges.
worker
Everything safe does, and additionally auto-resolves pre-push-outdated bot threads and merges PRs the merge gate proves 100% ready. Requires Python. For dedicated 24/7 loops over your own PRs.
autopilot
Maximum autonomy for a solo owner: every open PR under the watched owners regardless of author; fix everything it can; resolve every thread it has addressed (bot, AI-review, and human); merge everything the gate proves ready. Requires Python. A deliberate power-user opt-in, never a default.
help (or ?)
Print the common flows and the effective configuration below; take no other action.
Tier selection is explicit. The tier keyword in the invocation wins. An explicitly typed
/source-control:babysit-prs invocation with no keyword, including inside /loop. Runs the
configured default_tier, safe unless the consumer changed it. An auto-routed match (this
skill loaded from conversational vocabulary such as "babysit my PRs" rather than a typed
invocation) always runs the safe tier: default_tier never acts on auto-routed invocations, so
a merge-capable tier engages only when the user names it, the worker/autopilot keyword, or
a typed invocation under a deliberately changed default_tier. Configuration can never convert
a casual invocation into standing merge authority.
Any tier also honors an explicit user instruction to merge or resolve specific PRs now; that is a direct order, not autonomous behavior, and it runs the same guarded gates below.
Common flows (this is what help prints, along with the effective configuration):
/source-control:babysit-prs one pass at the configured default tier
/source-control:babysit-prs #87 one PR in the current repo
/source-control:babysit-prs owner/repo one repository
/source-control:babysit-prs owner/repo#87 one specific PR
/source-control:babysit-prs worker full-auto (your PRs): fix + resolve-outdated + merge-ready
/source-control:babysit-prs autopilot max autonomy: ALL authors, fix+resolve+merge, escalate stuck PRs
/source-control:babysit-prs help list these flows and stop
Looped worker: /loop 15m /source-control:babysit-prs worker
Looped autopilot: /loop 15m /source-control:babysit-prs autopilot
Explicit order (any tier): "merge owner/repo#87 now" | "resolve bot threads on #87"
Scope resolution
Scope resolves deterministically, most specific first. Read the current git context with gh/git (all read-only) before falling back:
Explicit full ref in the invocation (owner/repo#N or owner/repo), use it exactly.
Bare PR number (#87, pr 87) inside a git repo, resolve the current repo with
gh repo view --json nameWithOwner -q .nameWithOwner and target that owner/repo#87.
Bare invocation inside a repo whose current branch has an open PR you authored. Target
just that one PR (detect with gh pr view --json number,url,author,headRefName; use it only
when the PR exists and its author is a self login).
Bare invocation inside a repo under a watched owner, that repository's own open PRs.
When watched_owners is unset, the current repo's owner is the inferred watch scope.
Otherwise (a neutral working directory, or an unattended loop), your own open PRs
across every watched owner, via the snapshot's author filter.
Conversation context that clearly scopes specific PRs or repositories overrides the
working-directory inference at any level.
Own-authorship is the default safety boundary, not a preference: never act on another person's
PR under the safe default. Widen beyond your own authorship ONLY on an explicit user
instruction or in autopilot, a deliberate opt-in that drops the author filter. The owner
allowlist (watched_owners, inferred as the current repo's owner when unset) is a separate,
always-on trust boundary: even autopilot never acts on a repository outside the watched owners.
Autonomy tiers (per action class)
Autonomy is decomposed per action, not per run. Irreversibility governs the gate.
Action class
Safe (default)
Worker
Autopilot
Discover, snapshot, report
yes
yes
yes, all authors
Fix clear branch-owned CI or bot-review issues, commit, push
yes
yes
yes, and harder (research a fix before giving up)
Dispatch a dedicated conflict worker (git merge, never rebase; it resolves locally and never pushes, the orchestrator re-verifies and pushes, reference/orchestration.md)
no, report (simple mechanical conflicts met while freshening a branch are still handled inline per reference/loop.md)
attempt with research; escalate only when it cannot confidently and safely resolve
Reading the merge-conflict blocker string. The snapshot classifier is mode-agnostic by
design, it has no tier input, so it emits the same blocker string, "merge conflict; dedicated conflict-resolution agent required", for every conflicting PR regardless of tier.
That string names a capability that exists in this skill, not an instruction to invoke it. In
the safe tier the table's no — report still governs: report the blocker exactly as stated
and dispatch no conflict worker. Only worker and autopilot read that same string as
license to act.
Cross-tier invariants, hold in every tier including autopilot: never a force-push (freshness is
merge-only, refspec-pushed fast-forward, reference/loop.md); never --admin;
never delete a branch or worktree
that is dirty or unmerged; never change GitHub settings, secrets, branch protection, or
billing; never act on a repository outside the watched owners; never resolve a thread whose
finding is not actually addressed. A merge always requires the deterministic gate. Autopilot
works harder to reach that state but never forces past it. A blocked action escalates; it is
never routed around. Advisory-only fix attempts are bounded per PR (the fix-round cap in
reference/orchestration.md); blocking defects are never capped.
Dependency hold-merge: a dependency-manager-authored PR (Dependabot/Renovate-class) is
never merged autonomously in ANY tier, the merge gate refuses it absent --allow-dependency,
which is passed only on an explicit user instruction to merge that specific PR.
Draft policy (per tier). Drafts enter evaluation scope in every tier. There is no blanket
draft skip. Safe: evaluate and report draft status, never gh pr ready. Worker and autopilot:
zero-blocker drafts always route through a worker (see Fan out). gh pr ready happens only in
autopilot, only for a draft its worker assesses complete.
Autopilot
autopilot is a deliberate, set-aside power-user tier for a solo owner who wants the queue
driven to zero, not the default, and not for a repo with other human reviewers whose feedback
must not be steamrolled. It processes every PR, fixes what it can, resolves only threads it has
addressed, merges through the pinned gate, and escalates the specific PRs that genuinely need a
human. What it does per PR, what "every PR" excludes, its draft-PR handling, and which scopes it
widens are the single home in reference/autopilot.md.
Autopilot merge tier
A config-gated escalation of autopilot's merge authority, off by default and active only while the operator sets babysit_autopilot_merge_tier; with the key unset, every merge decision follows the base path above. When enabled, per candidate PR autopilot runs a genuine review pass under a second bot account (author ≠ approver) that submits an approving review only when clean, then runs the pinned merge gate with the --autopilot-merge-tier flags layered onto --merge --expected-head <post-push-head-sha>. The concrete enabled-path merge command, the second-account approve mechanic, and the review-workflow requiredness precondition for enabling the tier are the single home in reference/safety.md.
That gate merges only when every criterion holds, the criteria and the safety-contract rationale are codified in reference/safety.md. It is fail-closed (the umbrella flag refuses unless all three parameter sets are supplied; predicates reused from the shared babysit_classify module), and any criterion failing falls back to the human merge-ready list, the tier never routes around the gate.
The two mutation gates are invoked ONLY through their wrapper scripts, by the bundled bin/-path form,
never the bare command name nor the raw Python behind them. Each source-control-babysit-<x> named in the bullets below is that wrapper launched by its bin/-path form; the exact form is the single
home in reference/safety.md. Both fail closed without --allowed-owners.
Before composing either wrapper command, read reference/safety.md,
"Guarded Mutation Wrappers", for the exact flag set. That section is the single home for the
bin/-path form, every configured flag that must ride on a given form (self logins, extra bot
logins, the review-settle pair, extra dependency-manager logins), the pins and the refusals they
produce, the override flags that are never passed autonomously, and the per-thread action
vocabulary. Never reconstruct one of these commands from memory; a silently dropped flag is a
silently dropped guard.
Merge readiness. source-control-babysit-merge is the gate. Safe tier runs it read-only and
reports; worker and autopilot add --merge --expected-head <vetted-head-sha> only on a
vetted head, and an enabled autopilot merge tier layers its own flags on
(reference/safety.md). When the expected-head pin is missing, or the
pinned sha no longer matches the live head, the wrapper refuses: re-snapshot and reassess the new
head instead of using --allow-unpinned-head. React
to the reported blockers; do not bypass the gate, and never reach for one of its override flags
on an unattended path. This gate's ready field is the sole authority for calling a PR merge-ready, never the finding-classification gate's READINESS_OK (reference/safety.md "Two Gates, One Merge-Ready Authority").
Once ready, stop. When the gate proves a PR ready (safe mode) or its merge is deferred to
a human (Pinned-Command Degradation, reference/safety.md), report that
outcome and end the PR's cycle. The no-background-monitor clause (Worker Contract,
reference/orchestration.md) governs this gate-completion step
exactly as it governs a worker's turn. Proving readiness is never a license to arm a watch.
Thread resolution. source-control-babysit-resolve-thread is the gate, and the mode is the
tier's: safe lists only and never resolves; worker resolves --autonomous, confined further to
threads already outdated in the PRE-push snapshot
(reference/orchestration.md), a rule that is agent discipline rather
than machine-enforced; autopilot widens to threads it has addressed, human threads included. The
wrapper touches only bot-authored threads unless that widening is in play, and it can never merge,
reply, or dismiss reviews. Never treat exit code 0 alone as proof a specific thread was resolved.
Always parse the per-thread JSON action field and the run summary before reporting or
re-checking the merge gate.
Independent resolution. --independent-resolver is a THIRD mode, parallel to --autonomous
and never a relaxation of it. isOutdated means the referenced code moved, so on a prose or
documentation PR a genuinely addressed finding never becomes outdated and the worker guard refuses
forever. This mode is dispatched to a FRESH context that is not the merging worker and did not
author the fix, that independence is what replaces isOutdated as the anti-self-certification
property, and the script cannot verify it, which is why the other half is machine-checked: one
pinned thread per call, and a disposition whose evidence the script validates against the world
rather than against the claim. A thread carrying more than one finding is refused outright
(skipped-multi-finding-thread) and escalates: one disposition cannot clear a thread whose other
findings nothing validated. Bot-only and the security/P1 bright line still hold. Who dispatches
this mode, the per-finding
D7.5 ledger owed before the wrapper is called, the fresh-pin rule, and the fail-closed fallback
for every bound it cannot cross are the single home in
reference/independent-resolution.md.
The agent decides severity (is this security/P1?), whether a finding is genuinely addressed,
what a label means, and every fix-vs-escalate call, never a script. Escalate a security/P1
thread instead of resolving it, in every tier and mode and with no exception, the wrappers refuse
a severity-flagged thread whoever asks (safety.md, "Security/P1 escalation has no exception").
Fan out: one fresh worker per PR that needs one, per cycle
Engine-backed runs (Python present) process the queue as one bounded cycle: snapshot the queue,
handle orchestrator-only transitions (stale-branch refresh, review triggers) and global cleanup
while holding the queue lease, then spawn one fresh, unbiased sub-agent per actionable PR up to
the concurrency cap. "Actionable" is every open in-scope PR the snapshot returns, narrowed only
by the deterministic exclusions, lease contention, the owner allowlist,
mutation_policy.branch_write_allowed, and the snapshot's needs_worker delta gate, never by
the orchestrator's own priority judgment. Full mechanics, the worker contract, and the prompt
template (untrusted PR fields fenced as data) are in
reference/orchestration.md.
A PR that is merely unchanged since the last cycle, even one still reporting blockers it was
already escalated for, does not get a fresh worker. A non-draft PR with zero blockers and no
untriaged material feedback also gets no worker, only a direct mode-appropriate
source-control-babysit-merge gate check; that is coverage, not a skip, a PR still carrying
untriaged material findings defers to the snapshot's needs_worker signal instead. In default
(safe) mode, run the gate without --merge and report readiness without merging. Pass
--merge --expected-head <snapshotted-head-sha> only in worker or autopilot mode, or under
an explicit user order to merge that PR, but an enabled autopilot merge tier adds the tier flags
(reference/safety.md), never the flagless base command. Use the exact head
SHA from the snapshot; a missing or stale pin must refuse the merge and send the PR back through
snapshot and assessment, never an unattended unpinned override.
Zero-blocker drafts are the exception: always route them through a worker, never directly
to the merge gate. In autopilot, that worker assesses whether the draft is complete: a
completed draft is marked ready with gh pr ready and continues through the normal guarded
path; a genuinely in-progress draft stays draft and is reported and escalated with the reason.
GitHub's
draft-stage contract
confirms a draft cannot merge until it is marked ready. Completeness of the diff is not the
only hold reason: an explicit unchecked human-only item named in the PR's own body holds the
draft too, even when the content is finished and green. See the worker contract in
reference/orchestration.md.
Each per-PR worker owns its local lifecycle end to end: acquire that PR's worker lease and its
own isolated worktree (find or create, never a shared checkout), check out and freshen the PR
branch, make only clear branch-owned fixes, re-check the head SHA, push, clean up on merge
(worktree + local branch), and release the lease, except a conflict worker, whose push the
orchestrator performs (reference/orchestration.md). Worktree policy:
reference/worktrees.md.
Effective configuration (substituted at load)
The values below substitute from this plugin's stored configuration when this skill loads.
A surviving literal ${user_config.…} placeholder means that key is unset. Apply its
documented unset behavior. Reference files use <angle-bracket> slots; fill every slot from
this block. Values reach scripts ONLY as explicit CLI flags (option environment variables never reach skill-invoked scripts). Configuration selects targets and thresholds; it never widens tier authority.
built-in dependabot/renovate dependency-manager set only
babysit_approval_downgrade_logins
${user_config.babysit_approval_downgrade_logins}
--approval-downgrade-logins (snapshot)
an approval carrying blocking-looking prose is downgraded to ignored structurally (every bot); a named login instead surfaces its own as material. Real APPROVED-state reviews and plain clean approvals are ignored regardless.
babysit_skip_downgrade_logins
${user_config.babysit_skip_downgrade_logins}
--skip-downgrade-logins (snapshot)
downgrade heuristic dormant
babysit_max_quiet_recheck_seconds
${user_config.babysit_max_quiet_recheck_seconds}
--max-quiet-recheck-seconds (snapshot)
14400
babysit_stuck_check_age_seconds
${user_config.babysit_stuck_check_age_seconds}
--stuck-check-age-seconds (snapshot)
1800
babysit_advisory_fix_round_cap
${user_config.babysit_advisory_fix_round_cap}
--fix-round-cap (snapshot, ledger)
100
babysit_worker_concurrency_cap
${user_config.babysit_worker_concurrency_cap}
prose only. Fan-out bound
10
babysit_worktree_root
${user_config.babysit_worktree_root}
--root (prune; worktree creation)
${CLAUDE_PLUGIN_DATA}/worktrees
state dir (not configurable)
${CLAUDE_PLUGIN_DATA}/state/babysit-prs
--state-dir (every state-touching script)
n/a
Configure via the /plugin dialog, or headless at install time with claude plugin install --config KEY=VALUE; /source-control:setup documents both plus the environment probes.
Engine and degrade
The snapshot engine and gates are Python (stdlib-only) under
${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/scripts/; every script ships --help. Python is a
declared prerequisite for worker and autopilot (and for engine-backed safe runs): when it
is absent, worker/autopilot STOP at entry with a concise remediation message naming the
prerequisite, and the safe tier degrades gracefully to the Python-free loop in
reference/loop.md. Discovery via gh pr list, finding classification via the
plugin-scope gate script, cadence via the static ladder. The merge gate is itself Python, so that
path cannot assess merge-readiness at all: report it unchecked, never inferred from the
classification gate. Let a safe iteration proceed when the engine is absent, reporting
merge-readiness as unchecked.
Sandboxed sessions: the engine reads over REST, and thread resolution fails closed.gh pr view --json is implemented entirely over GraphQL, so it fails with HTTP 403 wherever only
a pinned set of GraphQL operations is served (Claude Code on the web and remote execution), the same
restriction pull-request/reference/create.md §2.4.0 and the
work-item-tracker GitHub adapter
work around. That 403 reads like an expired token or a missing scope and is neither, so take it as a
signal to switch APIs rather than to re-authenticate. The engine re-sources the whole gh pr view
bundle over REST by itself (GET …/pulls/{n} for the pull request, plus the commit check-runs and
combined-status endpoints for the check rollup), so discovery, classification, and the branch-rule
and freshness checks keep working unchanged.
Review-thread resolution is the one fact with no REST equivalent, and it is not approximated.
The merge gate reports threadResolutionProven: false and unresolvedThreadCount: null, never 0,
and holds the PR with a blocker naming the restriction: an empty thread list would read as "zero
unresolved threads", the false-clean signal reference/safety.md exists to
prevent. Readiness there is UNPROVEN, never clean. Report it that way, quoting the blocker, and run
the lane from a session that is served GraphQL when a PR actually needs to merge. reviewDecision
degrades the same way: REST can prove CHANGES_REQUESTED but cannot prove an approval (GitHub folds
CODEOWNERS and the required-reviewer count into that field), so a protected base holds rather than
merging on evidence that does not reach it.
Per-PR checklist (safe core, each PR, every iteration)
Execute for EACH PR discovered, oldest first. Detailed mechanics: reference/loop.md.
Step 0, PR discovery: open PRs in scope (tier-scoped author filter), oldest-first
FIFO (§5.0.2). Zero PRs → report and schedule the idle wake
Step 0.1, Evidence-based fresh rescan: fetch ALL comments via the bundled
${CLAUDE_PLUGIN_ROOT}/scripts/fetch-all-pr-comments.sh (derives owner/repo from the current directory; from a cwd that is not a checkout of the target repo, export FETCH_COMMENTS_OWNER/FETCH_COMMENTS_REPO first, also unblocks the readiness gate's exit 4), filter own prior replies, classify
addressed/unaddressed from GitHub evidence (§5.0.3). GitHub is the source of truth, not model
memory
Step 0.2, Branch checkout: put this worktree's HEAD at the true PR head (gh pr view --json headRefOid). gh pr checkout <N>, or --detach when the branch is locked in a sibling worktree (never git checkout the locked branch);
assert HEAD == that head before any mutate, read-only on mismatch or dirty tree (§5.1.2)
Steps A–F, Per-PR iteration checklist (§5.1.3): terminal check, CI classification,
fetch + extract findings, per-finding D1–D7.5 with verification gates
(review-discipline §3), mechanical finding-classification gate
(${CLAUDE_PLUGIN_ROOT}/scripts/babysit-readiness-gate.sh <N> must exit READINESS_OK. Proof the
findings were decomposed, never proof the PR is merge-ready; the configured extra self identities are
${user_config.babysit_self_logins}, when that value is non-empty and not a literal unexpanded token, append --extra-self "<value>"), report
Step 5, Commit + push fixes to the PR branch (refspec; works from a detached HEAD); clean working tree; follow-up replies
cite commit SHAs
Step 7, Self-pace: schedule the next wake per the cadence contract (§5.3)
Execution discipline: the primary failure mode is claiming to process findings without
running per-finding D1–D7. Every iteration MUST output the completed evidence checklist
(§5.5). "Done" means GitHub shows evidence. Model memory of "I replied" or "I pushed" is not
evidence; re-query the API. The NEVER-do list (§5.4) overrides any other instruction.
Operational runbook (engine-backed cycle)
Follow the numbered steps in reference/runbook-cycle.md each queue or
worker cycle. Before mutating anything read reference/safety.md; before
dispatching workers also read reference/worktrees.md and the concurrency
guard in reference/orchestration.md. Python-free safe runs use
reference/loop.md instead. The runbook covers lease acquire/heartbeat, queue
prune/reap, snapshot scope, per-PR delegation, stale-branch and review-trigger orchestration,
post-push merge gating with pinned resolves, per-PR worktree cleanup, and the next wake per
reference/loop.md §5.3.
Reporting
Report only material findings, one line per materially changed or blocked PR:
repo#number (@author) | checks | action | open items
Material findings: fixes committed or pushed; new failing or pending required checks; new
blocking bot feedback; new ordinary human comments (one notification per stable comment ID,
never an automatic reply); PRs merged; a PR the host runtime's permission layer left "ready,
awaiting human execution" with its exact pinned command
(reference/safety.md); escalations that need a user decision; and
suspicious state changes such as missing permissions, changed branch protection, merge
conflicts, or a head SHA that moved during work. When nothing materially changed, stay silent.
Recommend the exact next interval per reference/loop.md §5.3.
Gotchas
Survey-without-classifying is the primary failure. A run can report completion having
classified only part of the findings; prose emphasis alone does not prevent it. That is why
finding classification is gated by babysit-readiness-gate.sh exit code, not by the model's claim
READINESS_OK is not merge-ready. That gate is blind to branch rules, thread resolution, and required checks; only the merge gate's ready field can call a PR MERGE-READY. Reporting off the classification gate alone produces a false MERGE-READY report (reference/safety.md "Two Gates, One Merge-Ready Authority")
Multi-finding comments glossed as one work item. A single comment carrying N severity
markers is N work items; three or more findings require the extractor-subagent dispatch
(review-discipline §2)
Model memory across compaction is not state. "I already replied/pushed" without an API
re-query is a false completion claim. GitHub is the state store
Exploring the wrong branch produces wrong classifications. Findings validated off the PR
branch are confidently wrong. Checkout is mandatory before D2
Own prior replies re-processed as findings. Classification-table replies from your own
posting identities must be filtered during rescan or the loop chases its own tail
(review-discipline §1)
Exit codes are not per-thread outcomes. Both wrappers demand JSON action-field parsing;
a zero exit covers skipped and refused threads too
Self-blocking CI check. A newly required check whose own fix PR carries that same check
cannot be gate-merged, the check is failing or absent on the very PR that would make it pass,
so the merge gate correctly refuses. Breaking the cycle is a one-time human admin-merge
bootstrap of that fix PR; no tier automates it. Surface it as a blocker needing that bootstrap,
never as a reason to route around the gate
Reference index. Load on demand
File
Load when
reference/safety.md
Before any mutating action, in every tier. The two gates, role boundaries, stop-ask and never-do lists.
reference/runbook-cycle.md
Starting an engine-backed queue or worker cycle; it is the numbered sequence that cycle follows.
reference/loop.md
Running the safe tier, or the engine is unavailable and every tier degrades to the Python-free loop.
reference/orchestration.md
An acting cycle is about to dispatch workers or resolve a conflict: gate arms, concurrency cap, leases, prompt template.
reference/cadence.md
Deciding the next wake interval, or a recommended_cadence reading needs its state and threshold.
reference/freshness.md
The snapshot reports branch_freshness.state == "behind" for a PR.
reference/stuck-checks.md
The snapshot reports a non-empty checks.stuck array, orbranch_freshness.state == "conflicting" and the check list is short. Report and escalate, never auto-fix.
reference/review-trigger.md
An external AI reviewer is configured and a PR needs summoning or its gate read.
reference/autopilot.md
Running the autopilot tier: its per-PR steps, exclusions, draft handling, widened scopes.
reference/worktrees.md
Creating, reusing, or pruning a per-PR worktree before dispatching a worker.
reference/feedback.md
A PR carries review comments needing classification and disposition, or the PR is a bot's and its taxonomy decides the handling.
reference/independent-resolution.md
A current bot thread is addressed but this context may not retire it.
Running the per-PR checklist for real, or briefing a worker: the compact checklist above is a skeleton over this.
1---2name: babysit-prs3description: Babysit your own open GitHub pull requests as a tiered fleet loop. The safe default discovers YOUR PRs under the current repo's owner, checks readiness, fixes clear branch-owned issues, and reports, it never resolves threads or merges. Explicit 'worker' tier adds auto-resolving outdated bot threads and gate-proven merges; explicit 'autopilot' adds all authors under the watched owners. Use when asked to babysit, watch, or advance open pull requests as a fleet (the safe tier), to run the worker or autopilot tier by name, or when pairing with /loop for continuous coverage; not for the single-PR lifecycle: prep, create, monitor one PR, or merge (use /pull-request).4---56## Pre-computed context78Current login: !`gh api user --jq .login 2>/dev/null || echo "unknown"`9Own open PRs here: !`gh pr list --state open --author "@me" --limit 200 --json number --jq 'length' 2>/dev/null || echo "unknown"`1011Branch and working tree: gather with two separate Bash calls, `git branch --show-current` then `git status --porcelain`; treat a failure as an unknown value and carry on. Keep them out of the pre-computed block above: the harness composes that block into one shell invocation, and a worktree-isolated agent refuses a git-bearing compound command. The dated record for that composition claim is the `worktree` skill's [reference/gather-block.md](../worktree/reference/gather-block.md), "The pre-compute block runs as one shell invocation".1213## Purpose1415Keep pull requests moving without taking unsafe GitHub actions. Guarantees are enforced in16deterministic gate scripts; judgment stays with the agent. The safe default discovers your own17open PRs, author is one of your self logins, under the current repo's owner (or the configured18watched owners), works each to readiness, and reports. **The safe tier never resolves threads19and never merges**; merging exists only behind the explicit `worker`/`autopilot` opt-in and a20deterministic merge gate. Designed for `/loop /source-control:babysit-prs` continuous coverage.2122The per-PR review discipline (finding extraction, per-finding D1–D7 verification gates,23self-reply filtering) is the plugin-scope seam shared with `/source-control:pull-request`:24[`${CLAUDE_PLUGIN_ROOT}/reference/review-discipline.md`](../../reference/review-discipline.md).25Read it before processing findings; dispatched workers cite it directly.2627## Modes and arguments2829An invocation is `[mode] [scope]`; mode and scope are orthogonal. Combine them freely (`worker owner/repo`, `worker #87`, etc.).3031| Mode | What it does |32| --- | --- |33| *(none)*, the configured `default_tier` (`safe` unless the consumer changed it) | Safe tier: discover in-scope PRs (your own, under the current repo's owner by default), check readiness, fix clear branch-owned issues and push, report blockers and the next cadence. Never resolves threads or merges. |34| `worker` | Everything safe does, and additionally auto-resolves *pre-push-outdated* bot threads and merges PRs the merge gate proves 100% ready. Requires Python. For dedicated 24/7 loops over your own PRs. |35| `autopilot` | Maximum autonomy for a solo owner: every open PR under the watched owners regardless of author; fix everything it can; resolve every thread it has addressed (bot, AI-review, and human); merge everything the gate proves ready. Requires Python. A deliberate power-user opt-in, never a default. |36| `help` (or `?`) | Print the common flows and the effective configuration below; take no other action. |3738**Tier selection is explicit.** The tier keyword in the invocation wins. An explicitly typed39`/source-control:babysit-prs` invocation with no keyword, including inside `/loop`. Runs the40configured `default_tier`, `safe` unless the consumer changed it. An auto-routed match (this41skill loaded from conversational vocabulary such as "babysit my PRs" rather than a typed42invocation) always runs the safe tier: `default_tier` never acts on auto-routed invocations, so43a merge-capable tier engages only when the user names it, the `worker`/`autopilot` keyword, or44a typed invocation under a deliberately changed `default_tier`. Configuration can never convert45a casual invocation into standing merge authority.4647Any tier also honors an explicit user instruction to merge or resolve specific PRs now; that is a direct order, not autonomous behavior, and it runs the same guarded gates below.4849Common flows (this is what `help` prints, along with the effective configuration):5051```text52/source-control:babysit-prs one pass at the configured default tier53/source-control:babysit-prs #87 one PR in the current repo54/source-control:babysit-prs owner/repo one repository55/source-control:babysit-prs owner/repo#87 one specific PR56/source-control:babysit-prs worker full-auto (your PRs): fix + resolve-outdated + merge-ready57/source-control:babysit-prs autopilot max autonomy: ALL authors, fix+resolve+merge, escalate stuck PRs58/source-control:babysit-prs help list these flows and stop59Looped worker: /loop 15m /source-control:babysit-prs worker60Looped autopilot: /loop 15m /source-control:babysit-prs autopilot61Explicit order (any tier): "merge owner/repo#87 now" | "resolve bot threads on #87"62```6364## Scope resolution6566Scope resolves deterministically, most specific first. Read the current git context with `gh`/`git` (all read-only) before falling back:67681. **Explicit full ref** in the invocation (`owner/repo#N` or `owner/repo`), use it exactly.692. **Bare PR number** (`#87`, `pr 87`) inside a git repo, resolve the current repo with70 `gh repo view --json nameWithOwner -q .nameWithOwner` and target that `owner/repo#87`.713. **Bare invocation inside a repo whose current branch has an open PR you authored**. Target72 just that one PR (detect with `gh pr view --json number,url,author,headRefName`; use it only73 when the PR exists and its author is a self login).744. **Bare invocation inside a repo under a watched owner**, that repository's own open PRs.75 When `watched_owners` is unset, the current repo's owner is the inferred watch scope.765. **Otherwise** (a neutral working directory, or an unattended loop), your own open PRs77 across every watched owner, via the snapshot's author filter.786. **Conversation context** that clearly scopes specific PRs or repositories overrides the79 working-directory inference at any level.8081Own-authorship is the default safety boundary, not a preference: never act on another person's82PR under the safe default. Widen beyond your own authorship ONLY on an explicit user83instruction or in `autopilot`, a deliberate opt-in that drops the author filter. The owner84allowlist (`watched_owners`, inferred as the current repo's owner when unset) is a separate,85always-on trust boundary: even autopilot never acts on a repository outside the watched owners.8687## Autonomy tiers (per action class)8889Autonomy is decomposed per action, not per run. Irreversibility governs the gate.9091| Action class | Safe (default) | Worker | Autopilot |92| --- | --- | --- | --- |93| Discover, snapshot, report | yes | yes | yes, **all authors** |94| Fix clear branch-owned CI or bot-review issues, commit, push | yes | yes | yes, and harder (research a fix before giving up) |95| Dispatch a dedicated conflict worker (`git merge`, never rebase; it resolves locally and never pushes, the orchestrator re-verifies and pushes, [reference/orchestration.md](reference/orchestration.md)) | no, report (simple mechanical conflicts met while freshening a branch are still handled inline per [reference/loop.md](reference/loop.md)) | mechanical/textual conflicts only, escalate genuine ambiguity | mechanical/textual conflicts only, escalate genuine ambiguity |96| Resolve review threads | no, report | **pre-push-outdated bot threads only** | any thread **it has addressed**, bot, AI-review, or human |97| Merge a PR | no. Report readiness | only when the gate proves 100% ready | only when the gate proves 100% ready |98| Mark a completed draft ready (`gh pr ready`) | no, report | no, report | yes, via its worker's completeness assessment |99| Refresh a stale (behind-base) branch, post a review trigger | orchestrator-only | orchestrator-only | orchestrator-only |100| `CHANGES_REQUESTED`, security/P1, posture, design, dependency acceptance | escalate | escalate | attempt with research; escalate only when it cannot confidently and safely resolve |101102**Reading the merge-conflict blocker string.** The snapshot classifier is mode-agnostic by103design, it has no tier input, so it emits the same blocker string, `"merge conflict;104dedicated conflict-resolution agent required"`, for every conflicting PR regardless of tier.105That string names a capability that exists in this skill, not an instruction to invoke it. In106the safe tier the table's `no — report` still governs: report the blocker exactly as stated107and dispatch no conflict worker. Only `worker` and `autopilot` read that same string as108license to act.109110**Cross-tier invariants**, hold in every tier including autopilot: never a force-push (freshness is111merge-only, refspec-pushed fast-forward, [reference/loop.md](reference/loop.md)); never `--admin`;112never delete a branch or worktree113that is dirty or unmerged; never change GitHub settings, secrets, branch protection, or114billing; never act on a repository outside the watched owners; never resolve a thread whose115finding is not actually addressed. A merge always requires the deterministic gate. Autopilot116works harder to reach that state but never forces past it. A blocked action escalates; it is117never routed around. Advisory-only fix attempts are bounded per PR (the fix-round cap in118[reference/orchestration.md](reference/orchestration.md)); blocking defects are never capped.119**Dependency hold-merge:** a dependency-manager-authored PR (Dependabot/Renovate-class) is120never merged autonomously in ANY tier, the merge gate refuses it absent `--allow-dependency`,121which is passed only on an explicit user instruction to merge that specific PR.122123**Draft policy (per tier).** Drafts enter evaluation scope in every tier. There is no blanket124draft skip. Safe: evaluate and report draft status, never `gh pr ready`. Worker and autopilot:125zero-blocker drafts always route through a worker (see Fan out). `gh pr ready` happens only in126autopilot, only for a draft its worker assesses complete.127128## Autopilot129130`autopilot` is a deliberate, set-aside power-user tier for a **solo owner** who wants the queue131driven to zero, not the default, and not for a repo with other human reviewers whose feedback132must not be steamrolled. It processes every PR, fixes what it can, resolves only threads it has133addressed, merges through the pinned gate, and escalates the specific PRs that genuinely need a134human. What it does per PR, what "every PR" excludes, its draft-PR handling, and which scopes it135widens are the single home in [reference/autopilot.md](reference/autopilot.md).136137## Autopilot merge tier138139A config-gated escalation of autopilot's merge authority, off by default and active only while the operator sets `babysit_autopilot_merge_tier`; with the key unset, every merge decision follows the base path above. When enabled, per candidate PR autopilot runs a **genuine review pass** under a **second bot account** (author ≠ approver) that submits an approving review **only when clean**, then runs the pinned merge gate with the `--autopilot-merge-tier` flags layered onto `--merge --expected-head <post-push-head-sha>`. The concrete enabled-path merge command, the second-account approve mechanic, and the review-workflow requiredness precondition for enabling the tier are the single home in [reference/safety.md](reference/safety.md).140That gate merges **only when every criterion holds**, the criteria and the safety-contract rationale are codified in [reference/safety.md](reference/safety.md). It is **fail-closed** (the umbrella flag refuses unless all three parameter sets are supplied; predicates reused from the shared `babysit_classify` module), and any criterion failing falls back to the human merge-ready list, the tier never routes around the gate.141142## Guarded mutations: deterministic gates, agent judgment143144The two mutation gates are invoked ONLY through their wrapper scripts, by the bundled `bin/`-path form,145never the bare command name nor the raw Python behind them. Each `source-control-babysit-<x>` named in the bullets below is that wrapper launched by its `bin/`-path form; the exact form is the single146home in [reference/safety.md](reference/safety.md). Both fail closed without `--allowed-owners`.147148**Before composing either wrapper command, read [reference/safety.md](reference/safety.md),149"Guarded Mutation Wrappers", for the exact flag set.** That section is the single home for the150`bin/`-path form, every configured flag that must ride on a given form (self logins, extra bot151logins, the review-settle pair, extra dependency-manager logins), the pins and the refusals they152produce, the override flags that are never passed autonomously, and the per-thread `action`153vocabulary. Never reconstruct one of these commands from memory; a silently dropped flag is a154silently dropped guard.155156- **Merge readiness**. `source-control-babysit-merge` is the gate. Safe tier runs it read-only and157 reports; `worker` and `autopilot` add `--merge --expected-head <vetted-head-sha>` only on a158 vetted head, and an enabled autopilot merge tier layers its own flags on159 ([reference/safety.md](reference/safety.md)). When the expected-head pin is missing, or the160 pinned sha no longer matches the live head, the wrapper refuses: re-snapshot and reassess the new161 head instead of using `--allow-unpinned-head`. React162 to the reported `blockers`; do not bypass the gate, and never reach for one of its override flags163 on an unattended path. **This gate's `ready` field is the sole authority for calling a PR merge-ready**, never the finding-classification gate's `READINESS_OK` ([reference/safety.md](reference/safety.md) "Two Gates, One Merge-Ready Authority").164165- **Once ready, stop.** When the gate proves a PR ready (safe mode) or its merge is deferred to166 a human (Pinned-Command Degradation, [reference/safety.md](reference/safety.md)), report that167 outcome and end the PR's cycle. The no-background-monitor clause (Worker Contract,168 [reference/orchestration.md](reference/orchestration.md)) governs this gate-completion step169 exactly as it governs a worker's turn. Proving readiness is never a license to arm a watch.170171- **Thread resolution**. `source-control-babysit-resolve-thread` is the gate, and the mode is the172 tier's: safe lists only and never resolves; worker resolves `--autonomous`, confined further to173 threads already outdated in the PRE-push snapshot174 ([reference/orchestration.md](reference/orchestration.md)), a rule that is agent discipline rather175 than machine-enforced; autopilot widens to threads it has addressed, human threads included. The176 wrapper touches only bot-authored threads unless that widening is in play, and it can never merge,177 reply, or dismiss reviews. Never treat exit code 0 alone as proof a specific thread was resolved.178 Always parse the per-thread JSON `action` field and the run summary before reporting or179 re-checking the merge gate.180181- **Independent resolution**. `--independent-resolver` is a THIRD mode, parallel to `--autonomous`182 and never a relaxation of it. `isOutdated` means the referenced code moved, so on a prose or183 documentation PR a genuinely addressed finding never becomes outdated and the worker guard refuses184 forever. This mode is dispatched to a FRESH context that is not the merging worker and did not185 author the fix, that independence is what replaces `isOutdated` as the anti-self-certification186 property, and the script cannot verify it, which is why the other half is machine-checked: one187 pinned thread per call, and a disposition whose evidence the script validates against the world188 rather than against the claim. A thread carrying more than one finding is refused outright189 (`skipped-multi-finding-thread`) and escalates: one disposition cannot clear a thread whose other190 findings nothing validated. Bot-only and the security/P1 bright line still hold. Who dispatches191 this mode, the per-finding192 D7.5 ledger owed before the wrapper is called, the fresh-pin rule, and the fail-closed fallback193 for every bound it cannot cross are the single home in194 [reference/independent-resolution.md](reference/independent-resolution.md).195196- **The agent** decides severity (is this security/P1?), whether a finding is genuinely addressed,197 what a label means, and every fix-vs-escalate call, never a script. Escalate a security/P1198 thread instead of resolving it, in every tier and mode and with no exception, the wrappers refuse199 a severity-flagged thread whoever asks (`safety.md`, "Security/P1 escalation has no exception").200201## Fan out: one fresh worker per PR that needs one, per cycle202203Engine-backed runs (Python present) process the queue as one bounded cycle: snapshot the queue,204handle orchestrator-only transitions (stale-branch refresh, review triggers) and global cleanup205while holding the queue lease, then spawn one fresh, unbiased sub-agent per actionable PR up to206the concurrency cap. "Actionable" is every open in-scope PR the snapshot returns, narrowed only207by the deterministic exclusions, lease contention, the owner allowlist,208`mutation_policy.branch_write_allowed`, and the snapshot's `needs_worker` delta gate, never by209the orchestrator's own priority judgment. Full mechanics, the worker contract, and the prompt210template (untrusted PR fields fenced as data) are in211[reference/orchestration.md](reference/orchestration.md).212213A PR that is merely unchanged since the last cycle, even one still reporting blockers it was214already escalated for, does not get a fresh worker. A non-draft PR with zero blockers **and no215untriaged material feedback** also gets no worker, only a direct mode-appropriate216`source-control-babysit-merge` gate check; that is coverage, not a skip, a PR still carrying217untriaged material findings defers to the snapshot's `needs_worker` signal instead. In default218(safe) mode, run the gate without `--merge` and report readiness without merging. Pass219`--merge --expected-head <snapshotted-head-sha>` only in `worker` or `autopilot` mode, or under220an explicit user order to merge that PR, but an enabled autopilot merge tier adds the tier flags221([reference/safety.md](reference/safety.md)), never the flagless base command. Use the exact head222SHA from the snapshot; a missing or stale pin must refuse the merge and send the PR back through223snapshot and assessment, never an unattended unpinned override.224225**Zero-blocker drafts are the exception:** always route them through a worker, never directly226to the merge gate. In autopilot, that worker assesses whether the draft is complete: a227completed draft is marked ready with `gh pr ready` and continues through the normal guarded228path; a genuinely in-progress draft stays draft and is reported and escalated with the reason.229GitHub's230[draft-stage contract](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request)231confirms a draft cannot merge until it is marked ready. Completeness of the diff is not the232only hold reason: an explicit unchecked human-only item named in the PR's own body holds the233draft too, even when the content is finished and green. See the worker contract in234[reference/orchestration.md](reference/orchestration.md).235236Each per-PR worker owns its local lifecycle end to end: acquire that PR's worker lease and its237own isolated worktree (find or create, never a shared checkout), check out and freshen the PR238branch, make only clear branch-owned fixes, re-check the head SHA, push, clean up on merge239(worktree + local branch), and release the lease, except a conflict worker, whose push the240orchestrator performs ([reference/orchestration.md](reference/orchestration.md)). Worktree policy:241[reference/worktrees.md](reference/worktrees.md).242243## Effective configuration (substituted at load)244245The values below substitute from this plugin's stored configuration when this skill loads.246A surviving literal `${user_config.…}` placeholder means that key is unset. Apply its247documented unset behavior. Reference files use `<angle-bracket>` slots; fill every slot from248this block. Values reach scripts ONLY as explicit CLI flags (option environment variables never reach skill-invoked scripts). Configuration selects targets and thresholds; it never widens tier authority.249250| Key | Value | Flag delivery | Unset behavior |251| --- | --- | --- | --- |252| `babysit_watched_owners` | `${user_config.babysit_watched_owners}` | `--owners` (snapshot), `--allowed-owners` (both wrappers, fail-closed) | infer the current repo's owner |253| `babysit_self_logins` | `${user_config.babysit_self_logins}` | `--extra-self` (readiness gate and snapshot); `--self-logins` (merge gate, resolve-thread) | none. Always added to your `gh api user --jq .login` login |254| `babysit_intended_write_identity` | `${user_config.babysit_intended_write_identity}` | `--intended-write-identity` (snapshot) | attribution-drift check dormant |255| `babysit_default_tier` | `${user_config.babysit_default_tier}` | prose only. Tier of explicit bare invocations | `safe` |256| `babysit_merge_method` | `${user_config.babysit_merge_method}` | `--method` (merge wrapper) | repo convention, then squash |257| `babysit_autopilot_merge_tier` | `${user_config.babysit_autopilot_merge_tier}` | prose only. Gates whether the tier's `--autopilot-merge-tier` merge flags are wired at all | `false` (tier disabled; PRs go to the human merge-ready list) |258| `babysit_lane_logins` | `${user_config.babysit_lane_logins}` | `--lane-logins` (merge wrapper, autopilot merge tier) | tier refuses fail-closed when enabled |259| `babysit_approver_bot_logins` | `${user_config.babysit_approver_bot_logins}` | `--approver-bot-logins` (merge wrapper, autopilot merge tier) | tier refuses fail-closed when enabled |260| `babysit_merge_block_labels` | `${user_config.babysit_merge_block_labels}` | `--block-labels` (merge wrapper, autopilot merge tier) | tier refuses fail-closed when enabled |261| `babysit_review_trigger_phrase` | `${user_config.babysit_review_trigger_phrase}` | `--trigger-phrase` (snapshot, request_review) | review-trigger module dormant |262| `babysit_review_bot_logins` | `${user_config.babysit_review_bot_logins}` | `--review-bot-logins` (snapshot, request_review, merge gate) | review-trigger module dormant; merge gate's review-settle hold dormant |263| `babysit_review_gate_context` | `${user_config.babysit_review_gate_context}` | `--review-gate-context` (snapshot) | gate treated as absent |264| `babysit_review_settle_minutes` | `${user_config.babysit_review_settle_minutes}` | `--review-settle-minutes` (merge gate) | review-settle hold dormant. Pair it with `babysit_review_bot_logins`, which the gate requires alongside it |265| `babysit_ci_gateway_context` | `${user_config.babysit_ci_gateway_context}` | `--ci-gateway-context` (snapshot) | gateway check unused |266| `babysit_extra_bot_logins` | `${user_config.babysit_extra_bot_logins}` | `--extra-bot-logins` (snapshot, resolve-thread, request_review) | structural bot detection only |267| `babysit_extra_dependency_manager_logins` | `${user_config.babysit_extra_dependency_manager_logins}` | `--extra-dependency-manager-logins` (merge gate) | built-in dependabot/renovate dependency-manager set only |268| `babysit_approval_downgrade_logins` | `${user_config.babysit_approval_downgrade_logins}` | `--approval-downgrade-logins` (snapshot) | an approval carrying blocking-looking prose is downgraded to ignored structurally (every bot); a named login instead surfaces its own as material. Real APPROVED-state reviews and plain clean approvals are ignored regardless. |269| `babysit_skip_downgrade_logins` | `${user_config.babysit_skip_downgrade_logins}` | `--skip-downgrade-logins` (snapshot) | downgrade heuristic dormant |270| `babysit_max_quiet_recheck_seconds` | `${user_config.babysit_max_quiet_recheck_seconds}` | `--max-quiet-recheck-seconds` (snapshot) | `14400` |271| `babysit_stuck_check_age_seconds` | `${user_config.babysit_stuck_check_age_seconds}` | `--stuck-check-age-seconds` (snapshot) | `1800` |272| `babysit_advisory_fix_round_cap` | `${user_config.babysit_advisory_fix_round_cap}` | `--fix-round-cap` (snapshot, ledger) | `100` |273| `babysit_worker_concurrency_cap` | `${user_config.babysit_worker_concurrency_cap}` | prose only. Fan-out bound | `10` |274| `babysit_worktree_root` | `${user_config.babysit_worktree_root}` | `--root` (prune; worktree creation) | `${CLAUDE_PLUGIN_DATA}/worktrees` |275| state dir (not configurable) | `${CLAUDE_PLUGIN_DATA}/state/babysit-prs` | `--state-dir` (every state-touching script) | n/a |276277Configure via the `/plugin` dialog, or headless at install time with `claude plugin install278--config KEY=VALUE`; `/source-control:setup` documents both plus the environment probes.279280## Engine and degrade281282The snapshot engine and gates are Python (stdlib-only) under283`${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/scripts/`; every script ships `--help`. Python is a284declared prerequisite for `worker` and `autopilot` (and for engine-backed safe runs): when it285is absent, `worker`/`autopilot` STOP at entry with a concise remediation message naming the286prerequisite, and the safe tier degrades gracefully to the Python-free loop in287[reference/loop.md](reference/loop.md). Discovery via `gh pr list`, finding classification via the288plugin-scope gate script, cadence via the static ladder. The merge gate is itself Python, so that289path cannot assess merge-readiness at all: report it unchecked, never inferred from the290classification gate. Let a safe iteration proceed when the engine is absent, reporting291merge-readiness as unchecked.292293**Sandboxed sessions: the engine reads over REST, and thread resolution fails closed.**294`gh pr view --json` is implemented entirely over GraphQL, so it fails with `HTTP 403` wherever only295a pinned set of GraphQL operations is served (Claude Code on the web and remote execution), the same296restriction [`pull-request/reference/create.md`](../pull-request/reference/create.md) §2.4.0 and the297[work-item-tracker GitHub adapter](../../../work-items/tools/work-item-tracker/adapters/github/README.md)298work around. That 403 reads like an expired token or a missing scope and is neither, so take it as a299signal to switch APIs rather than to re-authenticate. The engine re-sources the whole `gh pr view`300bundle over REST by itself (`GET …/pulls/{n}` for the pull request, plus the commit check-runs and301combined-status endpoints for the check rollup), so discovery, classification, and the branch-rule302and freshness checks keep working unchanged.303304Review-thread **resolution** is the one fact with no REST equivalent, and it is not approximated.305The merge gate reports `threadResolutionProven: false` and `unresolvedThreadCount: null`, never `0`,306and holds the PR with a blocker naming the restriction: an empty thread list would read as "zero307unresolved threads", the false-clean signal [reference/safety.md](reference/safety.md) exists to308prevent. Readiness there is UNPROVEN, never clean. Report it that way, quoting the blocker, and run309the lane from a session that is served GraphQL when a PR actually needs to merge. `reviewDecision`310degrades the same way: REST can prove `CHANGES_REQUESTED` but cannot prove an approval (GitHub folds311CODEOWNERS and the required-reviewer count into that field), so a protected base holds rather than312merging on evidence that does not reach it.313314## Per-PR checklist (safe core, each PR, every iteration)315316Execute for EACH PR discovered, oldest first. Detailed mechanics: [reference/loop.md](reference/loop.md).317318- [ ] **Step 0, PR discovery:** open PRs in scope (tier-scoped author filter), oldest-first319 FIFO (§5.0.2). Zero PRs → report and schedule the idle wake320- [ ] **Step 0.1, Evidence-based fresh rescan:** fetch ALL comments via the bundled321 `${CLAUDE_PLUGIN_ROOT}/scripts/fetch-all-pr-comments.sh` (derives owner/repo from the current directory; from a cwd that is not a checkout of the target repo, export `FETCH_COMMENTS_OWNER`/`FETCH_COMMENTS_REPO` first, also unblocks the readiness gate's exit 4), filter own prior replies, classify322 addressed/unaddressed from GitHub evidence (§5.0.3). GitHub is the source of truth, not model323 memory324- [ ] **Step 0.2, Branch checkout:** put this worktree's HEAD at the true PR head (`gh pr view --json headRefOid`). `gh pr checkout <N>`, or `--detach` when the branch is locked in a sibling worktree (never `git checkout` the locked branch);325 assert HEAD == that head before any mutate, read-only on mismatch or dirty tree (§5.1.2)326- [ ] **Step 0.3, Branch freshness:** fetch + `git merge-base --is-ancestor`; integrate327 merge-only (never rebase, rebasing a PR branch needs a forbidden force-push), graduated conflict handling (§5.1.2)328- [ ] **Step 1, Event-delivery gate:** cloud poll / push channel / Monitor watch, re-armed329 per PR (§5.1.1)330- [ ] **Steps A–F, Per-PR iteration checklist** (§5.1.3): terminal check, CI classification,331 fetch + extract findings, per-finding D1–D7.5 with verification gates332 ([review-discipline](../../reference/review-discipline.md) §3), mechanical finding-classification gate333 (`${CLAUDE_PLUGIN_ROOT}/scripts/babysit-readiness-gate.sh <N>` must exit `READINESS_OK`. Proof the334 findings were decomposed, never proof the PR is merge-ready; the configured extra self identities are335 `${user_config.babysit_self_logins}`, when that value is non-empty and not a literal unexpanded token, append `--extra-self "<value>"`), report336- [ ] **Step 5, Commit + push** fixes to the PR branch (refspec; works from a detached HEAD); clean working tree; follow-up replies337 cite commit SHAs338- [ ] **Step 6, PR transition:** next-oldest PR needing attention (§5.1.6)339- [ ] **Step 7, Self-pace:** schedule the next wake per the cadence contract (§5.3)340341**Execution discipline:** the primary failure mode is claiming to process findings without342running per-finding D1–D7. Every iteration MUST output the completed evidence checklist343(§5.5). "Done" means GitHub shows evidence. Model memory of "I replied" or "I pushed" is not344evidence; re-query the API. The NEVER-do list (§5.4) overrides any other instruction.345346## Operational runbook (engine-backed cycle)347348Follow the numbered steps in [reference/runbook-cycle.md](reference/runbook-cycle.md) each queue or349worker cycle. Before mutating anything read [reference/safety.md](reference/safety.md); before350dispatching workers also read [reference/worktrees.md](reference/worktrees.md) and the concurrency351guard in [reference/orchestration.md](reference/orchestration.md). Python-free safe runs use352[reference/loop.md](reference/loop.md) instead. The runbook covers lease acquire/heartbeat, queue353prune/reap, snapshot scope, per-PR delegation, stale-branch and review-trigger orchestration,354post-push merge gating with pinned resolves, per-PR worktree cleanup, and the next wake per355[reference/loop.md](reference/loop.md) §5.3.356357## Reporting358359Report only material findings, one line per materially changed or blocked PR:360361```text362repo#number (@author) | checks | action | open items363```364365Material findings: fixes committed or pushed; new failing or pending required checks; new366blocking bot feedback; new ordinary human comments (one notification per stable comment ID,367never an automatic reply); PRs merged; a PR the host runtime's permission layer left "ready,368awaiting human execution" with its exact pinned command369([reference/safety.md](reference/safety.md)); escalations that need a user decision; and370suspicious state changes such as missing permissions, changed branch protection, merge371conflicts, or a head SHA that moved during work. When nothing materially changed, stay silent.372Recommend the exact next interval per [reference/loop.md](reference/loop.md) §5.3.373374## Gotchas375376- **Survey-without-classifying is the primary failure.** A run can report completion having377 classified only part of the findings; prose emphasis alone does not prevent it. That is why378 finding classification is gated by `babysit-readiness-gate.sh` exit code, not by the model's claim379- **`READINESS_OK` is not merge-ready.** That gate is blind to branch rules, thread resolution, and required checks; only the merge gate's `ready` field can call a PR MERGE-READY. Reporting off the classification gate alone produces a false MERGE-READY report ([reference/safety.md](reference/safety.md) "Two Gates, One Merge-Ready Authority")380- **Multi-finding comments glossed as one work item.** A single comment carrying N severity381 markers is N work items; three or more findings require the extractor-subagent dispatch382 ([review-discipline](../../reference/review-discipline.md) §2)383- **Model memory across compaction is not state.** "I already replied/pushed" without an API384 re-query is a false completion claim. GitHub is the state store385- **Exploring the wrong branch produces wrong classifications.** Findings validated off the PR386 branch are confidently wrong. Checkout is mandatory before D2387- **Own prior replies re-processed as findings.** Classification-table replies from your own388 posting identities must be filtered during rescan or the loop chases its own tail389 ([review-discipline](../../reference/review-discipline.md) §1)390- **Exit codes are not per-thread outcomes.** Both wrappers demand JSON `action`-field parsing;391 a zero exit covers skipped and refused threads too392- **Self-blocking CI check.** A newly required check whose own fix PR carries that same check393 cannot be gate-merged, the check is failing or absent on the very PR that would make it pass,394 so the merge gate correctly refuses. Breaking the cycle is a one-time human admin-merge395 bootstrap of that fix PR; no tier automates it. Surface it as a blocker needing that bootstrap,396 never as a reason to route around the gate397398## Reference index. Load on demand399400| File | Load when |401|---|---|402| [reference/safety.md](reference/safety.md) | Before any mutating action, in every tier. The two gates, role boundaries, stop-ask and never-do lists. |403| [reference/runbook-cycle.md](reference/runbook-cycle.md) | Starting an engine-backed queue or worker cycle; it is the numbered sequence that cycle follows. |404| [reference/loop.md](reference/loop.md) | Running the safe tier, or the engine is unavailable and every tier degrades to the Python-free loop. |405| [reference/orchestration.md](reference/orchestration.md) | An acting cycle is about to dispatch workers or resolve a conflict: gate arms, concurrency cap, leases, prompt template. |406| [reference/cadence.md](reference/cadence.md) | Deciding the next wake interval, or a `recommended_cadence` reading needs its state and threshold. |407| [reference/freshness.md](reference/freshness.md) | The snapshot reports `branch_freshness.state == "behind"` for a PR. |408| [reference/stuck-checks.md](reference/stuck-checks.md) | The snapshot reports a non-empty `checks.stuck` array, **or** `branch_freshness.state == "conflicting"` and the check list is short. Report and escalate, never auto-fix. |409| [reference/review-trigger.md](reference/review-trigger.md) | An external AI reviewer is configured and a PR needs summoning or its gate read. |410| [reference/autopilot.md](reference/autopilot.md) | Running the autopilot tier: its per-PR steps, exclusions, draft handling, widened scopes. |411| [reference/worktrees.md](reference/worktrees.md) | Creating, reusing, or pruning a per-PR worktree before dispatching a worker. |412| [reference/feedback.md](reference/feedback.md) | A PR carries review comments needing classification and disposition, or the PR is a bot's and its taxonomy decides the handling. |413| [reference/independent-resolution.md](reference/independent-resolution.md) | A current bot thread is addressed but this context may not retire it. |414| [`${CLAUDE_PLUGIN_ROOT}/reference/review-discipline.md`](../../reference/review-discipline.md) | Running the per-PR checklist for real, or briefing a worker: the compact checklist above is a skeleton over this. |
Run npx skillmds@latest add melodic-software/babysit-prs in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Babysit your own open GitHub pull requests as a tiered fleet loop. The safe default discovers YOUR PRs under the current repo's owner, checks readiness, fixes clear branch-owned issues, and reports, it never resolves threads or merges. Explicit 'worker' tier adds auto-resolving outdated bot threads and gate-proven merges; explicit 'autopilot' adds all authors under the watched owners. Use when asked to babysit, watch, or advance open pull requests as a fleet (the safe tier), to run the worker or autopilot tier by name, or when pairing with /loop for continuous coverage; not for the single-PR lifecycle: prep, create, monitor one PR, or merge (use /pull-request). It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
melodic-software (@melodic-software) published this skill. Their other Agent Skills are listed on their SkillMD profile.