Review a code change well — engine-agnostic critical review discipline for an inline dev loop. Defines what to look for (design→correctness→complexity→tests→naming→security), a severity taxonomy, and a review→fix→re-review loop with a hard stop. Use on "review this code", "review my diff", "is this change good", "critique this implementation", "review before commit". Not a ship-gate.
npx skills add https://github.com/BlackBeltTechnology/pi-agent-dashboard --skill review-code
Code review is the discipline of judging whether a change improves the health of the codebase — not whether it is perfect. An undirected reviewer does one of two failure modes: it rubber-stamps (misses real defects) or it nit-blocks (treats every preference as mandatory and never lets the change land). This skill prevents both by giving the review a governing principle, a fixed set of dimensions to inspect in value order, a parseable severity taxonomy, and a loop with an explicit stop condition.
This is the inline development-loop reviewer — it runs after you write a non-trivial change and before you commit. It is engine-agnostic: the reviewer can be a model (invoked via a role alias), a human, or a cloud tool. Because a model-backed reviewer has effectively unlimited throughput, it is the right engine for the inner loop — run it on every non-trivial change without spending a rate-limited cloud quota.
The cloud PR gate (CodeRabbit, via the rabbit-code-review skill) is a separate, later gate reserved for the pull request — do not spend it inside the inner loop. This skill covers everything up to the commit; the ship gate covers the PR.
Distilled from Google's Engineering Practices ("The Standard of Code Review", "What to look for"), the Conventional Comments spec, and the local severity→fix loop.
When NOT to use:
rabbit-code-review), run once, at the PRdoubt-driven-review (per-decision, not per-diff)systematic-debugging> Pass the change when it *definitely improves* code health. Not when it is perfect.
This is the single most important rule, because it is what *ends* the loop. A reviewer without it keeps finding one more nitpick forever and the change never lands. Approve once no blocking defect remains — even if you can still imagine improvements. Leave the non-blocking improvements as labelled suggestions the author may take or defer.
Two corollaries:
suggestion: for the rest is better than a change stalled on a reviewer's ideal.Review every changed line, in context, highest-value dimension first. Most defects that matter live near the top of this list; do not spend the review budget on naming while a design flaw goes unexamined.
1. DESIGN Does the change fit the system? Right layer, right seam?
Does it integrate, or bolt on? (highest-value — a wrong
design is expensive later; a wrong variable name is cheap.)
2. CORRECTNESS Does it do what it claims? Edge cases, error paths,
concurrency/races, boundary values, empty/null inputs.
3. COMPLEXITY Is it more complex than it needs to be? Over-engineering
and speculative generality (YAGNI) — solve the problem
that exists now, not a hypothetical future one.
4. TESTS Are there tests, and do they test behaviour (not just
cover lines)? Would they fail if the code were wrong?
5. NAMING Do names reveal intent? Could a reader guess wrong?
6. COMMENTS Do comments explain WHY, not WHAT? (What is in the code.)
7. CONSISTENCY Does it match the repo's conventions and style?
8. SECURITY Untrusted input, secrets, authz, injection. On any hit,
escalate to the `security-hardening` skill.
9. DOCS Are public surfaces / behavioural changes documented?
Also, deliberately look for something done well and say so — a sincere praise: per review is part of the discipline, not decoration.
Every finding carries a label so the author (or the loop) knows what is mandatory versus optional. Without labels, everything reads as blocking and the change stalls. Based on Conventional Comments; the blocking / non-blocking decoration is what the loop keys on.
| Label | Meaning | Blocks the loop? |
|---|---|---|
| issue(blocking) | A real defect that must be fixed before pass — wrong behaviour, a design flaw, a security hole, a missing critical test | Yes |
| issue(non-blocking) | A real but low-stakes defect; fine to fix now or file a follow-up | No |
| suggestion | An improvement; the author decides. Pair with the concrete change | No |
| nitpick | Trivial preference (style, phrasing). Never blocks | No |
| question | You are unsure a problem exists — ask for intent before judging | No (resolve first) |
| praise | Something genuinely good. Aim for ≥1 per review | No |
Finding format (explain the reasoning, point at the fix):
<label>[(blocking|non-blocking)]: <one-line subject>
path/to/file.ts:42 — why this is a problem, and the suggested change.
Rules for writing findings (from Google's "How to write comments"):
nitpick to issue(blocking) to force it.Coherence-preserving: the reviewer and the fixer share the same context, so the fix understands the change's intent.
1. Review every changed line across the dimensions → emit labelled findings.
2. Triage: collect all issue(blocking) + issue(non-blocking) you intend to fix.
3. Fix them SURGICALLY — smallest safe change per finding. Every changed line
traces to a finding. Do NOT refactor adjacent code "while you're here".
4. Re-review the new diff (fixes can introduce defects).
5. Repeat 1–4 until only non-blocking / suggestion / nitpick / praise remain.
6. PASS. Leave remaining suggestions labelled for the author to take or defer.
The stop condition is the governing principle made mechanical: zero issue(blocking) remaining ⇒ pass. Do not loop on suggestions.
rabbit-code-review / CodeRabbit), run once at the pull request, where its GitHub integration and auto-fix loop earn their cost. Never call it inside the inner loop — that spends the quota you need at ship time.question: and get it before judging.question:) firstpraise: ever — you are only modelling fault-findingissue(blocking) findings were fixed surgically and the diff re-reviewedTake blackbelttechnology/review-code from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.