Install
openclaw skills install @dennisrongo/code-reviewProduction-readiness code review at either scope — the uncommitted working tree (default) or a committed branch grouped per #NNN task (references/branch-review.md). Hunts DRY violations, dead code, leaky abstractions, missing error handling; auto-detects and runs the project's tests and build; findings categorized blocking/suggestion/question/nit/praise, and never edits code without permission — report first, ask, then fix. Non-trivial diffs get a lens council: parallel Explore sub-agents (correctness/design/security/tests/production-readiness) plus an adversarial critique round; small diffs skip it. Use this skill whenever the user says "code review", "review my code", "review the diff", "review my PR", "review my branch", "check my uncommitted changes", "is this production ready", "DRY check", or "/code-review" — even if they don't explicitly say "code review skill". Dirty tree → working-tree scope; "branch"/"PR" or clean tree with branch commits → branch scope.
openclaw skills install @dennisrongo/code-reviewReview code changes against DRY and common software-engineering best practices, verify the project still builds and its tests still pass, and surface findings as recommendations the user can act on — without editing code unprompted.
/code-review#NNN task with one verdict each, per references/branch-review.md.Never blend scopes into one report. Both apply (dirty tree and branch commits, user said "review everything") → ask which, or run them as two clearly separated reports.
If you find issues, do not start editing. Produce the findings report first. After delivering it, ask the user, per issue or per batch: "Want me to fix #N?" — and wait for an explicit yes before touching code. If the user pre-authorizes the whole batch ("fix them all"), proceed; otherwise default to ask-per-fix.
This rule overrides any general "be helpful, fix it" instinct. A drive-by refactor mid-review collapses the user's mental model of what changed.
The review pass is also read-only on git state: no checkout, stash, reset, rebase, or branch switching while reviewing — only git status / diff / show / log. Need a working copy of another revision? git worktree add /tmp/review-<sha> <sha> — never move HEAD on the user's checkout.
A claim about code you haven't opened this session is a hypothesis — verify it or label it as one.
Read the full enclosing function — and the whole file when it's small. Most false "missing null check" / "unhandled error" findings dissolve when you see the guard 10 lines above the hunk, or the caller that validates. A finding based only on diff-hunk context is not reportable.Grep for the identifier first. Cite the search in the finding: "no callers found (grep -rn 'buildQuery' src/)".question ("cannot verify from diff: …"), never silently passed. If the problem is with the plan rather than the implementation, say that.git status --short — see what's modified, staged, untracked.git diff — unstaged changes.git diff --staged — staged changes.git diff <base>...HEAD belongs to branch scope — see references/branch-review.md.package.json → npm test, npm run build (or pnpm / yarn if the lockfile says so)pyproject.toml / pytest.ini → pytest, plus python -m build or project-specific*.csproj / *.sln → dotnet build, dotnet testgo.mod → go build ./..., go test ./...Cargo.toml → cargo build, cargo testMakefile → check for test / build targets firstturbo.json, nx.json, pnpm-workspace.yaml) → use the orchestratorExplore sub-agents — one per lens — then run an adversarial critique round before reporting.
Earlier categories outrank later ones — a correctness bug makes a readability nit irrelevant.file:line so the user can jump to it.blocking / suggestion / nit / praise (see Categories).When the user says "fix them" — or when a lens sub-agent, a CI bot, or a human reviewer hands you findings — the findings are testimony, not instructions:
X does Y. Fixing." and move on; no apology essay.api/user.ts:42"). The diff is the acknowledgment.On GitHub, replies to inline review comments go in the comment thread (gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies), not as a new top-level PR comment.
These rules govern the fix-application phase only — they don't change the report itself.
// TODO without an issue link. One short line max — no multi-line comment blocks, no multi-paragraph docstrings. If the fix needs a comment to be understandable, the fix probably needs better names instead.// removed, // was: X trails. If you deleted something, delete it. Git history is the audit log.blocking — must fix before ship: bug, broken contract, security hole, build/test failure, missing migration, hard-coded secret. Burden of proof: a blocking finding must include a one-sentence concrete failure scenario (this input/state → this wrong outcome). If you cannot write that sentence, demote to suggestion.suggestion — would improve the code; user can take or leave. DRY consolidations, dead-code removal, missing error handling on non-critical paths.question — the author may know something you don't; ask before asserting. Also the landing spot for lens-council contradictions the user should adjudicate.nit — style/preference; never blocks.praise — something done well, cited to a specific file:line ("the retry wrapper at http.ts:40 is exactly right for this flaky API"). Generic filler ("nice clean code!") is worse than omitting the section. Include one only when it's genuine.Lead each finding with the why. "This swallows the exception so a failure here is silently lost" beats "add error handling".
Same finding, written badly and well:
fetchUser — api/user.ts:42. (No failure scenario, no consequence, one citation — reads as a reflex; the reviewer can't verify it or weigh it.)api/user.ts:42. Why: fetchUser rejects on 404, but ProfilePage (pages/profile.tsx:18) never catches — visiting a deleted user's profile renders a blank page with an unhandled rejection. Fix: catch in ProfilePage and render the not-found state.The ✅ names the trigger, the concrete consequence, and both file:line sites — verifiable without re-deriving it.
Priority order — review top-to-bottom, stop wasting tokens on lower categories once a higher one is on fire.
==This is the user-emphasized lens — apply it explicitly.
sleep, ordering assumptions, network).eval without escaping/parameterization.md5, sha1 for security use), hardcoded keys/IVs.console.log / print / Debug.WriteLine of PII or tokens.console.log, print, TODO: remove, // debug, commented-out blocks, scratch files..env.example.data, result) instead of what for.Only mention if the project has no formatter / linter. Otherwise trust the tools.
A single pass through the priority list anchors on whatever you saw first. For non-trivial diffs, run the lenses in parallel and then have them critique each other before publishing findings.
Otherwise stay single-pass. The council is overhead on a 20-line change.
Spawn one sub-agent per lens. Default set (skip lenses that don't apply — e.g. no schema changes → no migration sub-lens within prod-readiness):
| Lens | Looks for | Aligns with |
|---|---|---|
| Correctness | Off-by-one, null/undefined, race conditions, swallowed errors, default-value behaviour shifts, tz/locale assumptions | §1 |
| Design / DRY | Duplication that should unify, premature abstraction, single-responsibility violations, leaky abstractions, tight coupling, magic values, public-API breakage | §2 |
| Security | Untrusted input into sinks (shell/SQL/HTML/path/eval), secrets in code or logs, missing authn/authz, weak crypto, unsafe deserialization | §4 |
| Tests | Assertion-free / over-mocked / snapshot-only tests, missing edge cases, flaky-by-design tests, new behaviour with no test, test names that don't describe verification | §3 |
| Production-readiness | Debug residue, missing/spammy logging, no observability on new failure modes, undocumented env vars, schema change without migration, error messages leaking internals, missing feature flag, wire/DB breakage without deprecation | §6 |
Performance (§5), readability (§7), and style (§8) usually roll into Design — only spawn a dedicated lens for them if the diff is genuinely perf-sensitive or the project has no linter.
Agent calls (subagent_type=Explore). Each lens gets:
blocking / suggestion / nit; a blocking must state a one-sentence concrete failure scenario. Cite file:line for every finding. Lead each finding with the why. If your lens has no findings, say 'no findings' explicitly — do not pad. You do not spawn sub-agents and you do not mutate the working tree or git state. Report in ≤500 words."blocking — "is this actually exploitable / actually a bug / would this actually break in production?" Demote to suggestion or drop if the answer is no when you read the surrounding code.Lenses run: <list>. <N> findings raised by sub-agents, <M> dropped on critique.The user sees one clean report, not five agent transcripts. The transcripts stay internal — they were the deliberation.
# Code review — uncommitted changes
**Files changed:** <N> (<S staged>, <U unstaged>, <X untracked>)
**Build:** ✅ passed / ❌ failed / ⚠️ not detected
**Tests:** ✅ passed (<N>/<N>) / ❌ failed (<F> failing) / ⚠️ not detected
<paste relevant failing output, trimmed>
---
## Verdict
**Ship / Fix blockers first / Build broken**
<one-paragraph summary of the change and overall state>
---
## Blockers
### B1. <short title> — `path/to/file.ext:42`
**Why:** <root cause / consequence>
**Fix:** <concrete recommendation>
### B2. ...
## Suggestions
### S1. <short title> — `path/to/file.ext:88`
**Why:** ...
**Fix:** ...
## Nits
- `path:line` — <one-liner>
## Praise
- <thing done well>
---
## Fixes I can apply
If you want, I can apply any of: B1, B2, S1, S3. Which? (or "all", or "none")
End with the offer. Wait for the user's choice. Apply only the approved set, then re-run tests.
User: "do a code review on what I have so far"
Claude:
git status + git diff + git diff --staged in parallel.package.json → runs npm test and npm run build.B1 with the file:line, doesn't try to fix it yet.S1 (DRY consolidation) with a sketch of the extracted helper.User: "is this ready to ship?"
Claude: Reviews diff. Tests pass but the new branch in processOrder() has no test. Flags as B2 (blocking — "new behavior with no test, regression risk on next refactor"). Does not write the test silently; offers to write it after the report.
User: "review the diff and fix anything you find"
Claude: Produces the full report first anyway, then applies fixes one at a time, re-running tests between batches. Pre-authorization doesn't skip the report — it only skips the per-fix confirmation.
file:line.blocking with no concrete failure scenario. Can't write "this input → this wrong outcome"? It's a suggestion.git show or a throwaway worktree.regression-hunt (if installed) traces what the change breaks in code that didn't change. On a diff that renames, changes a default, or touches shared state, suggest running both.conventional-commits: after fixes are approved and applied, hand the commit-message authoring to that skill rather than improvising one here.