|
| 1 | +--- |
| 2 | +name: babysit-prs |
| 3 | +description: Drive a PR to a clean review (Greptile 5/5, zero open threads) — ships if needed, triggers Greptile/Cursor Bugbot, fixes real findings, replies to and resolves every thread, and loops until clean |
| 4 | +--- |
| 5 | + |
| 6 | +# Babysit PRs |
| 7 | + |
| 8 | +Owns a PR end-to-end through review: ship it, wait for the automatic review round, and if it |
| 9 | +isn't already clean, drive fix → reply → resolve → re-review cycles until Greptile reports 5/5 |
| 10 | +and there are zero open comment threads. Designed to be run under `/loop` (no fixed interval — |
| 11 | +let it self-pace on review latency) so it survives across multiple wakeups in the same session. |
| 12 | + |
| 13 | +## When to use |
| 14 | + |
| 15 | +- The user says "babysit this PR", "keep working the reviews until it's clean", or similar |
| 16 | +- As the natural follow-up to `/ship` when the user wants the review loop automated rather than |
| 17 | + manually re-triggering reviews and answering comments themselves |
| 18 | + |
| 19 | +## Inputs |
| 20 | + |
| 21 | +Needs a PR number. If none is given and there's no open PR for the current branch, run `/ship` |
| 22 | +first (which includes the `origin/staging` sync check — see `.agents/skills/ship/SKILL.md`) to |
| 23 | +create one. |
| 24 | + |
| 25 | +## Definition of "clean" |
| 26 | + |
| 27 | +Both must hold: |
| 28 | +1. The latest Greptile summary comment reports **Confidence Score: 5/5** |
| 29 | +2. `reviewThreads` (GraphQL, see below) has **zero threads with `isResolved: false`** |
| 30 | + |
| 31 | +Do not stop early on "no new comments this round" alone — a thread can be open from an earlier |
| 32 | +round. Always check both conditions freshly after every push. |
| 33 | + |
| 34 | +## Loop |
| 35 | + |
| 36 | +1. **Check current state** before doing anything: |
| 37 | + ```bash |
| 38 | + gh pr view <n> --json comments -q '.comments[] | select(.author.login=="greptile-apps") | .body' | tail -1 |
| 39 | + gh api graphql -f query=' |
| 40 | + query { repository(owner: "<owner>", name: "<repo>") { pullRequest(number: <n>) { |
| 41 | + reviewThreads(first: 50) { nodes { id isResolved path line |
| 42 | + comments(first: 5) { nodes { id databaseId author { login } body } } } } } } }' |
| 43 | + ``` |
| 44 | + If Greptile is 5/5 and every thread's `isResolved` is `true`, stop — report the outcome (see |
| 45 | + "Reporting" below) and skip the rest of this list. |
| 46 | + |
| 47 | +2. **If no review has run yet** (fresh PR, no Greptile/Cursor comments): they usually run |
| 48 | + automatically on PR open — confirm via `gh pr checks <n>` (look for `Cursor Bugbot` / |
| 49 | + `Greptile Review`) and wait for that first round before doing anything else. |
| 50 | + |
| 51 | +3. **If a review round has landed and it isn't clean**: for every thread where |
| 52 | + `isResolved: false`, triage the finding on its own merits — this is the part that requires |
| 53 | + judgment, not a mechanical loop: |
| 54 | + - **Real bug**: fix it in the cleanest way available. Match the codebase's existing |
| 55 | + conventions for that kind of problem before inventing a new one (e.g. an SSRF-prone |
| 56 | + user-supplied-host fetch should use whatever `validateUrlWithDNS`/`secureFetchWithPinnedIP` |
| 57 | + pattern the rest of the codebase already uses for that exact situation — grep for a sibling |
| 58 | + integration solving the same problem first). Never patch around a finding with a |
| 59 | + workaround, a broad try/catch, or a suppression comment — fix the actual cause. |
| 60 | + - **False positive**: don't change code. Reply with the specific reason it doesn't apply |
| 61 | + (cite the type definition, the established pattern it matches, or the doc it follows) so |
| 62 | + the reviewer bot and a human skimming later both understand why it was left as-is. |
| 63 | + - **Already fixed by an earlier finding in the same round**: note that and resolve without a |
| 64 | + duplicate code change. |
| 65 | + |
| 66 | +4. **Reply to every thread individually** before resolving it — never resolve silently: |
| 67 | + ```bash |
| 68 | + gh api repos/<owner>/<repo>/pulls/<n>/comments/<databaseId>/replies -f body="<what was done and why>" |
| 69 | + ``` |
| 70 | + Then resolve via GraphQL (needs the thread `id` from step 1, not the comment id): |
| 71 | + ```bash |
| 72 | + gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<threadId>"}) { thread { isResolved } } }' |
| 73 | + ``` |
| 74 | + |
| 75 | +5. **Before pushing, re-run the sync check** from `/ship` step 2 |
| 76 | + (`git fetch origin staging && git log --oneline origin/staging..HEAD` should list only this |
| 77 | + session's commits) — a babysit loop that runs over a long session is exactly the scenario |
| 78 | + where a branch can drift. Then run the repo's lint/typecheck/boundary-validation gates the |
| 79 | + same way `/ship` does before committing. |
| 80 | + |
| 81 | +6. **Commit and push** the round's fixes as one commit (`--force-with-lease` only if step 5's |
| 82 | + sync check required a rebuild). |
| 83 | + |
| 84 | +7. **Re-trigger review** by posting `@greptile` and `@cursor review` as **two separate PR |
| 85 | + comments** — never combine them into one comment, each bot only responds to its own mention: |
| 86 | + ```bash |
| 87 | + gh pr comment <n> --body "@greptile" |
| 88 | + gh pr comment <n> --body "@cursor review" |
| 89 | + ``` |
| 90 | + |
| 91 | +8. **Wait for the new round**, then go back to step 1. Pace the wait with `ScheduleWakeup` using |
| 92 | + a fallback delay of ~250–300s (Greptile/Cursor typically take 1–3 minutes) — never busy-poll |
| 93 | + in a sleep loop. Pass the same `/loop babysit PR <n>` prompt on each wakeup so the loop |
| 94 | + resumes correctly. |
| 95 | + |
| 96 | +9. **Stop conditions**: clean state reached (see above), or the same unresolved finding survives |
| 97 | + two consecutive rounds with no new information (surface it to the user instead of looping |
| 98 | + forever), or the user interrupts. |
| 99 | + |
| 100 | +## Reporting |
| 101 | + |
| 102 | +When the loop ends, summarize: how many rounds it took, what was actually fixed (one line each), |
| 103 | +what was pushed back on as a false positive and why, and the final Greptile score / thread count. |
| 104 | + |
| 105 | +## Hard rules |
| 106 | + |
| 107 | +- Never post the two re-review mentions as a single combined comment. |
| 108 | +- Never resolve a thread without replying to it first. |
| 109 | +- Never fix a finding with a hacky workaround — if the clean fix isn't obvious, find the sibling |
| 110 | + pattern elsewhere in the codebase solving the same class of problem and match it. |
| 111 | +- Never silently drop a finding — every thread gets either a code fix or a reasoned reply. |
| 112 | +- Always re-run the `/ship`-style sync check before every push in the loop, not just the first. |
0 commit comments