PR Review
Review a GitHub PR's diff and submit a single GitHub review with inline comments identifying bugs, performance issues, security concerns, and improvements.
Arguments
$ARGUMENTS (optional): The PR number to review. If not provided, detect the PR associated with the current branch.
Step 1: Identify the PR
- Get the repository:
gh repo view --json nameWithOwner -q '.nameWithOwner'
- If a PR number was provided in
$ARGUMENTS, use it directly.
- If no PR number was provided, detect the PR for the current branch:
gh pr list --head "$(git branch --show-current)" --json number,title,url --limit 1
- If no PR is found, inform the user and stop.
- Fetch PR metadata:
gh pr view <NUMBER> --json number,title,url,headRefName,baseRefName,author,body
- Show the PR title and URL for confirmation before proceeding.
Step 2: Fetch the Diff and Changed Files
- Get the full diff:
gh pr diff <NUMBER>
- Get the list of changed files with line counts:
gh pr view <NUMBER> --json files --jq '.files[] | "\(.path) +\(.additions) -\(.deletions)"'
Step 2.5: Load the Repository's Conventions
Read the repo's own rules before judging the code. They decide what counts as a defect here — reviewing against generic taste produces comments the team will reject.
ls CLAUDE.md AGENTS.md CONTRIBUTING.md README.md 2>/dev/null
ls .github/PULL_REQUEST_TEMPLATE.md .github/pull_request_template.md 2>/dev/null
# conventions local to the directories this PR touches
gh pr view <NUMBER> --json files -q '.files[].path' | xargs -r -n1 dirname | sort -u \
| while read -r d; do ls "$d"/CLAUDE.md "$d"/AGENTS.md "$d"/README.md 2>/dev/null; done
Read what exists (skip any CLAUDE.md already in your context) and extract the rules that make findings concrete:
- Required and forbidden patterns, architecture and layering rules, module boundaries
- Error-handling, logging and observability conventions
- Naming, file layout, and where tests belong; test requirements for new code
- Dependency policy, security rules, generated files that must not be hand-edited
- Build/lint/test commands the author was expected to run
How this changes the review:
- A violation of a documented repo rule is a finding, even when the code would be fine elsewhere. Cite the source —
CLAUDE.md:42 requires … — so the comment is actionable rather than a matter of opinion.
- A pattern the repo explicitly endorses is not a finding, however much it differs from your own preference. Drop those comments.
- If a documented rule and the diff conflict and the rule looks stale, raise it as ❓ a question about the rule, not as 🔴 critical.
- Check the PR body against the repo's template — a missing required section or an unticked mandatory checklist item is worth one comment, not one per item.
Step 3: Analyze Each Changed File
For each changed file in the diff:
- Read the full file for context (not just the diff) using the Read tool.
- Understand the purpose of the changes from the diff hunks and surrounding code.
- Review for issues across these categories:
| Tag |
What to look for |
| 🔴 Critical |
Bugs, logic errors, incorrect behavior, data loss risks |
| 🔒 Security |
Injection, auth bypass, secrets exposure, unsafe deserialization |
| ⚡ Performance |
N+1 queries, unnecessary re-renders, memory leaks, O(n²) when O(n) is possible |
| 🐛 Bug |
Null pointer risks, off-by-one errors, race conditions, unhandled errors |
| ✨ Improvement |
Clearer naming, better patterns, simpler logic, unnecessary complexity |
| 🧪 Testing |
Missing test cases, untested edge cases, weak assertions |
| 📝 Documentation |
Missing/incorrect JSDoc, misleading comments, unclear intent |
- Trace dependencies — use Grep/Glob to check callers, interfaces, and types affected by the change when relevant.
- Check the PR description — verify the code matches what the author says they changed.
Review guidelines
- Focus on substantive issues — skip formatting nitpicks, trivial style preferences, and obvious code.
- Judge against the repo's conventions from Step 2.5, not your own preferences. Quote the rule you're invoking.
- Every comment must be actionable — say what to change, not just what's wrong.
- Include a concrete code suggestion when possible.
- Be respectful and constructive. Assume the author is competent.
- Don't comment on unchanged code unless a change introduces an issue with it.
- For large PRs (20+ files), prioritize critical and security issues. Mention that a full review is recommended.
Step 4: Present Findings
Display ALL findings sorted by severity (critical first), then by file order in the diff.
For each finding:
### #N — [TAG] file/path.ts:L<line>
**Issue**: [Clear, concise description of the problem]
**Suggestion**: [Concrete fix or code change]
After presenting all findings:
- Show a summary count:
Found X issues: N critical, N security, N bugs, N improvements...
- If no issues found, say so clearly.
Then ask:
Ready to submit this review? Enter "yes" to post all comments, "remove N,N" to drop specific items, or "edit N" to modify a comment before posting.
Step 5: Submit the Review
Submit a single review using the GitHub API with event COMMENT:
gh api repos/{owner}/{repo}/pulls/{number}/reviews --method POST --input /tmp/pr-review-payload.json
Build the JSON payload with all comments. Each comment needs:
path: file path relative to repo root
line: the line number in the diff (use the new file line number for added/modified lines)
side: "RIGHT" for comments on the new version of the code
body: the review comment text with tag, issue description, and suggestion. Always append \n\n---\n_[Generated by AI]_ at the end of every comment body
Building the review payload
Construct a temporary JSON file with the review data:
{
"event": "COMMENT",
"body": "Review summary — found N issues across M files.",
"comments": [
{
"path": "src/auth.ts",
"line": 45,
"side": "RIGHT",
"body": "🔴 **Critical**: Missing null check on `user` before accessing `.id`. This will throw if the query returns no results.\n\n**Suggestion**:\n```ts\nif (!user) {\n throw new NotFoundError('User not found');\n}\n```\n\n---\n_[Generated by AI]_"
}
]
}
Submit with:
gh api repos/{owner}/{repo}/pulls/{number}/reviews --method POST --input /tmp/pr-review-payload.json
Clean up the temp file after submission.
Line number mapping
- For comments on added or modified lines: use the line number from the new file (
+ side of the diff), set side: "RIGHT".
- For comments on deleted lines: use the line number from the old file (
- side of the diff), set side: "LEFT".
- To find the correct line number, parse the diff hunk headers (
@@ -old_start,old_count +new_start,new_count @@) and count lines from there.
Step 6: Confirmation
After successful submission:
## Review Submitted
PR #<number> — <title>
URL: <review URL>
Posted <N> inline comments across <M> files.
If submission fails, show the error and suggest the user check their gh auth permissions.
1---2name: pr-review3description: Review a GitHub Pull Request and submit a single review with inline code comments. Identifies bugs, security vulnerabilities, performance issues, logic errors, missing edge cases, and suggests improvements. Use when the user wants to review a PR, do a code review, or add review comments to a pull request.4---56# PR Review78Review a GitHub PR's diff and submit a single GitHub review with inline comments identifying bugs, performance issues, security concerns, and improvements.910## Arguments1112- `$ARGUMENTS` (optional): The PR number to review. If not provided, detect the PR associated with the current branch.1314## Step 1: Identify the PR15161. Get the repository:17 ```bash18 gh repo view --json nameWithOwner -q '.nameWithOwner'19 ```202. If a PR number was provided in `$ARGUMENTS`, use it directly.213. If no PR number was provided, detect the PR for the current branch:22 ```bash23 gh pr list --head "$(git branch --show-current)" --json number,title,url --limit 124 ```254. If no PR is found, inform the user and stop.265. Fetch PR metadata:27 ```bash28 gh pr view <NUMBER> --json number,title,url,headRefName,baseRefName,author,body29 ```306. Show the PR title and URL for confirmation before proceeding.3132## Step 2: Fetch the Diff and Changed Files33341. Get the full diff:35 ```bash36 gh pr diff <NUMBER>37 ```382. Get the list of changed files with line counts:39 ```bash40 gh pr view <NUMBER> --json files --jq '.files[] | "\(.path) +\(.additions) -\(.deletions)"'41 ```4243## Step 2.5: Load the Repository's Conventions4445Read the repo's own rules before judging the code. They decide what counts as a defect here — reviewing against generic taste produces comments the team will reject.4647```bash48ls CLAUDE.md AGENTS.md CONTRIBUTING.md README.md 2>/dev/null49ls .github/PULL_REQUEST_TEMPLATE.md .github/pull_request_template.md 2>/dev/null5051# conventions local to the directories this PR touches52gh pr view <NUMBER> --json files -q '.files[].path' | xargs -r -n1 dirname | sort -u \53 | while read -r d; do ls "$d"/CLAUDE.md "$d"/AGENTS.md "$d"/README.md 2>/dev/null; done54```5556Read what exists (skip any `CLAUDE.md` already in your context) and extract the rules that make findings concrete:5758- Required and forbidden patterns, architecture and layering rules, module boundaries59- Error-handling, logging and observability conventions60- Naming, file layout, and where tests belong; test requirements for new code61- Dependency policy, security rules, generated files that must not be hand-edited62- Build/lint/test commands the author was expected to run6364How this changes the review:6566- **A violation of a documented repo rule is a finding**, even when the code would be fine elsewhere. Cite the source — `CLAUDE.md:42 requires …` — so the comment is actionable rather than a matter of opinion.67- **A pattern the repo explicitly endorses is not a finding**, however much it differs from your own preference. Drop those comments.68- **If a documented rule and the diff conflict and the rule looks stale**, raise it as ❓ a question about the rule, not as 🔴 critical.69- **Check the PR body against the repo's template** — a missing required section or an unticked mandatory checklist item is worth one comment, not one per item.7071## Step 3: Analyze Each Changed File7273For each changed file in the diff:74751. **Read the full file** for context (not just the diff) using the Read tool.762. **Understand the purpose** of the changes from the diff hunks and surrounding code.773. **Review for issues** across these categories:7879| Tag | What to look for |80|-----|-----------------|81| 🔴 Critical | Bugs, logic errors, incorrect behavior, data loss risks |82| 🔒 Security | Injection, auth bypass, secrets exposure, unsafe deserialization |83| ⚡ Performance | N+1 queries, unnecessary re-renders, memory leaks, O(n²) when O(n) is possible |84| 🐛 Bug | Null pointer risks, off-by-one errors, race conditions, unhandled errors |85| ✨ Improvement | Clearer naming, better patterns, simpler logic, unnecessary complexity |86| 🧪 Testing | Missing test cases, untested edge cases, weak assertions |87| 📝 Documentation | Missing/incorrect JSDoc, misleading comments, unclear intent |88894. **Trace dependencies** — use Grep/Glob to check callers, interfaces, and types affected by the change when relevant.905. **Check the PR description** — verify the code matches what the author says they changed.9192### Review guidelines9394- Focus on **substantive issues** — skip formatting nitpicks, trivial style preferences, and obvious code.95- **Judge against the repo's conventions from Step 2.5, not your own preferences.** Quote the rule you're invoking.96- Every comment must be **actionable** — say what to change, not just what's wrong.97- Include a **concrete code suggestion** when possible.98- Be respectful and constructive. Assume the author is competent.99- Don't comment on unchanged code unless a change introduces an issue with it.100- For large PRs (20+ files), prioritize critical and security issues. Mention that a full review is recommended.101102## Step 4: Present Findings103104Display ALL findings sorted by severity (critical first), then by file order in the diff.105106For each finding:107108```md109### #N — [TAG] file/path.ts:L<line>110**Issue**: [Clear, concise description of the problem]111**Suggestion**: [Concrete fix or code change]112```113114After presenting all findings:115116- Show a summary count: `Found X issues: N critical, N security, N bugs, N improvements...`117- If no issues found, say so clearly.118119Then ask:120121> **Ready to submit this review?** Enter "yes" to post all comments, "remove N,N" to drop specific items, or "edit N" to modify a comment before posting.122123## Step 5: Submit the Review124125Submit a single review using the GitHub API with event `COMMENT`:126127```bash128gh api repos/{owner}/{repo}/pulls/{number}/reviews --method POST --input /tmp/pr-review-payload.json129```130131Build the JSON payload with all comments. Each comment needs:132- `path`: file path relative to repo root133- `line`: the line number in the diff (use the **new file** line number for added/modified lines)134- `side`: `"RIGHT"` for comments on the new version of the code135- `body`: the review comment text with tag, issue description, and suggestion. Always append `\n\n---\n_[Generated by AI]_` at the end of every comment body136137### Building the review payload138139Construct a temporary JSON file with the review data:140141```json142{143 "event": "COMMENT",144 "body": "Review summary — found N issues across M files.",145 "comments": [146 {147 "path": "src/auth.ts",148 "line": 45,149 "side": "RIGHT",150 "body": "🔴 **Critical**: Missing null check on `user` before accessing `.id`. This will throw if the query returns no results.\n\n**Suggestion**:\n```ts\nif (!user) {\n throw new NotFoundError('User not found');\n}\n```\n\n---\n_[Generated by AI]_"151 }152 ]153}154```155156Submit with:157```bash158gh api repos/{owner}/{repo}/pulls/{number}/reviews --method POST --input /tmp/pr-review-payload.json159```160161Clean up the temp file after submission.162163### Line number mapping164165- For comments on **added or modified lines**: use the line number from the new file (`+` side of the diff), set `side: "RIGHT"`.166- For comments on **deleted lines**: use the line number from the old file (`-` side of the diff), set `side: "LEFT"`.167- To find the correct line number, parse the diff hunk headers (`@@ -old_start,old_count +new_start,new_count @@`) and count lines from there.168169## Step 6: Confirmation170171After successful submission:172173```md174## Review Submitted175176PR #<number> — <title>177URL: <review URL>178179Posted <N> inline comments across <M> files.180```181182If submission fails, show the error and suggest the user check their `gh` auth permissions.