Systematically address unresolved review feedback on a pull request.
Input
PR number or URL ($ARGUMENTS; auto-detects from current branch if omitted). Optional: -- <additional context> for prioritization guidance.
Unattended mode: --unattended never asks; Steps 2–3 say what happens instead.
Process
Step 1: Fetch Unaddressed Threads
Use GraphQL — the REST API does NOT expose isResolved status on review threads. Threads whose last comment is ours are awaiting the reviewer, so they are filtered out here in every mode. When composed by forge-guard, reuse its $PR and $ME instead of re-deriving them.
# Derive owner/repo from the checkout; PR_ARG is the number or URL from $ARGUMENTS, empty when omitted
PR_ARG=""
OWNER=$(gh repo view --json owner --jq .owner.login)
REPO=$(gh repo view --json name --jq .name)
PR_NUMBER=$(gh pr view $PR_ARG --json number --jq .number) # empty PR_ARG → PR for the current branch
ME=$(gh api user --jq .login)
gh api graphql -F owner="$OWNER" -F repo="$REPO" -F pr="$PR_NUMBER" -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
path
line
id
comments(last: 20) {
nodes { id body author { login } url }
}
}
}
}
}
}' --jq ".data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false and .comments.nodes[-1].author.login != \"$ME\")"
Step 2: Process Each Thread
For each unaddressed thread, read the file and surrounding context, then categorize:
- Actionable — code change needed
- Question — respond with explanation
- Discussion — assess if change improves code
- Already addressed — thread not resolved but change was made
- Won't fix — current approach is preferred
- Deferred — valid but out of scope — becomes a Deferred item (new Issue)
For Discussion threads where the decision is genuinely the user's to make, ask via AskUserQuestion instead of assuming. In unattended mode: decide when the code or project conventions settle it and say which evidence did. When neither does, reply "Needs your decision: vs — ", leave the thread open, and list it under needing a human decision in the summary — never resolve it or hide it in an Issue.
Step 3: Address and Reply Individually
Address each thread and reply before moving to the next, so every reply can cite the commit that resolved it.
For each thread:
- Make the change (if actionable)
- Run lint/format/checks
- Commit:
git commit -m "fix: address PR feedback — <brief description>" - Reply, and resolve when the outcome is concrete — Actionable, Already addressed, or Deferred. Question, Discussion, and Won't fix stay open so the reviewer sees the reasoning. One mutation does both (drop
resolveReviewThreadfor threads that stay open); pass the reply as a GraphQL variable on stdin — interpolating it into the query breaks on quotes and newlines:
gh api graphql -f threadId="<THREAD_ID>" -F body=@- -f query='
mutation($threadId: ID!, $body: String!) {
addPullRequestReviewThreadReply(input: {pullRequestReviewThreadId: $threadId, body: $body}) {
comment { id }
}
resolveReviewThread(input: {threadId: $threadId}) {
thread { isResolved }
}
}' <<'REPLY_EOF'
<response>
REPLY_EOF
Reply format by category:
- Actionable: "Fixed in
<sha>. " - Question: ""
- Discussion: ""
- Already addressed: "Addressed in
<sha>." - Won't fix: "Keeping current approach because ."
- Deferred: "Created # to track this."
Step 4: Create Issues for Deferred Items
For each Deferred item, create an Issue in the project's Issue tracker (see issue-operations). Include the PR context: reviewer's comment, PR number, and proposed solution.
Step 5: Push and Summarize
git push
Report: threads addressed, commits created, Deferred items created, threads needing a human decision.
Guidelines
- GraphQL for discovery — REST API doesn't show resolution status
- Address, reply, then next — don't batch
- Be specific — reference commits, line numbers, and code
- Test changes — run checks before committing
Related Skills
If the feedback required substantial changes: Use forge-reflect for one more self-review before re-requesting review.
Composed by: forge-guard runs this process in unattended mode for each feedback round.
Example Usage
/forge-address-pr-feedback 123
/forge-address-pr-feedback 123 -- prioritize security comments
/forge-address-pr-feedback --unattended 123
/forge-address-pr-feedback