| name | address-pr-review |
| description | Address reviewer and bot comments on a GitHub pull request — validate each comment, apply fixes where valid, reply with reasoning, and resolve threads. |
| when_to_use | Use when responding to review comments on a GitHub pull request (human reviewer or bot such as Coderabbit, DeepSource), after feedback has been left and needs iteration. |
| argument-hint | [PR_NUMBER] [subagent|no-subagent|auto] |
Address PR Review
Work through unresolved review comments on a GitHub pull request: fetch each thread, validate the claim against the pinned code, apply fixes where valid, reply with technical reasoning, and resolve the thread.
This skill is a companion to code-review. code-review finds gaps proactively from the diff; address-pr-review reacts to comments already on the PR.
Subagent Mode (argument)
Second $ARGUMENTS slot controls subagent delegation:
| Value | Meaning |
|---|
subagent | Delegate comment validation research and multi-file fixes to Task subagents in parallel |
no-subagent | Stay in main context — no Task delegation |
auto | Decide per comment: research-heavy or multi-file → delegate; simple → stay in-context |
| (empty) | Same as auto |
Default: auto. Validation re-reads always run in main context regardless of this mode.
Arguments
$ARGUMENTS is [PR_NUMBER] [subagent|no-subagent|auto]. Either slot may be omitted.
$1 — PR number. If omitted, infer from the current branch.
$2 — subagent mode (see above).
Resolution rules:
- If
$1 is a number → treat as PR number.
- If
$1 is one of subagent/no-subagent/auto → treat as subagent mode; infer PR from branch.
- If
$1 is empty → infer PR from branch. If on main/master with no PR, ask the user.
Workflow Overview
┌──────────────────────────────────────┐
│ 1. Resolve PR number + repo │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 2. Fetch unresolved review threads │
│ via GraphQL │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 3. Detect stack + dependency versions │
│ (per-package in monorepos) │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 4. Validate each comment │
│ → valid / partial / invalid / │
│ defer / repeat │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 5. Present summary → AskUserQuestion │
│ (Apply / Done — free-form Other) │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 6. Apply fixes (tracked fix loop) │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 7. Push (commits live on origin) │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 8. Reply to each item (cite live SHA) │
│ 8a inline · 8b issue / body │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 9. Resolve inline threads │
│ (carve-out defer) │
└──────────────┬───────────────────────┘
▼
┌──────────────────────────────────────┐
│ 10. Update PR description (optional) │
└──────────────────────────────────────┘
Instructions
Step 1: Resolve PR number and repo
Always re-check the current branch first. Do not rely on conversation memory.
git branch --show-current
Resolve the repo:
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
OWNER=${REPO%/*}
NAME=${REPO#*/}
Resolve PR:
- If
$1 is a number → PR=$1.
- Else infer from current branch:
PR=$(gh pr view --json number --jq '.number' 2>/dev/null).
- If empty (not a PR branch) → ask the user for the PR number.
Step 2: Fetch unresolved review threads, issue comments, and review bodies
GitHub PRs carry feedback in three distinct surfaces, and this skill must address all of them:
- Inline review threads (
reviewThreads) — comments pinned to a diff line; can be resolved.
- Issue-level comments (
comments) — free-form PR conversation (bots like Coderabbit's summary, human chat). Cannot be "resolved"; handled via reply.
- Review bodies (
reviews.body) — top-level summary text a reviewer writes when submitting a review. Cannot be replied-to inline; acknowledged via an issue comment.
Fetch all three in one GraphQL call:
{
repository(owner: "<OWNER>", name: "<NAME>") {
pullRequest(number: <PR>) {
reviewThreads(first: 50) {
nodes {
id
isResolved
comments(first: 5) {
nodes { id databaseId body author { login } createdAt }
}
}
}
comments(first: 50) {
nodes { id databaseId body author { login } createdAt }
}
reviews(first: 50) {
nodes { id databaseId body state author { login } submittedAt }
}
}
}
}
Execute via gh api graphql -f query=....
Filtering:
reviewThreads → keep isResolved == false.
comments (issue-level) → keep ones authored after the last push by the PR author, or that contain actionable feedback (bots often post a summary + suggestions here). Skip your own prior replies and pure acknowledgements.
reviews → keep state in (CHANGES_REQUESTED, COMMENTED) with non-empty body. Skip APPROVED unless the body contains actionable notes.
If all three surfaces are empty, report "No unresolved feedback" and stop.
Pagination note: reviewThreads(first: 50), comments(first: 50), reviews(first: 50), and comments(first: 5) per thread will silently truncate large inputs. Add a totalCount selection to each; if any overflow, re-run with pageInfo { endCursor hasNextPage } and an after: cursor until exhaustion.
ID usage:
- Inline thread reply → REST
in_reply_to with comment databaseId (Step 8a).
- Inline thread resolve → GraphQL thread node
id (Step 9).
- Issue comment reply → new issue comment via
gh pr comment or REST POST /issues/:n/comments (Step 8b). No threading, no resolve.
- Review body acknowledgement → same as issue comment (Step 8b). No resolve.
Step 3: Detect stack and dependency versions
Get changed files in this PR:
gh pr view "$PR" --json files --jq '.files[].path'
Group changed paths by package/service (first path segment in monorepos; repo root for single-package repos). For each affected package, read:
- The relevant dependency manifest / lockfile (see the stack → manifest table in ../code-review/references/dependency-grounding.md)
- Any runtime pinning file present:
.tool-versions, .nvmrc, .python-version, .ruby-version
- The package-level
AGENTS.md / CLAUDE.md / CONTRIBUTING.md closest to the changed files
Multi-package awareness: different packages may pin different versions, enforce different conventions, and require different compile/check commands. Track all affected packages. Validation in Step 4 and checks in Step 6 must cover all of them — no global assumptions.
Step 4: Validate each comment
Process all three surfaces uniformly: inline threads, issue comments, and review bodies. For items without a file:line anchor (issue comments, review bodies), extract file/line references from the body text itself — bots often embed them as path/to/file.ts:42 or Markdown links.
For each item:
- Read the commented code — open the file at the commented/referenced line range. Use
Read directly; do not trust the comment's excerpt. If the item has no file anchor and references nothing, treat it as a general remark (design, scope, acknowledgement).
- Understand the claim — is it a bug, a style preference, a factual assertion about library behavior, a broader design concern?
- Ground the claim:
- Library behavior → verify against the exact pinned version using ../code-review/references/dependency-grounding.md. Do not reason from latest-release knowledge.
- Pattern claim ("this is how we do X here") → Grep the codebase for counter-examples or confirming examples
- Style / convention → check the project's linter/formatter configs and the nearest
AGENTS.md. If the config explicitly disables a rule, the comment may be invalid
- Cross-stack integration → trace per ../code-review/references/integration-tracing.md
- Repeat of a previously-addressed point → check the PR description's Design Decisions section (or equivalent); bots often lack memory across rounds
- Classify the comment:
- Valid — the issue exists; will apply a fix
- Partially valid — the premise is right but the proposed fix isn't; will apply a modified fix
- Invalid — wrong premise; will reply with technical reasoning
- Acknowledged, defer — fair observation but out of scope for this PR
- Repeat — already addressed in a previous round or in the PR description
Subagent usage (per Subagent Mode): for research-heavy validation (cross-repo pattern search, deep library source inspection, changelog reading), delegate to subagents where appropriate. Keep the actual Read to confirm the commented code in the main context.
Present a summary table to the user. Include a Source column so the user sees where each item lives (resolve-capable or not):
| # | Source | Ref | File:line | Severity | Summary | Classification | Proposed action |
|---|--------------|------------|------------------|----------|---------|----------------|-----------------|
| 1 | inline | #R_aaa | src/auth.ts:45 | HIGH | ... | Valid | Fix + resolve |
| 2 | issue-comment| #IC_123 | (none) | MED | ... | Valid | Fix + reply |
| 3 | review-body | #RV_456 | src/api.ts:89 | LOW | ... | Invalid | Reply only |
Source values: inline (reviewThread), issue-comment, review-body.
Step 5: Present and ask
Use AskUserQuestion with two options. Fallback via "Other" for any subset.
{
"questions": [
{
"question": "Apply the proposed actions for all N threads?",
"header": "Address comments",
"multiSelect": false,
"options": [
{
"label": "Apply all actions",
"description": "Fix valid/partial, reply to all, resolve all threads"
},
{
"label": "Done — not now",
"description": "Exit without changes"
}
]
}
]
}
Pluralization: for N = 1 use "Apply the proposed action for the 1 thread?".
Free-form "Other" parses the same way as in code-review (see its Step 3): 1,3,5 / only valid / skip #2 / etc. Ambiguous input → confirm, do not guess.
Step 6: Apply fixes (tracked fix loop)
For threads classified Valid or Partially valid in the approved set.
Pre-gate checklist (same as code-review Step 4):
- Working tree clean, or user explicitly approved mixing
- Current branch still matches the PR branch (
git branch --show-current)
- Every referenced
file:line still exists
Tracked fix loop:
-
TaskCreate one task per thread to fix:
subject: Fix thread #N — <file:line> — <classification>
activeForm: Fixing thread #N
-
For each thread sequentially:
TaskUpdate status=in_progress
- Read the file region
- Apply the fix (Edit, or delegate multi-file to a
general-purpose subagent per Subagent Mode)
- Post-fix verify — re-read to confirm change took effect. For type/compile-sensitive edits run the project's own check (e.g.
tsc --noEmit, go build, pytest --collect-only, linter). Use whatever the project already uses; do not introduce new tools.
TaskUpdate status=completed only on successful verification
-
On failure → apply the Failure & Resumption Protocol from ../code-review/references/failure-resumption.md. Halt, create blocker, surface to user with Retry / Skip / Abort.
-
Stage and commit:
git add <modified files>
git commit -m "<message>"
Commit message format:
fix: address review comment <brief>
Thread: <thread-id or quoted comment summary>
Why: <short reason>
Never use --no-verify. Let hooks run. If a hook fails, fix the underlying issue, re-stage, create a new commit — do not --amend unless the user explicitly asks.
Step 7: Push
git push -u origin HEAD
-u origin HEAD avoids the "no upstream branch" error on first push. Do not force push. If push fails because of remote changes, pull/rebase first and reconcile — ask the user if conflicts arise.
Why push before reply? Replies cite commit SHAs (Fixed in abc1234). If the SHA is not live on origin when the reviewer clicks it, GitHub returns 404. Always land the commits remotely before advertising them.
Step 8: Reply to each item
Every processed item gets a reply (including invalid/deferred/repeat). The endpoint depends on the Source:
Step 8a: Inline review threads
Reply threaded to the original inline comment using its REST databaseId. Use -f (typed) not -F (raw string) so the integer in_reply_to is coerced correctly — GitHub's REST API rejects a string here with 422:
gh api repos/"$OWNER"/"$NAME"/pulls/"$PR"/comments \
-X POST \
-f in_reply_to="$DATABASE_ID" \
-f body="<reply>"
Step 8b: Issue comments and review bodies
These have no thread anchor. Post a new PR issue comment that quotes or references the original so the reply is attributable. Mention the reviewer's handle to re-notify them.
gh pr comment "$PR" --body "<reply>"
Or via REST for scripted batching:
gh api repos/"$OWNER"/"$NAME"/issues/"$PR"/comments \
-X POST \
-f body="<reply>"
Reply body template for issue-comment / review-body items:
@<reviewer> re: <short quote or link to original comment>
<classification reply from the table below>
Link syntax for referencing a specific comment: https://github.com/<OWNER>/<NAME>/pull/<PR>#issuecomment-<databaseId> (issue comment) or #pullrequestreview-<databaseId> (review body).
Reply templates (keep concise, cite the commit where applicable):
| Classification | Reply |
|---|
| Valid + fixed | Valid. <brief explanation>. Fixed in <sha>. |
| Partially valid + fixed | Partially valid. <what was right, what was adjusted>. Fixed in <sha>. |
| Invalid | Invalid — <technical reasoning with evidence, cite file/line or version>. |
| Acknowledged, defer | Acknowledged. Out of scope for this PR — <reason, link backlog/issue if applicable>. Leaving this thread open for your call. |
| Repeat | Already addressed in this PR. See <Design Decisions section / prior thread>. |
Never reply before the fix has been verified, committed, and pushed (for valid cases) — the sha must be live on origin.
Step 9: Resolve threads
Applies to inline review threads only. Issue comments and review bodies have no resolve mechanism on GitHub — the reply in Step 8b is the full closure.
Resolve threads classified Valid, Partially valid, Invalid, or Repeat — using the GraphQL node id from Step 2.
Do NOT resolve threads classified "Acknowledged, defer". The reviewer left a valid-but-out-of-scope observation; auto-resolving their thread reads as dismissal. Leave it open so the reviewer can close it themselves or convert it to a follow-up issue.
Batch into a single GraphQL mutation when possible using aliases:
mutation {
r1: resolveReviewThread(input: { threadId: "<NODE_ID_1>" }) {
thread {
isResolved
}
}
r2: resolveReviewThread(input: { threadId: "<NODE_ID_2>" }) {
thread {
isResolved
}
}
}
Execute via gh api graphql -f query=....
Step 10: Update PR description (optional)
If any comments were classified Acknowledged, defer or Invalid with important reasoning, consider adding/updating a Design Decisions section in the PR description. Bots typically cannot see prior thread replies — only the PR body and latest diff. Documenting there prevents repeat comments in the next round.
Only update if there is new information not already captured. Do not rewrite sections unrelated to review outcomes.
Output Behavior
- Do not narrate workflow steps to the user. No "Step 1: ...".
- First user-visible output should be the summary table (Step 4), not progress chatter about fetching threads or detecting the stack.
- Surface only: summary table, pre-gate failures, fix progress (via TaskCreate/TaskUpdate), reply/resolve confirmations, and the final push result.
Anti-Patterns
- Trusting comments blindly — bots and humans both hallucinate or misread. Always re-read the actual code before accepting or rejecting a claim.
- Grounding against latest instead of pinned version — verify library claims against the exact version pinned in the manifest.
- Global assumptions in a monorepo — different packages may pin different versions and conventions. Validate per-package.
- Replying before verifying the fix — never cite a
sha that isn't real or a fix that wasn't verified.
- Skipping hooks — no
--no-verify unless the user explicitly asks. Pre-commit hooks exist for a reason.
- Force push to address comments — never. Create new commits. If upstream moved, pull/rebase and reconcile.
- Resolving without replying — every processed thread gets a reply, even invalid/deferred. Resolving silently is rude.
- Silent skips on failure — failed fixes route through the Failure & Resumption Protocol. Never drop a thread without a decision.
- Amending someone else's commit — create a new commit. Only amend your own HEAD and only when the user explicitly asks.
- Auto-running the next round — if the bot re-reviews after your push, this skill does not auto-handle the next round. Let the user re-invoke.
- Paraphrasing AskUserQuestion as a prose question — Step 5 presents choices via the AskUserQuestion tool. Invoke it verbatim so the structured panel renders. A natural-language question in chat is a bug, not an alternative.
- Checking only one feedback surface — GitHub PRs carry feedback across three surfaces (
reviewThreads, issue-level comments, and reviews.body). Skipping any of them silently misses entire reviews. Bots like claude[bot] post to issue comments; CodeRabbit often posts to reviews.body; humans use all three. Step 2 is mandatory in full.
- Replying to SHAs that aren't on origin yet — push before reply. A reviewer clicking
abc1234 before the push completes sees a 404.
Example Session
User: /address-pr-review 1234
[Internal: resolve repo, fetch unresolved threads (3), detect stack, validate each]
Claude:
| # | Thread | File:line | Severity | Summary | Classification | Action |
|---|------------|----------------------|----------|----------------------------------|----------------|------------------------|
| 1 | #R_aaa | src/auth.ts:45 | HIGH | Use parameterized query | Valid | Fix |
| 2 | #R_bbb | src/api.ts:89 | MED | Catch should re-throw | Partially | Fix (adjusted) |
| 3 | #R_ccc | src/utils.ts:12 | LOW | Rename helper for clarity | Invalid | Reply with reasoning |
[AskUserQuestion: "Apply the proposed actions for all 3 threads?"
Options: Apply all actions / Done — not now]
User: Apply all actions
[Pre-gate: ✓ clean tree, ✓ branch, ✓ files exist]
[TaskCreate × 2 (for threads 1 and 2 — thread 3 is Invalid, reply only)]
[#1 in_progress → Read → Edit (parameterize query) → verify (re-read) → completed]
[git add src/auth.ts; git commit -m "fix: address review comment on parameterized query
Thread: #R_aaa
Why: prevent SQL injection on user-provided id"]
[#2 in_progress → Read → Edit (throw after log) → verify → completed]
[git add src/api.ts; git commit -m "fix: address review comment on catch re-throw
Thread: #R_bbb
Why: preserve stack; logging alone swallowed the original error"]
[git push -u origin HEAD] ← push BEFORE reply so SHAs are live
[Reply to #1 (8a): "Valid. Switched to parameterized query. Fixed in abc1234."]
[Reply to #2 (8a): "Partially valid. Re-throw after logging preserves the stack. Fixed in def5678."]
[Reply to #3 (8a): "Invalid — the helper name matches the domain term used in docs/GLOSSARY.md and other callers."]
[Resolve threads #1, #2, #3 in one batched mutation (defer carve-out: none deferred here)]
Claude: ## Done
- 2 threads fixed (commits abc1234, def5678), 1 replied as invalid
- All 3 threads resolved
- Pushed to origin/<branch>
References