Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.
.claude/skills/penpot-code-review/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 172% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 164% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 134% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 148% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 151% | 0% |
Multi-dimensional code review with quality gates. Every change gets reviewed before merge — no exceptions. Review covers five axes: correctness, readability, architecture, security, and performance.
The approval standard: Approve a change when it definitely improves overall code health, even if it isn't perfect. Perfect code doesn't exist — the goal is continuous improvement. Don't block a change because it isn't exactly how you would have written it. If it improves the codebase and follows the project's conventions, approve it.
These principles underpin every axis. When in doubt, default to them.
Every review evaluates code across these dimensions.
Does the code do what it claims to do?
Can another engineer (or agent) understand this code without the author explaining it?
temp, data, result without context)// removed comments?Does the change fit the system's design?
any/unknown/optional/casts and silent fallbacks.For detailed security guidance, see security-and-hardening.
| Prefix | Meaning | Author Action | |--------|---------|---------------| | Critical: | Blocks merge | Security vulnerability, data loss, broken functionality | | High: | Required change | Must address before merge | | Medium: | Should fix | Strongly recommended, not a blocker | | Low: | Minor, optional | Author may ignore — formatting, style preferences | | Suggestion: | Worth considering | Not required, but improves the code |
Unique finding IDs. Assign every finding a stable identifier: F1, F2, F3, … numbered in order of severity (Critical first, then High, Medium, Low, Suggestion). Use the ID everywhere the finding is mentioned — in section headers, in the verdict, in follow-up discussion. Never renumber within a review. Example: **F3 (High)** — app/validate.cljs:42 — duplicate branch logic….
For each finding, describe the circumstances under which it could fail: specific inputs, load conditions, timing, or user actions that trigger the problem. "This crashes when input is null" is actionable; "this might crash" is not.
Lead with what matters: correctness and security first, then structural issues, then everything else. A few high-conviction comments beat a long list.
Structure every review using this format:
Briefly explain what the code does and give an overall assessment.
List problems that could cause security incidents, data loss, crashes, incorrect behavior, or major performance degradation. Each finding gets its unique ID (F1, F2, …). For each: state the severity, identify the file/function/code section, explain why it's a problem, describe failure circumstances, and provide a concrete improvement with corrected code when useful.
List medium- and low-priority issues, including maintainability and design concerns. Continue the ID sequence started above (F3, F4, …).
Provide focused code changes or revised snippets. Preserve existing behavior unless a behavior change is explicitly justified.
Identify missing tests and describe specific test cases, including edge cases and failure scenarios.
Mention implementation choices that are clear, safe, efficient, or well designed. This is not fluff — it reinforces good patterns and tells the author what to keep doing.
Choose one:
List the finding IDs the verdict depends on (e.g. "Request changes: F1, F4").
Small, focused changes are easier to review, faster to merge, and safer to deploy.
~100 lines changed → Good. Reviewable in one sitting.
~300 lines changed → Acceptable if it's a single logical change.
~1000 lines changed → Too large. Split it.Watch file size, not just diff size. Around 1000 total lines in a single file is a common inspection signal. When a change materially grows an already-large file, decompose first.
Splitting strategies:
| Strategy | How | When | |----------|-----|------| | Stack | Submit a small change, start the next one based on it | Sequential dependencies | | By file group | Separate changes for groups needing different reviewers | Cross-cutting concerns | | Horizontal | Create shared code/stubs first, then consumers | Layered architecture | | Vertical | Break into smaller full-stack slices of the feature | Feature work |
Separate refactoring from feature work. A change that refactors and adds new behavior is two changes — submit them separately.
Before adding any dependency:
npm audit)Rule: Prefer standard library and existing utilities over new dependencies. Every dependency is a liability.
Upgrading dependencies:
package.json. Commit it and never hand-edit it.For supply-chain risk triage, follow the security-and-hardening skill.
| Rationalization | Reality | |---|---| | "It works, that's good enough" | Working code that's unreadable, insecure, or architecturally wrong creates debt that compounds. | | "I wrote it, so I know it's correct" | Authors are blind to their own assumptions. Every change benefits from another set of eyes. | | "We'll clean it up later" | Later never comes. The review is the quality gate — use it. | | "AI-generated code is probably fine" | AI code needs more scrutiny, not less. It's confident and plausible, even when wrong. | | "The tests pass, so it's good" | Tests are necessary but not sufficient. They don't catch architecture, security, or readability problems. | | "The refactor makes it cleaner" | Relocating complexity isn't reducing it. If the reader still holds the same number of concepts, the structure didn't improve. | | "It's only a small addition to this file" | Small diffs still push files past healthy size and bolt branches onto unrelated flows. | | "It's just a version bump" | A bump is a behavior change you didn't write. Read the changelog. | | "I'll upgrade everything in one PR" | A bulk bump hides which package broke the build. One per change. | | "It's duplicated but it's only two places" | Two becomes three becomes five. Extract now, before the copies diverge. | | "The abstraction is future-proof" | YAGNI. Delete speculative generality — generalize on the third occurrence, not the first. | | "It's clever but efficient" | Cleverness is a readability tax. If it needs a comment to understand, simplify it. |
Before emitting the verdict, verify the change as it stands. This is the reviewer's own due diligence — it covers the state of the code at review time, not the later resolution of findings (fixing findings is the author's job; confirming them is a new review):
security-and-hardening| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 43,204 | 14,024 | -68% | 1 | 1 | 0% | 8,311 | 5,008 | -40% | 0 | 0 | — |
case-02 | fail→fail | 38,461 | 60,577 | +58% | 1 | 1 | 0% | 6,835 | 9,282 | +36% | 0 | 0 | — |
case-03 | fail→fail | 31,419 | 43,564 | +39% | 1 | 1 | 0% | 5,348 | 4,439 | -17% | 0 | 0 | — |
case-04 | fail→pass | 9,806 | 7,277 | -26% | 1 | 1 | 0% | 1,575 | 4,283 | +172% | 0 | 0 | — |
case-05 | fail→pass | 8,954 | 4,232 | -53% | 1 | 1 | 0% | 1,428 | 3,777 | +164% | 0 | 0 | — |
case-06 | pass→pass | 30,749 | 13,689 | -55% | 1 | 1 | 0% | 2,490 | 5,095 | +105% | 0 | 0 | — |
case-07 | pass→pass | 12,734 | 12,700 | -0% | 1 | 1 | 0% | 1,897 | 5,112 | +169% | 0 | 0 | — |
case-08 | pass→pass | 11,860 | 11,376 | -4% | 1 | 1 | 0% | 1,692 | 4,923 | +191% | 0 | 0 | — |
case-09 | fail→pass | 28,257 | 13,470 | -52% | 1 | 1 | 0% | 2,161 | 5,060 | +134% | 0 | 0 | — |
case-10 | pass→pass | 10,344 | 8,737 | -16% | 1 | 1 | 0% | 1,469 | 4,506 | +207% | 0 | 0 | — |
case-11 | fail→pass | 13,197 | 12,641 | -4% | 1 | 1 | 0% | 2,003 | 4,971 | +148% | 0 | 0 | — |
case-12 | pass→pass | 10,619 | 8,392 | -21% | 1 | 1 | 0% | 1,678 | 4,342 | +159% | 0 | 0 | — |
case-13 | pass→pass | 15,865 | 10,497 | -34% | 1 | 1 | 0% | 1,815 | 4,807 | +165% | 0 | 0 | — |
case-14 | pass→pass | 9,545 | 8,766 | -8% | 1 | 1 | 0% | 1,502 | 4,283 | +185% | 0 | 0 | — |
case-15 | fail→pass | 17,744 | 10,921 | -38% | 1 | 1 | 0% | 1,985 | 4,983 | +151% | 0 | 0 | — |
case-16 | pass→pass | 7,589 | 4,792 | -37% | 1 | 1 | 0% | 1,017 | 3,892 | +283% | 0 | 0 | — |
case-17 | pass→pass | 15,641 | 12,039 | -23% | 1 | 1 | 0% | 1,949 | 5,202 | +167% | 0 | 0 | — |
case-18 | pass→pass | 9,715 | 8,141 | -16% | 1 | 1 | 0% | 1,230 | 4,425 | +260% | 0 | 0 | — |
case-19 | pass→pass | 39,462 | 9,958 | -75% | 1 | 1 | 0% | 2,114 | 4,645 | +120% | 0 | 0 | — |
case-20 | pass→pass | 10,647 | 20,345 | +91% | 1 | 1 | 0% | 1,983 | 5,807 | +193% | 0 | 0 | — |
case-21 | pass→pass | 6,562 | 6,234 | -5% | 1 | 1 | 0% | 1,097 | 4,205 | +283% | 0 | 0 | — |
case-22 | fail→fail | 5,680 | 7,358 | +30% | 1 | 1 | 0% | 824 | 3,985 | +384% | 0 | 0 | — |
case-23 | pass→pass | 18,764 | 21,237 | +13% | 1 | 1 | 0% | 3,110 | 6,362 | +105% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +22 percentage points is the difference between those two pass rates over the 23 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.