Multi-reviewer code review. Spawns domain-specific reviewers in parallel, cross-checks findings, posts a single structured GitHub review.
Multi-reviewer code review. Spawns domain-specific reviewers in parallel, cross-checks their findings for contradictions and convergence, then posts a single structured GitHub review with inline comments.
Use .claude/skills/code-review/ for focused single-domain changes or quick single-pass reviews.
Prerequisite: This skill requires the ability to spawn parallel subagents. If your agent runtime cannot spawn subagents, use code-review instead.
Severity scales: Deep-review uses P0–P4 (consequence-based). Code-review uses 🔴🟡🔵. Both are valid; they serve different review depths. Approximate mapping: P0–P1 ≈ 🔴, P2 ≈ 🟡, P3–P4 ≈ 🔵.
.claude/skills/doc-check/ instead.Estimate scope before committing to a deep review. If the PR has fewer than 3 files and fewer than 100 lines changed, suggest code-review instead. If the PR is docs-only, suggest doc-check. Proceed only if the change warrants multi-reviewer analysis.
Author independence. Review with the same rigor regardless of who authored the PR. Don't soften findings because the author is the person who invoked this review, a maintainer, or a senior contributor. Don't harden findings because the author is a new contributor. The review's value comes from honest, consistent assessment.
Create the review output directory before anything else:
export REVIEW_DIR="/tmp/deep-review/$(date +%s)"
mkdir -p "$REVIEW_DIR"
Re-review detection. Check if you or a previous agent session already reviewed this PR:
gh pr view {number} --json reviews --jq '.reviews[] | select(.body | test("P[0-4]|\\*\\*Obs\\*\\*|\\*\\*Nit\\*\\*")) | .submittedAt' | head -1
If a prior agent review exists, you must produce a prior-findings classification table before proceeding. This is not optional — the table is an input to step 3 (reviewer prompts). Without it, reviewers will re-discover resolved findings.
$REVIEW_DIR/prior-findings.md with this format:# Prior findings from round {N}
| Finding | Author response | Status |
|---------|----------------|--------|
| P1 `file.go:42` wire-format break | Acknowledged, pushed fix in abc123 | Resolved |
| P2 `handler.go:15` missing auth check | "Middleware handles this" — see comment | Contested |
| P3 `db.go:88` naming | Agreed, will fix | Acknowledged |
Classify each finding as:
Only Contested and No response findings carry forward to the new review. Resolved and Acknowledged findings must not be re-raised.
Scope the diff. Get the file list from the diff, PR, or user. Skim for intent and note which layers are touched (frontend, backend, database, auth, concurrency, tests, docs).
For each changed file, briefly check the surrounding context:
Match reviewer roles to layers touched. The Test Auditor, Edge Case Analyst, and Contract Auditor always run. Conditional reviewers activate when their domain is touched.
| Role | Focus | When |
|---|---|---|
| Test Auditor | Test authenticity, missing cases, readability | Always |
| Edge Case Analyst | Chaos testing, edge cases, hidden connections | Always |
| Contract Auditor | Contract fidelity, lifecycle completeness, semantic honesty | Always |
| Structural Analyst | Implicit assumptions, class-of-bug elimination | API design, type design, test structure, resource lifecycle |
| Performance Analyst | Hot paths, resource exhaustion, allocation patterns | Hot paths, loops, caches, resource lifecycle |
| Database Reviewer | PostgreSQL, data modeling, Go↔SQL boundary | Migrations, queries, schema, indexes |
| Security Reviewer | Auth, attack surfaces, input handling | Auth, new endpoints, input handling, tokens, secrets |
| Product Reviewer | Over-engineering, feature justification | New features, new config surfaces |
| Frontend Reviewer | UI state, render lifecycles, component design | Frontend changes, UI components, API response shape changes |
| Duplication Checker | Existing utilities, code reuse | New files, new helpers/utilities, new types or components |
| Go Architect | Package boundaries, API lifecycle, middleware | Go code, API design, middleware, package boundaries |
| Concurrency Reviewer | Goroutines, channels, locks, shutdown | Goroutines, channels, locks, context cancellation, shutdown |
| Role | Focus | File filter |
|---|---|---|
| Modernization Reviewer | Language-level improvements, stdlib patterns | Per-language (see below) |
| Style Reviewer | Naming, comments, consistency | *.go *.ts *.tsx *.py *.sh |
Tier 2 file filters:
Modernization Reviewer: one instance per language present in the diff. Filter by extension:
*.go — reference .claude/docs/GO.md before reviewing.*.ts *.tsx: reference .agents/skills/deep-review/references/typescript.md before reviewing.*.tsx *.jsx: reference .agents/skills/deep-review/references/react.md before reviewing..tsx files match both TypeScript and React filters. Spawn both instances when the diff contains .tsx changes — TS covers language-level patterns; React covers component and hooks patterns. Before spawning, verify each instance's filter produces a non-empty diff. Skip instances whose filtered diff is empty.
Style Reviewer: *.go *.ts *.tsx *.py *.sh
Each reviewer writes findings to $REVIEW_DIR/{role-name}.md where {role-name} is the kebab-cased role name (e.g. test-auditor, go-architect). For Modernization Reviewer instances, qualify with the language: modernization-reviewer-go.md, modernization-reviewer-ts.md, modernization-reviewer-react.md. The orchestrator does not read reviewer findings from the subagent return text — it reads the files in step 4.
Spawn all Tier 1 and Tier 2 reviewers in parallel. Give each reviewer a reference (PR number, branch name), not the diff content. The reviewer fetches the diff itself. Reviewers are read-only — no worktrees needed.
Tier 1 prompt:
Read `AGENTS.md` in this repository before starting.
You are the {Role Name} reviewer. Read your methodology in
`.agents/skills/deep-review/roles/{role-name}.md`.
Follow the review instructions in
`.agents/skills/deep-review/structural-reviewer-prompt.md`.
Review: {PR number / branch / commit range}.
Output file: {REVIEW_DIR}/{role-name}.md
Tier 2 prompt:
Read `AGENTS.md` in this repository before starting.
You are the {Role Name} reviewer. Read your methodology in
`.agents/skills/deep-review/roles/{role-name}.md`.
Follow the review instructions in
`.agents/skills/deep-review/nit-reviewer-prompt.md`.
Review: {PR number / branch / commit range}.
File scope: {filter from step 2}.
Output file: {REVIEW_DIR}/{role-name}.md
For Modernization Reviewer instances, add the language reference after the methodology line:
Read .claude/docs/GO.md as your Go language reference before reviewing.Read .agents/skills/deep-review/references/typescript.md as your TypeScript language reference before reviewing.Read .agents/skills/deep-review/references/react.md as your React language reference before reviewing.For re-reviews, append to both Tier 1 and Tier 2 prompts:
Prior findings and author responses are in {REVIEW_DIR}/prior-findings.md. Read it before reviewing. Do not re-raise Resolved or Acknowledged findings.
Read each reviewer's output file from $REVIEW_DIR/ one at a time. One file per read — do not batch multiple reviewer files in parallel. Batching causes reviewer voices to blend in the context window, leading to misattribution (grabbing phrasing from one reviewer and attributing it to another).
For each file:
If a file says "No findings," record that and move on. If a file is missing (reviewer crashed or timed out), note the gap and proceed — do not stall or silently drop the reviewer's perspective.
After reading all files, you have a finding inventory. Proceed to cross-check.
Handle Tier 1 and Tier 2 findings separately before merging.
Tier 2 nit findings: Apply a lighter filter. Drop nits that are purely subjective, that duplicate what a linter already enforces, or that the author clearly made intentionally. Keep nits that have a practical benefit (clearer name, better error message, obsolete stdlib usage). Surviving nits stay as Nit.
Tier 1 structural findings: Before producing the final review, look across all findings for:
For each finding and observation, apply the severity test in both directions. Observations are not exempt — a reviewer may underrate a convention violation or a missing guarantee as Obs when the consequence warrants P3+:
When the severity spread among reviewers exceeds one level, note it explicitly. Only credit reviewers at or above the posted severity. A finding that survived 2+ independent reviewers needs an explicit counter-argument to drop. "Low risk" is not a counter when the reviewers already addressed it in their evidence.
Before forwarding a nit, form an independent opinion on whether it improves the code. Before rejecting a nit, verify you can prove it wrong, not just argue it's debatable.
Drop findings that don't survive this check. Adjust severity where the cross-check changes the picture.
After filtering both tiers, check for overlap: a nit that points at the same line as a Tier 1 finding can be folded into that comment rather than posted separately.
When a finding survives cross-check, the reviewer's technical evidence is the source of record. Do not paraphrase it.
Convergent findings — sharpest first. When multiple reviewers flag the same issue:
Single-reviewer findings. Go back to the reviewer's file and copy the evidence verbatim. The orchestrator owns framing, severity assessment, and practical judgment — those are your words. The technical claim and code-level evidence are the reviewer's words.
A posted finding has two voices:
If you need to adjust a finding's scope (e.g. the reviewer said "file.go:42" but the real issue is broader), say so explicitly rather than silently rewriting the evidence.
Attribution must show severity spread. When reviewers disagree on severity, the attribution should reflect that — not flatten everyone to the posted severity. Show each reviewer's individual severity: *(Security Reviewer P1, Concurrency Reviewer P1, Test Auditor P2)* not *(Security Reviewer, Concurrency Reviewer, Test Auditor)*.
Integrity check. Before posting, verify that quoted evidence in findings actually corresponds to content in the diff. This guards against garbled cross-references from the file-reading step.
When reviewing a GitHub PR, post findings as a proper GitHub review with inline comments, not a single comment dump.
Review body. Open with a short, friendly summary: what the change does well, what the overall impression is, and how many findings follow. Call out good work when you see it. A review that only lists problems teaches authors to dread your comments.
Clean approach to X. The Y handling is particularly well done.
A couple things to look at: 1 P2, 1 P3, 3 nits across 5 inline
comments.
For re-reviews (round 2+), open with what was addressed:
Thanks for fixing the wire-format break and the naming issue.
Fresh review found one new issue: 1 P2 across 1 inline comment.
Keep the review body to 2–4 sentences. Don't use markdown headers in the body — they render oversized in GitHub's review UI.
Inline comments. Every finding is an inline comment, pinned to the most relevant file and line. For findings that span multiple files, pin to the primary file (GitHub supports file-level comments when position is omitted or set to 1).
Inline comment format:
**P{n}** One-sentence finding *(Reviewer Role)*
> Reviewer's evidence quoted verbatim from their file
Orchestrator's practical judgment: is this worth fixing now, or
is the current tradeoff acceptable? Scenario building, severity
reasoning, fix suggestions — these are your words.
For convergent findings (multiple reviewers, same issue):
**P{n}** One-sentence finding *(Performance Analyst P1,
Contract Auditor P1, Test Auditor P2)*
> Sharpest reviewer's evidence as base text
> *Contract Auditor adds:* Additional detail from their file
Orchestrator's practical judgment.
For observations: **Obs** One-sentence observation *(Role)* ... For nits: **Nit** One-sentence finding *(Role)* ...
P3 findings and observations can be one-liners. Group multiple nits on the same file into one comment when they're co-located.
Review event. Always use COMMENT. Never use REQUEST_CHANGES — this isn't the norm in this repository. Never use APPROVE — approval is a human responsibility.
For P0 or P1 findings, add a note in the review body: "This review contains findings that may need attention before merge."
Posting via GitHub API.
The gh api endpoint for posting reviews routes through GraphQL by default. Field names differ from the REST API docs:
position (diff-relative line number), not line + side. side is not a valid field in the GraphQL schema.subject_type: "file" is not recognized. Pin file-level comments to position: 1 instead.-X POST with --input to force REST API routing.To compute positions: save the PR diff to a file, then count lines from the first @@ hunk header of each file's diff section. For new files, position = line number + 1 (the hunk header is position 1, first content line is position 2).
gh pr diff {number} > /tmp/pr.diff
Submit:
gh api -X POST \
repos/{owner}/{repo}/pulls/{number}/reviews \
--input review.json
Where review.json:
{
"event": "COMMENT",
"body": "Summary of what's good and what to look at.\n1 P2, 1 P3 across 2 inline comments.",
"comments": [
{
"path": "file.go",
"position": 42,
"body": "**P1** Finding... *(Reviewer Role)*\n\n> Evidence..."
},
{
"path": "other.go",
"position": 1,
"body": "**P2** Cross-file finding... *(Reviewer Role)*\n\n> Evidence..."
}
]
}
Tone guidance. Frame design concerns as questions: "Could we use X instead?" — be direct only for correctness issues. Hedge design, not bugs. Build concrete scenarios to make concerns tangible. When uncertain, say so. See .claude/docs/PR_STYLE_GUIDE.md for PR conventions.
After posting the review, monitor the PR for author responses. If the author pushes fixes or responds to findings, consider running a re-review (this skill, starting from step 1 with the re-review detection path). Allow time for the author to address multiple findings before re-reviewing — don't trigger on each individual response.