review
SkillSecurityPerform a comprehensive code review on a GitHub pull request. Use when the user asks to review a PR, review code changes, check a pull request for quality, security, bugs, or best practices, or provides a PR number or GitHub PR URL to review.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the review skill
What this skill tells your AI
The instructions your AI receives, as published by rlajous/claude-code-commands in skills/review/SKILL.md and read by ahel’s review.
Cross-runtime: follow runtime compatibility for invocation, delegation, configuration precedence, state paths, and permissions.
You are performing a comprehensive code review on a GitHub pull request. Your task is to deeply analyze the changes, identify issues across multiple dimensions, and produce a structured review document.
Step 1: Parse Arguments
Determine the PR to review:
- If a GitHub URL was provided: extract
{owner},{repo}, and{PR_NUMBER}from the URL. SetREPO_FLAG='--repo "{owner}/{repo}"' - If a PR number was provided as argument: set
REPO_FLAG="" - If no argument: check for an open PR on the current branch with
REPO_FLAG=""
# If no argument provided, try to find PR for current branch
gh pr view --json number,url 2>/dev/null || echo "NO_PR_FOUND"
If no PR is found, use the active host user-input mechanism to ask:
Question: "Which PR would you like to review? Provide a PR number or GitHub URL."
When REPO_FLAG is empty (PR number or current-branch input), resolve {owner} and {repo} from the PR metadata URL returned by Step 2's gh pr view call (which includes the url field). Parse {owner} and {repo} from the URL pattern https://github.com/{owner}/{repo}/pull/{number}.
Step 2: Fetch PR Metadata
gh pr view {PR_NUMBER} {REPO_FLAG} --json number,title,body,author,state,baseRefName,baseRefOid,headRefName,headRefOid,files,url,additions,deletions,changedFiles,labels,reviewRequests,createdAt
If {owner} and {repo} were not set in Step 1 (i.e., input was a PR number or current branch), extract them from the url field in the response (format: https://github.com/{owner}/{repo}/pull/{number}).
Error Handling:
| Scenario | Action |
|---|---|
gh not installed | Provide installation instructions: brew install gh or see https://cli.github.com |
| Not authenticated | Instruct to run gh auth login |
| PR not found | Show error, ask user to verify PR number |
| PR is merged | Inform user PR is already merged, ask if they still want to review |
| PR is closed | Inform user PR is closed, ask if they still want to review |
Step 3: Ask for Review Context
Ask the following single question through the active host user-input mechanism:
Question: "Any specific focus areas, business context, or known risks for this review? (Type 'skip' to proceed without additional context)"
Examples:
- "This touches the payment flow — watch for data integrity issues"
- "Focus on performance, we're seeing slow responses"
- "New developer's first PR, be thorough"
- "skip"
Step 4: Collect Changes
Resolve CONFIG_PATH once: use .git-workflow/config.yaml when present, otherwise .claude/config.yaml as a legacy read-only fallback. Use defaults only when neither exists.
Get the diff and assess its size:
# Get diff line count
gh pr diff {PR_NUMBER} {REPO_FLAG} | wc -l
Load from the resolved CONFIG_PATH (if one exists):
review:
maxDiffLines: 3000
Default: 3000 lines
- If diff ≤ maxDiffLines: ingest the full diff with
gh pr diff {PR_NUMBER} {REPO_FLAG} - If diff > maxDiffLines: read files individually in Step 6 (skip full diff)
Also collect the file list:
gh pr view {PR_NUMBER} {REPO_FLAG} --json files --jq '.files[].path'
Step 5: Categorize Files
Categorize changed files for prioritized review:
Priority Order:
- New source files — New code requires the most scrutiny
- Business logic — Core application code (services, models, domain logic)
- API layer — Controllers, routes, handlers, resolvers
- Infrastructure — Config, deployment, CI/CD, environment
- Tests — Test files and fixtures
- Auto-generated — Lock files, compiled output,
dist/
Skip auto-generated files:
package-lock.json,yarn.lock,pnpm-lock.yaml,Cargo.lock,poetry.lockdist/,build/,.next/,__pycache__/- Files with
// @generatedor# auto-generatedheaders
Never skip migration files:
Migration SQL files (migrations/, *migration*.sql, or SQL files altering schema/data) must always be reviewed regardless of size. Migrations can contain destructive schema changes (DROP TABLE, ALTER COLUMN, etc.) that are critical to catch during review.
For large PRs (30+ changed files):
Prioritize review in this order: new files → business logic → API layer → infrastructure → tests. Summarize but don't deep-review auto-generated files.
Step 6: Read Source Files
For each categorized file (in priority order):
# Read the full source file for architectural context
cat -- "{file_path}"
Important: Read full files, not just diffs. Diffs show what changed but full files reveal:
- Whether the change fits the existing patterns
- Missing error handling in surrounding code
- Architectural context for the modification
Also read key dependencies:
- If a file imports a service/module that was NOT changed, read it to understand the contract
- Read type definitions, interfaces, or schemas referenced by changed files
- Read configuration files if config was changed
Step 7: Dispatch Specialized Review Agents (parallel)
Instead of reviewing every dimension inline, fan out to focused subagents through the active host's subagent mechanism and aggregate their findings. This yields sharper, single-concern analysis than one monolithic pass.
Select aspects from $ARGUMENTS (space-separated; default all):
code— general quality + bug detection →pr-revieweragenterrors— swallowed errors / inadequate error handling →silent-failure-hunteragenttypes— type design, invariants, encapsulation →type-design-analyzeragenttests— behavioral coverage gaps →pr-test-analyzeragentcomments— comment rot / inaccurate docstrings →comment-analyzeragentall— every applicable agent (default)
Map changed files to applicable agents (only launch what applies):
| Signal in the changed files | Agent to launch |
|---|---|
| Always (any code change) | pr-reviewer |
| try/catch, error handling, fallbacks | silent-failure-hunter |
| New/modified types, interfaces, schemas | type-design-analyzer |
| Test files added/changed, or new behavior lacking tests | pr-test-analyzer |
| Comments/docstrings added or changed | comment-analyzer |
Launch in parallel: start every applicable named agent before waiting so the agents run concurrently. Give each agent the PR number/repo, baseRefOid as BASE_SHA, headRefOid as HEAD_SHA, changed-file list, and diff (or file paths for large PRs). The pr-reviewer must use BASE_SHA...HEAD_SHA when it needs to reconstruct the PR diff; it must not substitute the locally checked-out HEAD. Wait for every agent and collect all findings before continuing.
Review lenses the general
pr-reviewerpass (and your own synthesis) applies — architecture, business logic, data integrity, error handling, security, performance, testing, code quality. Use them to fill gaps the specialized agents don't cover. Full checklist: seereferences/review-lenses.md.
Step 8: Identify Open Questions
Collect questions that cannot be answered from code alone:
- Business rule ambiguities ("Should this return 404 or empty array?")
- Design intent ("Is this intentionally different from the pattern in X?")
- Volume/scale expectations ("How many concurrent users are expected?")
- External system behavior ("What does this API return on timeout?")
- Migration concerns ("Do existing records need backfilling?")
Step 9: Score, Filter, and Categorize Findings
First aggregate the findings from all specialized agents plus your own general pass, de-duplicating any that overlap (same file+line+issue).
Confidence score (0–100). Assign each finding a confidence that it is a real, actionable defect in the changed code. Only keep findings with confidence ≥ 80. Discard the rest (they add noise). This mirrors the high-signal bar used by mature review tooling.
False-positive taxonomy — drop a finding (do NOT report) if it is:
- Pre-existing — the issue is on lines this PR did not modify (not introduced by this change).
- Linter/type-checker-catchable — a lint or type error that CI would already surface.
- Intentionally silenced — explicitly suppressed via a lint-ignore/
// eslint-disable/# noqawith a reason. - Style-only nit already handled by a formatter (Prettier/Black/gofmt).
- Speculative — depends on runtime facts you cannot verify from the diff (score it below 80).
Then assign each surviving finding a severity:
| Severity | Criteria | Examples |
|---|---|---|
| BLOCKING | Deployment-preventing issues | Data loss risk, security vulnerability, broken functionality |
| HIGH | Correctness or business logic bugs | Wrong calculation, missing validation, race condition |
| MEDIUM | Robustness and maintainability | Missing error handling, tight coupling, missing tests |
| LOW | Polish and minor improvements | Naming, style, minor optimizations, documentation |
Each finding should include:
- File and line reference:
src/services/auth.ts:45 - Confidence:
0–100(only findings ≥ 80 are reported) - Issue description: What's wrong and why it matters
- Suggested fix: Concrete code or approach to resolve it
- Severity justification: Why this severity level
Step 10: Build Architecture Flow
Create an ASCII diagram tracing execution from entry point through the call chain:
Request → Controller → Service → Repository → Database
↓
Validation
↓
External API
Include:
- Entry points (HTTP endpoints, event handlers, cron jobs)
- Key function calls in order
- External system interactions (databases, APIs, queues, caches)
- Error/retry paths
Step 11: Generate Review Document
Produce a structured markdown document:
# Code Review: PR #{number} — {title}
## Metadata
| Field | Value |
|-------|-------|
| **PR** | #{number} |
| **Author** | {author} |
| **Branch** | `{head}` → `{base}` |
| **Files Changed** | {count} |
| **Additions** | +{additions} |
| **Deletions** | -{deletions} |
| **Reviewed** | {date} |
## Overall Assessment
{1-2 paragraph summary: what the PR does, whether it's ready to merge, and the most important concerns}
**Verdict**: {APPROVE | REQUEST CHANGES | NEEDS DISCUSSION}
## Architecture Flow
```
{ASCII diagram from Step 10}
```
## Questions for Author
{Numbered list from Step 8. If none, write "No open questions."}
## Findings
### BLOCKING
{Each finding with file reference, description, and suggested fix. If none, write "No blocking issues found."}
### HIGH
{Each finding with file reference, description, and suggested fix. If none, write "No high-severity issues found."}
### MEDIUM
{Each finding with file reference, description, and suggested fix. If none, omit section.}
### LOW
{Each finding with file reference, description, and suggested fix. If none, omit section.}
## What's Done Well
{Bullet list of positive observations — good patterns, thorough tests, clean design}
## Summary
| Severity | Count |
|----------|-------|
| BLOCKING | {n} |
| HIGH | {n} |
| MEDIUM | {n} |
| LOW | {n} |
| **Total** | **{n}** |
**Recommended fix priority:**
1. {Most important fix}
2. {Second most important}
3. {Third most important}
Step 12: Save Review
Load from the resolved CONFIG_PATH (if one exists):
review:
saveLocally: true
reviewsDir: docs
Defaults: saveLocally: true, reviewsDir: docs
If saveLocally is true:
# Extract feature name from branch
FEATURE_NAME=$(echo "{head_branch}" | sed 's|.*/||' | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
# Ensure directory exists
mkdir -p -- "{reviewsDir}"
# Save review document
# Write to: "{reviewsDir}/code-review-{feature-name}.md"
Write the review document to the file. Do NOT commit it.
If saveLocally is false: the review content is held in memory for posting or display. No file is written.
Step 13: Confirm Before Posting
Load from the resolved CONFIG_PATH (if one exists):
review:
postToGitHub: ask # ask | always | never
Default: ask
If postToGitHub is always: skip to Step 14.
If postToGitHub is never: skip to Step 15.
If postToGitHub is ask: use the active host user-input mechanism:
Question: "How would you like to proceed with this review?"
Options:
- Post review as a comment on the PR
- Save locally only — choosing this option overrides
saveLocallyconfig and writes the review file locally even if automatic saving was disabled in Step 12 - Let me edit the review first, then I'll tell you when to post
Step 14: Post to GitHub
If the user chose to post:
Use SHA-based permalinks for every file reference so the links stay valid even after the branch moves. First capture the PR head commit SHA:
# Full head SHA of the PR (do NOT inline $(git rev-parse HEAD) into the Markdown — the link must be literal)
HEAD_SHA=$(gh pr view {PR_NUMBER} {REPO_FLAG} --json headRefOid --jq '.headRefOid')
Render each finding's location as a literal permalink:
https://github.com/{owner}/{repo}/blob/{HEAD_SHA}/{file_path}#L{start}-L{end}
Build the URL with the resolved SHA already substituted (a literal 40-char hash in the Markdown) — never leave a $(...) command substitution or a branch name in the posted text.
Choose REVIEW_EVENT before posting. Compare the PR author from Step 2 with gh api user --jq .login. Set {HAS_BLOCKING} from Step 9 and add
{SELF_AUTHORED_FLAG}=--self-authored only when the logins match. Resolve {SKILL_DIR} to the absolute, physical directory containing this loaded SKILL.md; the tested resolver loads
review.postEvent using the canonical/legacy precedence (default auto) and enforces the self-review restriction:
REVIEW_EVENT="$(bash "{SKILL_DIR}/scripts/review-event.sh" --has-blocking {HAS_BLOCKING} {SELF_AUTHORED_FLAG})"
If unavailable, use PLUGIN_ROOT, then CLAUDE_PLUGIN_ROOT, only to locate skills/review/SKILL.md; verify each helper exists and never fall back to /scripts. Run this only after review.postToGitHub gates posting in Step 13; stop on invalid configuration.
# Post review as a PR review comment
gh api "repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews" \
--method POST \
-f body="$(cat <<'REVIEW_EOF'
{REVIEW_CONTENT}
REVIEW_EOF
)" \
-f event="$REVIEW_EVENT"
Handle body size limit:
GitHub has a ~65,000 character limit for review bodies. If the review exceeds this:
- Truncate the review at the Summary section
- If the review was saved locally, add a note: "Full review available locally at
{file_path}". Otherwise, add: "Review was truncated due to GitHub size limits." - Post the truncated version
Error Handling:
| Scenario | Action |
|---|---|
| Not authorized | Inform user, suggest gh auth login with required scopes |
| API rate limit | Inform user, suggest waiting or posting manually |
| Network error | Save locally, inform user the post failed |
Step 15: Confirm
Output final summary:
Review complete for PR #{number}: {title}
Findings:
BLOCKING: {n}
HIGH: {n}
MEDIUM: {n}
LOW: {n}
{If saved locally:}
Review saved: {file_path}
{If posted to GitHub:}
Review posted: {pr_url}
{If BLOCKING or HIGH issues found:}
⚠ This PR has issues that should be addressed before merging.
{If no BLOCKING or HIGH issues:}
✓ No critical issues found. PR looks good for merge.
Configuration Reference
| Setting | Default | Description |
|---|---|---|
review.saveLocally | true | Save review document to local file |
review.reviewsDir | docs | Directory for review documents |
review.postToGitHub | ask | Post to PR: ask, always, or never |
review.maxDiffLines | 3000 | Max diff lines before file-by-file reading |
review.postEvent | auto | auto derives REQUEST_CHANGES/APPROVE from findings; comment always posts COMMENT |
SARIF Export (--sarif)
If --sarif was passed as an argument, also export the findings from Step 9 as a SARIF 2.1.0 log for CI / code-scanning ingestion. Serialize the findings to the JSON array shape [{ file, line, severity, confidence, message, rule }] and pipe it through the converter script:
echo '{FINDINGS_JSON}' | node "{SKILL_DIR}/scripts/to-sarif.mjs" > review.sarif
Tell the user the SARIF file was written to review.sarif (e.g. for github/codeql-action/upload-sarif).
Error Handling
| Scenario | Action |
|---|---|
gh not installed | Provide installation instructions |
| Not authenticated | Run gh auth login instructions |
| PR not found | Show error, ask user to verify |
| PR is merged/closed | Inform user, ask if they still want to review |
| Diff too large | Switch to file-by-file reading |
| Review too long for GitHub | Truncate and note full review location |
| No files changed | Inform user the PR has no file changes |
| Network error on post | Save locally, report error |
Examples
Standard Review
User: /review 123
Agent: [Fetches PR #123 metadata]
Agent: Any focus areas? -> "skip"
Agent: [Reads 8 changed files, analyzes across all dimensions]
Agent: [Generates review with 0 BLOCKING, 2 HIGH, 3 MEDIUM, 1 LOW]
Agent: How to proceed? -> "Post to PR"
Result: Review posted to PR #123
Review saved: docs/code-review-add-auth-flow.md
Review with Context
User: /review https://github.com/org/repo/pull/456
Agent: [Fetches PR #456]
Agent: Focus areas? -> "This changes the billing flow, watch for data integrity"
Agent: [Deep analysis with focus on transactions and idempotency]
Agent: [Finds 1 BLOCKING issue: missing transaction wrapper]
Result: Review posted with REQUEST CHANGES verdict
Large PR Review
User: /review 789
Agent: [Fetches PR #789 — 45 files changed, 4200 line diff]
Agent: [Switches to file-by-file reading, prioritizes business logic]
Agent: [Reviews top 30 files in priority order, summarizes remainder]
Result: Review saved locally (too large to post as single comment)
Signals
- GitHub stars
- 30
- Forks
- 2
- Last commit
- Aug 2026
- Hacker News mentions
- 20
Advanced
- Catalog kind
- skill
- Gateway key
review-rlajous- Source
- github.com/rlajous/claude-code-commands