Linters catch syntax errors. Formatters fix indentation. Type checkers enforce contracts. None of them know that your team stopped using moment.js six months ago, or that direct database queries in controller files violate your architecture, or that the intern’s “refactor” quietly removed the rate limiter from your payment endpoint.
That’s the gap a code review skill fills. It encodes the things your senior engineers catch in pull requests โ the tribal knowledge, the “we learned this the hard way” rules, the patterns that are correct in general but wrong for your codebase. This tutorial walks through building one from scratch, with a complete SKILL.md you can adapt for your team.
What You’ll Build
By the end of this tutorial, you’ll have a working code review skill that:
- Catches architectural violations โ wrong imports, misplaced logic, broken layer boundaries
- Flags security patterns your linter doesn’t know about โ missing auth checks, exposed internal IDs, unsafe deserialization
- Enforces team conventions โ naming patterns, error handling standards, logging requirements
- Runs automatically when Claude is asked to review code or open a PR
Total time: about 15 minutes to create, then ongoing refinement as you discover new failure points.
Prerequisites
You need Claude Code installed and a basic understanding of how skills work. If you haven’t built a skill before, read Build Your First Agent Skill in 15 Minutes first โ it covers the fundamentals of SKILL.md structure, frontmatter, and file organization.
Step 1: Create the Directory Structure
Start by setting up the skill’s file layout. Code review skills benefit heavily from progressive disclosure โ the core review instructions stay in SKILL.md while detailed reference material lives in separate files.
mkdir -p code-review-skill/references
mkdir -p code-review-skill/examples
# Create the files
touch code-review-skill/SKILL.md
touch code-review-skill/references/architecture-rules.md
touch code-review-skill/references/security-checklist.md
touch code-review-skill/examples/good-review.md
touch code-review-skill/examples/bad-review.md
This structure keeps the main SKILL.md focused on workflow and gotchas. Claude loads the detailed rules from references/ only when it’s actually performing a review, saving context window space during unrelated tasks.
Step 2: Write the Frontmatter
The frontmatter determines when Claude activates your skill. Get this wrong and the skill sits unused. Here’s what works for code review:
---
name: code-review
description: >
Use when reviewing code, pull requests, diffs, or merge requests.
Triggers on: "review this code", "review my PR", "check this diff",
"code review", "what's wrong with this code", "review before merging",
"check for issues", "audit this file".
NOT for: writing new code, refactoring (use refactor skill),
generating tests (use test-generator skill).
---
Notice the explicit trigger phrases โ these are the actual words developers use when they want a code review. The NOT for section prevents the skill from activating on refactoring requests or test generation, which overlap in surface-level language but need different workflows.
If you’re publishing to AgentSkillExchange or ClawHub, the description field is what determines discoverability. Anthropic engineer Thariq has emphasized that this field is for the model, not for humans โ Claude reads it to decide whether to activate the skill.
Step 3: Write the Core Review Workflow
The main SKILL.md body defines how Claude should approach code reviews. Resist the urge to script every step. Instead, provide a framework that Claude adapts based on context:
# Code Review Skill
When reviewing code, follow this priority order:
## Review Priority
1. **Security** โ authentication, authorization, input validation, data exposure
2. **Correctness** โ logic errors, edge cases, race conditions, error handling
3. **Architecture** โ layer violations, dependency direction, separation of concerns
4. **Performance** โ N+1 queries, unnecessary allocations, missing indexes
5. **Maintainability** โ naming, complexity, duplication, documentation
Do NOT review for style or formatting โ the linter handles that.
## Review Format
For each issue found, provide:
- **File and line** โ exact location
- **Severity** โ ๐ด Must fix, ๐ก Should fix, ๐ต Consider
- **What's wrong** โ one sentence
- **Why it matters** โ the actual risk or consequence
- **Fix** โ concrete code suggestion
If the code is clean, say so. Don't manufacture issues.
## Architecture Rules
Read `references/architecture-rules.md` for project-specific
architecture patterns and layer boundaries.
## Security Checklist
Read `references/security-checklist.md` for the full security
review checklist. Always run through this for any code touching
authentication, payments, or user data.
Two things matter here. First, the priority order โ it tells Claude what to focus on first, so reviews aren’t a random grab bag of nitpicks. Second, the instruction to not manufacture issues. Without this, Claude tends to find “problems” in perfectly fine code just to produce output.
Step 4: Build the Gotchas Section
This is the section that separates a useful skill from a generic one. Gotchas capture the failure modes specific to your codebase โ the things Claude will get wrong until you tell it otherwise.
Here’s an example gotchas section for a Node.js/Express codebase:
## Gotchas
### Architecture
- Controllers must NOT import from `src/repositories/` directly.
Always go through the service layer: Controller โ Service โ Repository.
The model frequently suggests "simplifying" by removing the service layer.
Don't allow it.
- Files in `src/shared/` must not import from any feature module
(`src/features/*`). Shared utilities are downstream dependencies, not
upstream consumers. Claude regularly misses this dependency direction.
- Event handlers in `src/events/` must be idempotent. If the handler
creates a record, it must check for existence first. Claude tends to
write handlers that fail silently on duplicate events instead of
handling them explicitly.
### Security
- Any endpoint accepting user IDs must verify the requesting user has
access to that resource. Claude often generates endpoints that accept
a userId parameter without checking `req.user.id === userId` or
verifying org membership. This is an IDOR vulnerability.
- The `sanitizeHtml` import is from our internal package
`@company/sanitize`, NOT from the npm `sanitize-html` package.
They have different APIs. Claude picks the wrong one about 40% of
the time because the npm package has more training data.
- Rate limiting is configured at the route level in `src/middleware/`,
not in individual controllers. If Claude suggests adding rate limiting
inside a controller function, that's wrong โ point it to the
middleware pattern.
### Common False Positives
- The `any` type in `src/legacy/` files is intentional. We're
migrating incrementally. Don't flag legacy files for type safety
unless the PR specifically touches type definitions.
- `console.log` in `scripts/` directory is fine. It's not fine
anywhere else. Use the `logger` service.
Every one of these entries comes from a real mistake โ something that actually happened during code review that Claude (or a junior developer) got wrong. The “Common False Positives” subsection is particularly valuable: it prevents Claude from wasting review time on things that look wrong but are intentional choices.
Step 5: Create Reference Files
Move the detailed checklists and rules into references/ so they’re loaded on demand rather than on every skill activation.
references/architecture-rules.md
# Architecture Rules
## Layer Boundaries
```
โโโโโโโโโโโโโโโ
โ Controllers โ โ HTTP handling only, no business logic
โโโโโโโโโโโโโโโค
โ Services โ โ Business logic, orchestration
โโโโโโโโโโโโโโโค
โ Repositories โ โ Data access, queries
โโโโโโโโโโโโโโโค
โ Models โ โ Data structures, validation
โโโโโโโโโโโโโโโ
```
### Import Rules
- Controllers โ Services โ
- Controllers โ Repositories โ
- Services โ Repositories โ
- Services โ Other Services โ
(but watch for circular deps)
- Repositories โ Models โ
- Models โ nothing โ
(pure data layer)
- Anything โ Shared โ
- Shared โ Feature modules โ
### File Naming
- Controllers: `*.controller.ts`
- Services: `*.service.ts`
- Repositories: `*.repository.ts`
- Tests mirror source: `*.test.ts` next to the file they test
### Error Handling
- Controllers catch errors and map to HTTP responses
- Services throw domain errors (`AppError` subclasses)
- Repositories throw `DatabaseError` for connection/query failures
- Never catch and swallow errors silently
references/security-checklist.md
# Security Review Checklist
Run through these for any code touching auth, payments, or user data.
## Authentication
- [ ] Endpoints have appropriate auth middleware
- [ ] Token validation occurs before any data access
- [ ] Refresh token rotation is implemented (not reused)
- [ ] Session invalidation on password change
## Authorization
- [ ] Resource ownership verified (no IDOR)
- [ ] Role checks use middleware, not inline conditionals
- [ ] Admin routes separated in route config
- [ ] Bulk operations verify access for ALL resources, not just the first
## Input Validation
- [ ] Request body validated with schema (zod/joi)
- [ ] URL parameters validated (no raw string interpolation into queries)
- [ ] File uploads checked for type AND content (not just extension)
- [ ] Pagination parameters bounded (max limit enforced)
## Data Exposure
- [ ] Responses exclude internal IDs, timestamps, or metadata not needed by client
- [ ] Error responses don't leak stack traces in production
- [ ] Logs don't contain PII, tokens, or credentials
- [ ] Database queries use SELECT with explicit columns, not SELECT *
Step 6: Add Review Examples
Examples are the most underrated part of skill design. A single good review example teaches Claude more about your expected output format than a page of instructions.
examples/good-review.md
# Example: Good Review Output
## Review: PR #342 โ Add user invitation endpoint
### ๐ด Must Fix
**`src/controllers/invite.controller.ts:28`**
The endpoint accepts `orgId` from the request body but doesn't verify
the requesting user belongs to that organization.
**Why:** Any authenticated user can send invitations on behalf of any
org. This is an IDOR vulnerability.
**Fix:**
```typescript
// Before (vulnerable)
const { orgId, email } = req.body;
await inviteService.sendInvite(orgId, email);
// After (secure)
const { orgId, email } = req.body;
const membership = await orgService.getMembership(req.user.id, orgId);
if (!membership || membership.role !== 'admin') {
throw new ForbiddenError('Not authorized to invite to this org');
}
await inviteService.sendInvite(orgId, email);
```
### ๐ก Should Fix
**`src/services/invite.service.ts:15`**
The invitation email is sent synchronously inside the request handler.
If the email service is slow or down, the API response hangs.
**Why:** Email delivery failures shouldn't break the invitation flow.
**Fix:** Emit an event and handle email sending asynchronously:
```typescript
await inviteRepository.create({ orgId, email, token });
eventBus.emit('invite.created', { orgId, email, token });
// Email sent by event handler, not blocking the response
```
### โ
Looks Good
- Input validation with zod schema
- Rate limiting applied at route level
- Invitation token has 24h expiry
The example demonstrates the exact format: severity emoji, file/line location, explanation of the risk (not just “this is wrong”), and a concrete fix with before/after code. Claude will mirror this format in its reviews.
Step 7: Install and Test
With the files in place, install the skill:
# If using repo-checked skills (recommended for team skills)
cp -r code-review-skill/ .claude/skills/code-review/
# Or install via ClawHub for personal use
clawhub publish code-review-skill/
Test it by asking Claude to review real code from your project. Not toy examples โ actual pull requests with real issues. The first few reviews will reveal gaps in your gotchas section. That’s expected. Fill them in as you go.
Effective prompts for testing:
"Review the changes in my current git diff"
"Review src/controllers/payment.controller.ts for security issues"
"Check this PR for architectural violations"
If Claude misses something you’d catch manually, add it to the gotchas. If Claude flags something that’s actually fine, add it to the false positives. After a week of active use, your gotchas section will be significantly more useful than it was on day one.
Extending the Skill: Hooks for Automatic Reviews
Skills can register on-demand hooks that run automatically during certain operations. For code review, the most useful hook triggers before Claude creates a commit or opens a PR:
## Hooks
### PreToolUse: create_pull_request
Before creating a PR, automatically run the full review checklist on the
staged changes. If any ๐ด (Must Fix) issues are found, block the PR
creation and report the issues.
This turns the skill from a passive tool (Claude reviews when asked) into an active guardrail (Claude reviews before every PR). Teams at companies with strict review standards find this pattern particularly valuable โ it catches issues before a human reviewer even sees the code.
Common Mistakes to Avoid
After reviewing dozens of code review skills submitted to AgentSkillExchange, these are the patterns that consistently produce poor results:
- Restating linter rules. If ESLint or Prettier already catches it, don’t put it in your skill. You’re wasting context tokens on solved problems.
- Generic security advice. “Validate all inputs” is useless. “The
userIdparameter in/api/admin/*routes must be verified againstreq.user.orgIdbecause our admin routes are org-scoped, not globally scoped” is useful. - Reviewing everything at once. A skill that tries to check architecture, security, performance, accessibility, and style in one pass produces shallow reviews across all categories. The priority ordering approach (security โ correctness โ architecture) produces deeper analysis of what matters most.
- No examples. Without a concrete review example, Claude will produce reviews in whatever format feels natural that day. That format changes. Pin it down with an example.
- Hardcoding project paths. If your skill references
/Users/yourname/projects/myapp/src/, it works for you and nobody else. Use relative paths and let the file structure speak for itself.
The Complete File Listing
Here’s everything in the skill directory once you’re done:
code-review-skill/
โโโ SKILL.md # ~80 lines: workflow, priorities, gotchas
โโโ references/
โ โโโ architecture-rules.md # Layer boundaries, import rules, naming
โ โโโ security-checklist.md # Auth, authz, input, data exposure checks
โโโ examples/
โโโ good-review.md # Model review output with correct format
โโโ bad-review.md # Anti-patterns to avoid in reviews
Total content: roughly 200 lines across all files. That’s intentional. A code review skill doesn’t need to be comprehensive โ it needs to be specific to the gaps in your existing toolchain.
Frequently Asked Questions
Can I use this for languages other than TypeScript?
Yes. The structure and approach are language-agnostic. Replace the architecture rules and security checklist with patterns relevant to your stack. A Python/Django review skill would have different layer boundaries (views โ serializers โ models) but the same gotchas-driven approach.
How many gotchas should I start with?
Five to ten is a good starting range. Don’t try to anticipate every failure mode upfront. Start with the issues you’ve seen in actual code reviews over the past month, then add entries as Claude misses things during use.
Should the skill be repo-specific or general?
Both, using progressive disclosure. Keep the SKILL.md general (review priorities, output format, hooks) and put project-specific rules in references/. When you move to a new project, swap the reference files and the skill adapts.
How do I share this with my team?
The simplest method: commit the skill to .claude/skills/code-review/ in your repo. Every team member using Claude Code gets the skill automatically when they work in that repository. For cross-repo skills, publish to AgentSkillExchange or your team’s internal ClawHub instance.
What’s Next
A code review skill is a living document. The gotchas section should grow every week as you discover new failure points. The security checklist should evolve as your application changes. Treat it like you’d treat any other piece of your development infrastructure: version it, review changes, and keep it current.
If you build a code review skill that works well for your stack, consider publishing it on AgentSkillExchange. The ecosystem grows when teams share what they’ve learned โ and your hard-won gotchas might save another team from the same mistakes.
Tomorrow on the blog: MCP vs. Agent Skills: What’s the Difference and When to Use Each โ clearing up the most common confusion in the agent tooling ecosystem.