Files
simstudioai--sim/.cursor/commands/babysit.md
T
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

7.7 KiB
Raw Blame History

Babysit Command

Owns 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.

When to use

  • The user says "babysit this PR", "keep working the reviews until it's clean", or similar
  • As the natural follow-up to /ship when the user wants the review loop automated rather than manually re-triggering reviews and answering comments themselves

Inputs

Needs 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 .cursor/commands/ship.md) to create one.

Definition of "clean"

Both must hold:

  1. The latest Greptile summary comment reports Confidence Score: 5/5
  2. reviewThreads (GraphQL, see below) has zero threads with isResolved: false

Do 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.

Loop

  1. Check current state before doing anything:

    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 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.

  2. 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.

  3. 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:

    • Real bug: fix it in the cleanest way available. Match the codebase's existing conventions for that kind of problem before inventing a new one (e.g. an SSRF-prone user-supplied-host fetch should use whatever 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.
    • False positive: don't change code. Reply with the specific reason it doesn't apply (cite the type definition, the established pattern it matches, or the doc it follows) so the reviewer bot and a human skimming later both understand why it was left as-is.
    • Already fixed by an earlier finding in the same round: note that and resolve without a duplicate code change.
  4. 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 } } }'
    
  5. 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 — not just lint/typecheck/boundary- validation, but also the conditional /cleanup (UI changes) and /db-migrate (schema/migration changes) gates from .agents/skills/ship/SKILL.md steps 4 and 5 (Cursor's own 7-step ship.md doesn't carry those steps, but a review-fix round is still a code change and can trip either gate just as easily as the original commit did).

  6. Commit and push the round's fixes as one commit — --force-with-lease whenever step 5'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 7's post-push verify — not just before the first push, every push in the loop (the Cursor /ship has 7 steps; the Claude Code skill version's equivalent is step 9 — see .agents/skills/babysit/SKILL.md if working from that copy):

    git fetch origin staging && git log --oneline --reverse origin/staging..HEAD
    gh pr view <n> --json commits -q '.commits[].messageHeadline'
    

    --reverse matches git log's newest-first default to the PR commit list's oldest-first order — 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 5) and never after is how a bad push or a PR whose commit history quietly went stale between rounds goes unnoticed.

  7. 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"
    
  8. Wait for the new round, then go back to step 1. Never busy-poll in a sleep loop — pace the wait to roughly how long Greptile/Cursor take (13 minutes).

  9. Stop conditions: clean state reached (see above), or the same unresolved finding survives two consecutive rounds with no new information (surface it to the user instead of looping forever), or the user interrupts.

Reporting

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.

Hard rules

  • Never post the two re-review mentions as a single combined comment.
  • Never resolve a thread without replying to it first.
  • Never fix a finding with a hacky workaround — if the clean fix isn't obvious, find the sibling pattern elsewhere in the codebase solving the same class of problem and match it.
  • Never silently drop a finding — every thread gets either a code fix or a reasoned reply.
  • Always re-run the /ship-style sync check before every push in the loop, not just the first.