review-loop
review-loop
Iterates code review until convergence — addressing every comment, re-requesting review, and stopping only when the diff is clean and approved. Use after opening a pull request, when review feedback arrives in batches, or when closing out comments one-by-one loses track of what remains.
- Category
- Category: loop-engineering
- code-review
- pull-request
- iteration
- feedback
- convergence
Install this skill
npx . --tool claude-code --only review-loopRun from a git checkout of this repo — see the README for details.
When to apply
Use whenever a change is under review: after opening a pull request, when review comments arrive, or when fixes spawn further comments. The loop's exit condition is an approved, comment-free diff — not "I replied to everything".
Workflow
- Inventory — List every review comment and CI check. Each gets an entry:
comment → owner (you) → state (open/done/disputed). - Triage each comment into:
- Fix — address exactly as asked
- Clarify — comment was based on a misreading; answer precisely, change nothing
- Dispute — you believe the reviewer is wrong; state your reasoning and evidence, offer to defer
- Apply fixes in the review's priority order — blocking comments before nits. Keep each fix minimal (see minimal-fix).
- Re-run the verification chain — typecheck, tests, build. A comment addressed by code that breaks CI was not addressed.
- Re-request review with a summary: what changed per comment, what's disputed and why.
- Check convergence:
- New comments on previously-commented lines → keep looping
- Only style nits remain → apply or dispute once, then loop
- Zero open comments + green CI + approval → done
Worked example
PR #42: "Add user profile page"
Round 1 review — 3 comments:
| # | Comment | State | Action |
|---|--------------------------------------|----------|---------------------------------|
| 1 | "Loading state missing" | open | Fix: add Suspense fallback |
| 2 | "Why not use useQuery here?" | open | Clarify: useQuery needs a cache |
| | | | we don't have yet; noted in TODO |
| 3 | "Rename `data` to `profile`" | open | Fix: renamed |
Apply fixes → run tests → re-request review with summary:
"1: fixed (added Suspense fallback). 2: clarified (no query cache yet,
filed #43). 3: fixed (renamed)."
Round 2 review — 1 comment:
| # | Comment | State | Action |
|---|--------------------------------------|----------|---------------------------------|
| 4 | "Fallback should show skeleton" | open | Fix: replaced spinner w/ skeleton |
Apply → test → re-request. Round 3: LGTM, CI green. **Done.**
Stop conditions
- Approver says LGTM and no blocking checks remain → exit success
- A dispute cannot be resolved after two exchanges → escalate to a human decision, don't relitigate
- Loop count exceeds ~5 on the same comment → something is structurally wrong with the change; propose closing and splitting it
Rules
- Never mark a comment "done" without the diff to show for it.
- Replies to every comment, even the ones you fix silently — reviewers shouldn't diff your diff to discover your response.
- Do not add unrelated improvements mid-review; they reset the review and the loop.
Related skills
- minimal-fix — The shape of each individual fix inside the loop.
- loop-verifier — What the reviewer is (ideally) running on their side.