Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when the user asks to review pull requests, analyze code changes, check for security issues in PRs, or assess code quality of diffs.
.claude/skills/alirezarezvani-pr-review-expert/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 172% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 195% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 53% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 52% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 744% | 0% |
Tier: POWERFUL Category: Engineering Domain: Code Review / Quality Assurance
Structured, systematic code review for GitHub PRs and GitLab MRs. Goes beyond style nits — this skill performs blast radius analysis, security scanning, breaking change detection, and test coverage delta calculation. Produces a reviewer-ready report with a 30+ item checklist and prioritized findings.
bash# View diff in terminal gh pr diff <PR_NUMBER> # Get PR metadata (title, body, labels, linked issues) gh pr view <PR_NUMBER> --json title,body,labels,assignees,milestone # List files changed gh pr diff <PR_NUMBER> --name-only # Check CI status gh pr checks <PR_NUMBER> # Download diff to file for analysis gh pr diff <PR_NUMBER> > /tmp/pr-<PR_NUMBER>.diff
bash# View MR diff glab mr diff <MR_IID> # MR details as JSON glab mr view <MR_IID> --output json # List changed files glab mr diff <MR_IID> --name-only # Download diff glab mr diff <MR_IID> > /tmp/mr-<MR_IID>.diff
bashPR=123 gh pr view $PR --json title,body,labels,milestone,assignees | jq . gh pr diff $PR --name-only gh pr diff $PR > /tmp/pr-$PR.diff
For each changed file, identify:
bash# Find all files importing a changed module grep -r "from ['\"].*changed-module['\"]" src/ --include="*.ts" -l grep -r "require(['\"].*changed-module" src/ --include="*.js" -l # Python grep -r "from changed_module import\|import changed_module" . --include="*.py" -l
bash# Check if changed files span multiple services (monorepo) gh pr diff $PR --name-only | cut -d/ -f1-2 | sort -u
bashgh pr diff $PR --name-only | grep -E "types/|interfaces/|schemas/|models/"
Blast radius severity:
bashDIFF=/tmp/pr-$PR.diff # SQL Injection — raw query string interpolation grep -n "query\|execute\|raw(" $DIFF | grep -E '\$\{|f"|%s|format\(' # Hardcoded secrets grep -nE "(password|secret|api_key|token|private_key)\s*=\s*['\"][^'\"]{8,}" $DIFF # AWS key pattern grep -nE "AKIA[0-9A-Z]{16}" $DIFF # JWT secret in code grep -nE "jwt\.sign\(.*['\"][^'\"]{20,}['\"]" $DIFF # XSS vectors grep -n "dangerouslySetInnerHTML\|innerHTML\s*=" $DIFF # Auth bypass patterns grep -n "bypass\|skip.*auth\|noauth\|TODO.*auth" $DIFF # Insecure hash algorithms grep -nE "md5\(|sha1\(|createHash\(['\"]md5|createHash\(['\"]sha1" $DIFF # eval / exec grep -nE "\beval\(|\bexec\(|\bsubprocess\.call\(" $DIFF # Prototype pollution grep -n "__proto__\|constructor\[" $DIFF # Path traversal risk grep -nE "path\.join\(.*req\.|readFile\(.*req\." $DIFF
bash# Count source vs test files changed CHANGED_SRC=$(gh pr diff $PR --name-only | grep -vE "\.test\.|\.spec\.|__tests__") CHANGED_TESTS=$(gh pr diff $PR --name-only | grep -E "\.test\.|\.spec\.|__tests__") echo "Source files changed: $(echo "$CHANGED_SRC" | wc -w)" echo "Test files changed: $(echo "$CHANGED_TESTS" | wc -w)" # Lines of new logic vs new test lines LOGIC_LINES=$(grep "^+" /tmp/pr-$PR.diff | grep -v "^+++" | wc -l) echo "New lines added: $LOGIC_LINES" # Run coverage locally npm test -- --coverage --changedSince=main 2>/dev/null | tail -20 pytest --cov --cov-report=term-missing 2>/dev/null | tail -20
Coverage delta rules:
bash# OpenAPI/Swagger spec changes grep -n "openapi\|swagger" /tmp/pr-$PR.diff | head -20 # REST route removals or renames grep "^-" /tmp/pr-$PR.diff | grep -E "router\.(get|post|put|delete|patch)\(" # GraphQL schema removals grep "^-" /tmp/pr-$PR.diff | grep -E "^-\s*(type |field |Query |Mutation )" # TypeScript interface removals grep "^-" /tmp/pr-$PR.diff | grep -E "^-\s*(export\s+)?(interface|type) "
bash# Migration files added gh pr diff $PR --name-only | grep -E "migrations?/|alembic/|knex/" # Destructive operations grep -E "DROP TABLE|DROP COLUMN|ALTER.*NOT NULL|TRUNCATE" /tmp/pr-$PR.diff # Index removals (perf regression risk) grep "DROP INDEX\|remove_index" /tmp/pr-$PR.diff
bash# New env vars referenced in code (might be missing in prod) grep "^+" /tmp/pr-$PR.diff | grep -oE "process\.env\.[A-Z_]+" | sort -u # Removed env vars (could break running instances) grep "^-" /tmp/pr-$PR.diff | grep -oE "process\.env\.[A-Z_]+" | sort -u
bash# N+1 query patterns (DB calls inside loops) grep -n "\.find\|\.findOne\|\.query\|db\." /tmp/pr-$PR.diff | grep "^+" | head -20 # Then check surrounding context for forEach/map/for loops # Heavy new dependencies grep "^+" /tmp/pr-$PR.diff | grep -E '"[a-z@].*":\s*"[0-9^~]' | head -20 # Unbounded loops grep -n "while (true\|while(true" /tmp/pr-$PR.diff | grep "^+" # Missing await (accidentally sequential promises) grep -n "await.*await" /tmp/pr-$PR.diff | grep "^+" | head -10 # Large in-memory allocations grep -n "new Array([0-9]\{4,\}\|Buffer\.alloc" /tmp/pr-$PR.diff | grep "^+"
bash# Extract ticket references from PR body gh pr view $PR --json body | jq -r '.body' | \ grep -oE "(PROJ-[0-9]+|[A-Z]+-[0-9]+|https://linear\.app/[^)\"]+)" | sort -u # Verify Jira ticket exists (requires JIRA_API_TOKEN to be SET in the environment). # Credentials are fed to curl via a config read from stdin (-K -) so the token # never appears in argv — `ps aux` / /proc/*/cmdline can't see it, and nothing # secret lands in shell history. Never paste the raw token on the command line. TICKET="PROJ-123" : "${JIRA_API_TOKEN:?JIRA_API_TOKEN must be set}" curl -s -K - "https://your-org.atlassian.net/rest/api/3/issue/$TICKET" <<EOF | \ jq '{key, summary: .fields.summary, status: .fields.status.name}' user = "user@company.com:$JIRA_API_TOKEN" EOF # Linear ticket — same pattern: the Authorization header goes through the # stdin config, not a -H flag, to keep the key out of the process list. LINEAR_ID="abc-123" : "${LINEAR_API_KEY:?LINEAR_API_KEY must be set}" curl -s -K - -H "Content-Type: application/json" \ --data "{\"query\": \"{ issue(id: \\\"$LINEAR_ID\\\") { title state { name } } }\"}" \ https://api.linear.app/graphql <<EOF | jq . header = "Authorization: $LINEAR_API_KEY" EOF
> Security note: for repeated Jira use, prefer a ~/.netrc entry > (machine your-org.atlassian.net login user@company.com password <token>, > chmod 600 ~/.netrc) and call curl -s --netrc … — no secret material in > the command at all.
markdown## Code Review Checklist ### Scope & Context - [ ] PR title accurately describes the change - [ ] PR description explains WHY, not just WHAT - [ ] Linked Jira/Linear ticket exists and matches scope - [ ] No unrelated changes (scope creep) - [ ] Breaking changes documented in PR body ### Blast Radius - [ ] Identified all files importing changed modules - [ ] Cross-service dependencies checked - [ ] Shared types/interfaces/schemas reviewed for breakage - [ ] New env vars documented in .env.example - [ ] DB migrations are reversible (have down() / rollback) ### Security - [ ] No hardcoded secrets or API keys - [ ] SQL queries use parameterized inputs (no string interpolation) - [ ] User inputs validated/sanitized before use - [ ] Auth/authorization checks on all new endpoints - [ ] No XSS vectors (innerHTML, dangerouslySetInnerHTML) - [ ] New dependencies checked for known CVEs - [ ] No sensitive data in logs (PII, tokens, passwords) - [ ] File uploads validated (type, size, content-type) - [ ] CORS configured correctly for new endpoints ### Testing - [ ] New public functions have unit tests - [ ] Edge cases covered (empty, null, max values) - [ ] Error paths tested (not just happy path) - [ ] Integration tests for API endpoint changes - [ ] No tests deleted without clear reason - [ ] Test names clearly describe what they verify ### Breaking Changes - [ ] No API endpoints removed without deprecation notice - [ ] No required fields added to existing API responses - [ ] No DB columns removed without two-phase migration plan - [ ] No env vars removed that may be set in production - [ ] Backward-compatible for external API consumers ### Performance - [ ] No N+1 query patterns introduced - [ ] DB indexes added for new query patterns - [ ] No unbounded loops on potentially large datasets - [ ] No heavy new dependencies without justification - [ ] Async operations correctly awaited - [ ] Caching considered for expensive repeated operations ### Code Quality - [ ] No dead code or unused imports - [ ] Error handling present (no bare empty catch blocks) - [ ] Consistent with existing patterns and conventions - [ ] Complex logic has explanatory comments - [ ] No unresolved TODOs (or tracked in ticket)
Structure your review comment as:
## PR Review: [PR Title] (#NUMBER)
Blast Radius: HIGH — changes lib/auth used by 5 services
Security: 1 finding (medium severity)
Tests: Coverage delta +2%
Breaking Changes: None detected
--- MUST FIX (Blocking) ---
1. SQL Injection risk in src/db/users.ts:42
Raw string interpolation in WHERE clause.
Fix: db.query("SELECT * WHERE id = $1", [userId])
--- SHOULD FIX (Non-blocking) ---
2. Missing auth check on POST /api/admin/reset
No role verification before destructive operation.
--- SUGGESTIONS ---
3. N+1 pattern in src/services/reports.ts:88
findUser() called inside results.map() — batch with findManyUsers(ids)
--- LOOKS GOOD ---
- Test coverage for new auth flow is thorough
- DB migration has proper down() rollback method
- Error handling consistent with rest of codebase| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 14,058 | 18,485 | +31% | 1 | 1 | 0% | 2,599 | 5,840 | +125% | 0 | 0 | — |
case-02 | fail→fail | 15,652 | 19,935 | +27% | 1 | 1 | 0% | 2,054 | 5,616 | +173% | 0 | 0 | — |
case-03 | fail→fail | 19,247 | 14,196 | -26% | 1 | 1 | 0% | 1,598 | 5,449 | +241% | 0 | 0 | — |
case-04 | fail→pass | 9,131 | 6,730 | -26% | 1 | 1 | 0% | 1,822 | 4,960 | +172% | 0 | 0 | — |
case-05 | pass→pass | 14,403 | 4,234 | -71% | 1 | 1 | 0% | 2,865 | 4,373 | +53% | 0 | 0 | — |
case-06 | pass→pass | 13,790 | 4,054 | -71% | 1 | 1 | 0% | 2,797 | 4,244 | +52% | 0 | 0 | — |
case-07 | pass→pass | 2,697 | 2,353 | -13% | 1 | 1 | 0% | 467 | 3,942 | +744% | 0 | 0 | — |
case-08 | pass→pass | 1,946 | 1,685 | -13% | 1 | 1 | 0% | 349 | 3,840 | +1000% | 0 | 0 | — |
case-09 | pass→pass | 3,025 | 3,114 | +3% | 1 | 1 | 0% | 384 | 3,972 | +934% | 0 | 0 | — |
case-10 | pass→pass | 14,166 | 15,567 | +10% | 1 | 1 | 0% | 2,572 | 6,204 | +141% | 0 | 0 | — |
case-11 | pass→pass | 10,958 | 9,749 | -11% | 1 | 1 | 0% | 1,842 | 5,108 | +177% | 0 | 0 | — |
case-12 | pass→pass | 15,967 | 14,079 | -12% | 1 | 1 | 0% | 2,785 | 6,078 | +118% | 0 | 0 | — |
case-13 | pass→pass | 9,768 | 11,169 | +14% | 1 | 1 | 0% | 1,780 | 5,549 | +212% | 0 | 0 | — |
case-14 | pass→pass | 7,792 | 6,708 | -14% | 1 | 1 | 0% | 1,390 | 4,602 | +231% | 0 | 0 | — |
case-15 | pass→pass | 14,590 | 8,745 | -40% | 1 | 1 | 0% | 2,541 | 5,043 | +98% | 0 | 0 | — |
case-16 | pass→pass | 13,534 | 10,771 | -20% | 1 | 1 | 0% | 2,552 | 5,612 | +120% | 0 | 0 | — |
case-17 | pass→pass | 7,985 | 4,232 | -47% | 1 | 1 | 0% | 1,319 | 4,269 | +224% | 0 | 0 | — |
case-18 | fail→pass | 8,395 | 3,485 | -58% | 1 | 1 | 0% | 1,383 | 4,077 | +195% | 0 | 0 | — |
case-19 | pass→pass | 15,010 | 8,946 | -40% | 1 | 1 | 0% | 2,654 | 5,165 | +95% | 0 | 0 | — |
case-20 | pass→pass | 13,041 | 14,526 | +11% | 1 | 1 | 0% | 2,844 | 6,913 | +143% | 0 | 0 | — |
case-21 | pass→pass | 4,226 | 3,836 | -9% | 1 | 1 | 0% | 906 | 4,280 | +372% | 0 | 0 | — |
case-22 | pass→pass | 10,680 | 10,864 | +2% | 1 | 1 | 0% | 2,240 | 5,725 | +156% | 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. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
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.