Drive a PR to a clean review (Greptile 5/5, zero open threads) — ships if needed, keeps it mergeable against staging, triggers Greptile/Cursor Bugbot, fixes real findings, replies to and resolves every thread, and loops until clean
62
72%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./.agents/skills/babysit/SKILL.mdOwns a PR end-to-end through review: ship it, wait for the automatic review round, and if it
isn't already clean, drive fix → reply → resolve → re-review cycles until Greptile reports 5/5
and there are zero open comment threads, keeping the branch mergeable against staging along the
way. Designed to be run under /loop (no fixed interval — let it self-pace on review latency)
so it survives across multiple wakeups in the same session.
/ship when the user wants the review loop automated rather than
manually re-triggering reviews and answering comments themselvesNeeds a PR number. If none is given and there's no open PR for the current branch, run /ship
first (which includes the origin/staging sync check — see .agents/skills/ship/SKILL.md) to
create one.
Both must hold:
reviewThreads (GraphQL, see below) has zero threads with isResolved: falseDo not stop early on "no new comments this round" alone — a thread can be open from an earlier round. Always check both conditions freshly after every push.
Check current state before doing anything, including whether the PR is still mergeable:
gh pr view <n> --json mergeable
gh pr view <n> --json comments -q '[.comments[] | select(.author.login=="greptile-apps")] | last | .body'
gh api graphql -f query='
query { repository(owner: "<owner>", name: "<repo>") { pullRequest(number: <n>) {
reviewThreads(first: 50) { pageInfo { hasNextPage endCursor } nodes { id isResolved path line
comments(first: 5) { nodes { id databaseId author { login } body } } } } } } }'[.comments[]] | last | .body, not ... | .body | tail -1 — the latter pipes every matching
comment's full multi-line body through the pipeline and keeps only the final line of that
combined output (usually the "Reviews (n): Last reviewed commit..." footer), not the last
comment, so it silently misses the actual "Confidence Score: X/5" line.
reviewThreads(first: 50) is a single page — check pageInfo.hasNextPage. If true, don't
stop yet: re-run the same query with after: "<endCursor>" and keep paging until
hasNextPage is false before evaluating "clean." A PR with more than 50 threads is rare but
stopping on a partial page would silently miss unresolved ones past the cutoff.
If mergeable is CONFLICTING, fix that first (step 2). Otherwise, if Greptile is 5/5 and
every thread across all pages has isResolved: true, stop — report the outcome (see
"Reporting" below) and skip the rest of this list.
If the PR has a merge conflict, merge origin/staging, resolve the conflicts, run the
usual pre-push checks, push, and go to step 8 to re-trigger review.
If no review has run yet (fresh PR, no Greptile/Cursor comments): they usually run
automatically on PR open — confirm via gh pr checks <n> (look for Cursor Bugbot /
Greptile Review) and wait for that first round before doing anything else.
If a review round has landed and it isn't clean: for every thread where
isResolved: false, triage the finding on its own merits — this is the part that requires
judgment, not a mechanical loop:
validateUrlWithDNS/secureFetchWithPinnedIP
pattern the rest of the codebase already uses for that exact situation — grep for a sibling
integration solving the same problem first). Never patch around a finding with a
workaround, a broad try/catch, or a suppression comment — fix the actual cause.Reply to every thread individually before resolving it — never resolve silently:
gh api repos/<owner>/<repo>/pulls/<n>/comments/<databaseId>/replies -f body="<what was done and why>"Then resolve via GraphQL (needs the thread id from step 1, not the comment id):
gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<threadId>"}) { thread { isResolved } } }'Before pushing, re-run the full sync check from /ship step 2 — not just the log command,
the whole check-and-recover flow (stash WIP if needed, rebase, verify the rebase didn't just
cleanly replay stray commits, cherry-pick rebuild if it did or if it conflicted). A babysit
loop spanning a long session is exactly the scenario where a branch can drift, and pushing
review fixes on top of undetected drift is how an oversized PR happens even after the branch
was fixed once. Then run the repo's pre-ship checks the same way /ship does before
committing — not just lint/typecheck/boundary-validation, but also the conditional /cleanup
(if this round's fix touched UI code) and /db-migrate (if it touched schema/migrations)
gates from /ship steps 4 and 5. A review-fix round is still a code change and can trip
either gate just as easily as the original commit did.
Commit and push the round's fixes as one commit — --force-with-lease whenever step 6's
sync check rewrote history, which includes a plain git rebase origin/staging that completed
with no conflicts, not only the cherry-pick rebuild path; both rewrite commits already
published to the remote, so a plain git push can be rejected either way — then run /ship
step 9's post-push verify — not just before the first push, every push in the loop:
git fetch origin staging && git log --oneline --reverse origin/staging..HEAD
gh pr view <n> --json commits -q '.commits[].messageHeadline'--reverse makes git log oldest-first, matching the PR commit list's order — plain
git log is newest-first, so without it a positional comparison can spuriously fail on any
multi-commit branch.
These two lists must describe the same commits. A review loop runs many pushes across many
rounds; checking sync only before the push (step 6) and never after is how a bad push or a
PR whose commit history quietly went stale between rounds goes unnoticed.
Re-trigger review by posting @greptile and @cursor review as two separate PR
comments — never combine them into one comment, each bot only responds to its own mention:
gh pr comment <n> --body "@greptile"
gh pr comment <n> --body "@cursor review"Wait for the new round, then go back to step 1. Pace the wait with ScheduleWakeup using
a fallback delay of ~250–300s (Greptile/Cursor typically take 1–3 minutes) — never busy-poll
in a sleep loop. Pass the same /loop babysit PR <n> prompt on each wakeup so the loop
resumes correctly.
Stop conditions: clean state reached (see above), or the same unresolved finding or merge conflict survives two consecutive rounds with no new information (surface it to the user instead of looping forever), or the user interrupts.
When the loop ends, summarize: how many rounds it took, what was actually fixed (one line each), what was pushed back on as a false positive and why, and the final Greptile score / thread count.
/ship-style sync check before every push in the loop, not just the first.6f514c1
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.