Resolve PR Review Comments
Capability discovery & grounding
Before researching or recommending, enumerate the tools and skills your session actually exposes — do not assume a fixed set; the user may have installed anything — and select the best fit per ${CLAUDE_PLUGIN_ROOT}/skills/speckit-autopilot/references/capability-discovery.md. Ground every external fact you assert in a real tool, skill, or file result per ${CLAUDE_PLUGIN_ROOT}/skills/speckit-autopilot/references/grounding.md, and abstain when nothing grounds it.
Codex Skill-Selection Guard
If this file is loaded in Codex, the runtime selected the Claude Code
variant from skills/ instead of the Codex variant from codex-skills/.
Do not follow the Claude-oriented instructions below in Codex. Immediately
read and follow ../../codex-skills/speckit-resolve-pr/SKILL.md from this plugin
root, treat that document as the active skill, and report that the fallback
guard was triggered.
Address ALL unresolved review comments on a pull request, fix the code, and mark each thread resolved.
Input
The user provides either:
- A full PR URL:
https://github.com/owner/repo/pull/46 - A full PR review URL:
https://github.com/owner/repo/pull/46#pullrequestreview-123 - Just a PR number:
46(repo detected fromgit remote -v)
What to Do
1. Parse Input and Detect Repo
If full URL provided:
Extract OWNER, REPO, PR_NUMBER from URL
If just a number:
Run `git remote -v` and extract OWNER/REPO from origin URL
PR_NUMBER = the provided number
Check out the PR branch and verify the actual code behavior in that checkout. Never review or remediate from the diff alone.
2. Discover Project Commands
Read CLAUDE.md and package.json (or equivalent) to find:
- BUILD command
- TYPECHECK command
- LINT command
- LINT_FIX command
- UNIT_TEST command
- INTEGRATION_TEST command
Detect package manager from lockfile if Node.js project; the plugin's PreToolUse hook denies a shell command that uses a different manager than the lockfile names.
Run TYPECHECK and UNIT_TEST locally before posting any review comment or reply. Scope every finding to files the PR changed unless the user explicitly asks for a broader review.
3. Fetch All Unresolved Review Threads
Fetch review threads via GraphQL with gh api graphql to get thread IDs
(needed for resolution) and comment details in one call. Query
repository.pullRequest.reviewThreads(first: 100) and include each thread's
id, isResolved, path, line, and the first 10 comments with id,
databaseId, body, author.login, and createdAt.
Filter to unresolved threads only (isResolved == false).
Each thread's id is the threadId needed for resolution.
Each thread's comments.nodes[0] is the original review
comment with the reviewer's feedback.
If 0 unresolved threads, report "No unresolved comments on PR #" and stop.
4. Process Comments — Partition by File, Parallel Across Files
Partition the unresolved threads by file path. Within a partition
(same file), process serially — concurrent edits to the same file race
on the Edit tool. Across partitions (different files), dispatch
parallel background subagents in ONE assistant message. This is
Use site 6 of the Agent Teams integration map.
4a. Detect cross-file comments
Before partitioning, scan each thread's comment body for cross-file
hints (e.g., "rename foo and update all callers", "this affects
bar.ts too", references to other paths). Cross-file comments are
serialized — they touch multiple files and cannot run in parallel
with siblings without race risk.
For each thread:
cross_file = false
if comment body mentions other paths/files/symbols that imply
edits beyond thread.path:
cross_file = true
thread.cross_file = cross_file
4b. Build partitions
PARTITIONS = {} # file_path -> [threads]
CROSS_FILE = [] # serialized, processed last
For each thread:
if thread.cross_file:
CROSS_FILE.append(thread)
else:
PARTITIONS[thread.path].append(thread)
4c. Dispatch parallel subagents per partition
If PARTITIONS has ≥2 entries, dispatch ALL partitions in ONE
assistant message via background subagents:
For each (file_path, threads) in PARTITIONS:
Agent(
subagent_type: "general-purpose",
run_in_background: true,
description: "Resolve PR #<N> comments on <file_path>",
prompt: """
Fix the following review threads on `<file_path>`. Threads are
ordered by line number; address them in order.
## Project commands (from Step 2)
BUILD: <BUILD>
TYPECHECK: <TYPECHECK>
UNIT_TEST: <UNIT_TEST>
LINT_FIX: <LINT_FIX>
## Threads
<list of {thread_id, line, comment_body, comment_id}>
## What to do for each thread
(a) CODE FIX → Edit the file; run BUILD+TYPECHECK+UNIT_TEST; fix
until clean.
(b) STYLE → run LINT_FIX.
(c) QUESTION → prepare a reply (no code change).
(d) FALSE POSITIVE → prepare a reply explaining why no change.
## When done
Commit ALL fixes for this file in one commit:
git add <file_path>
git commit -m "fix: address review - <brief summary>"
Return a structured summary:
- Threads handled (count, IDs, action taken per ID)
- Commit SHA (if any fix committed; null otherwise)
- Verification result (pass/fail; if fail, surface error)
- Per-thread reply text (for the orchestrator to post)
Do NOT push. Do NOT post replies. Do NOT resolve threads.
The orchestrator handles git push and gh API calls serially.
"""
)
If PARTITIONS has 1 entry (all threads on one file), do NOT spawn a
subagent — process directly in the orchestrator (no parallelism win,
extra tool-call latency).
4d. Process cross-file comments serially
After all partition subagents return, process CROSS_FILE threads
one at a time in the orchestrator (each touches multiple files; serial
prevents inter-thread race).
5. Reply and Resolve Each Thread (orchestrator, serial)
The orchestrator collects partition-subagent results, then for each thread (parallel partitions + serial cross-file) posts the reply and resolves the thread via gh API. Writes to GitHub are cheap and ordered:
Reply to the comment:
Use `gh api repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/comments` with `POST`,
`body='<explanation of what was fixed or why no change>'`, and
`in_reply_to=<comment_id>`.
Resolve the review thread:
Use `gh api graphql` with the `resolveReviewThread` mutation and
`threadId: "<thread_id>"`.
The <thread_id> comes from the GraphQL query in Step 3
(each thread's id field). Do NOT use the comment's
node_id — thread resolution requires the thread ID.
A new finding of your own (not a reply) goes inline: POST repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/comments with path, line,
side, and commit_id targeting the exact diff line. A summary
comment is not a substitute for an inline one.
6. Verify, Push, Confirm
After all comments are addressed, finish in one pass:
- Run the full suite: FULL_VERIFY, or BUILD && TYPECHECK && LINT && UNIT_TEST && INTEGRATION_TEST. A failure here reopens Step 4; do not push a red branch.
- Run
git push. - Confirm with
git status -sb: the branch line must not readahead. Do not report completion until that confirmation is in hand. While an autopilot workflow is active, the plugin's Stop hook blocks ending the turn with unpushed commits.
7. Report Summary
## PR Review Comments Resolved
**PR:** #<PR_NUMBER> (<OWNER>/<REPO>)
**Comments processed:** N total
- Code fixes: N (committed)
- Style fixes: N (committed)
- Replies only: N (questions/false positives)
**Commits pushed:** N
**Threads resolved:** N
**Remaining:** 0 unresolved
(or "N comments could not be resolved — manual review needed")