Interactive PR feedback processing - one thread at a time with plan-execute loop. Invoke with /pr-address-feedback [--author=<name>] [--pr=<number>] [--batch].
/plugin marketplace add jasonkuhrt/claude-marketplace/plugin install github-workflows@jasonkuhrtThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Interactively process PR review threads one at a time. Each thread gets full attention: discussion, planning, execution, and resolution before moving to the next.
| Term | Definition |
|---|---|
| Thread | A GitHub review comment thread (atomic unit on GitHub) |
| Item | A unit of work in this process - either a single thread or multiple related threads processed together |
Actions (what user chooses):
| Action | Code change | Thread closed | Meaning |
|---|---|---|---|
| Address | Yes | Yes | Valid feedback, implement fix |
| Dismiss | No | Yes | Invalid/out-of-scope/noise |
| Prior fix | No | Yes | Already fixed in earlier work |
| Defer | No | No | Too complex, handle manually later |
| Discuss | TBD | TBD | Need conversation first |
/pr-address-feedback - Process all unresolved threads from current branch's PR/pr-address-feedback --author=copilot - Only Copilot feedback/pr-address-feedback --author=<username> - Only feedback from specific user/pr-address-feedback --pr=123 - Specific PR number/pr-address-feedback --batch - Batch mode: defer all GitHub ops to end for confirmation/pr-address-feedback --author=copilot --pr=626 - Combine filters--author=<name>: Filter by thread author (case-insensitive match against login)--pr=<number>: Specific PR number (default: current branch's PR)--batch: Batch mode - defer all GitHub operations until end of session, show confirmation before executingGet repo info and PR number:
OWNER=$(gh repo view --json owner -q '.owner.login')
REPO=$(gh repo view --json name -q '.name')
PR_NUMBER=$(gh pr view --json number -q .number)
Argument parsing: Parse $ARGUMENTS for flags:
--author=<value> if present → store as AUTHOR_FILTER--pr=<number> if present → override PR_NUMBERIf --pr was provided, use it directly:
PR_NUMBER=123 # from --pr argument
Error handling: If gh pr view fails (no open PR for current branch) and no --pr provided:
No open PR found for the current branch.
Options:
1. Specify a PR number: /pr-address-feedback --pr=123
2. Push your branch and open a PR first
Exit gracefully - do not proceed.
Fetch unresolved review threads via GraphQL:
gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
comments(first: 10) {
nodes {
id
databaseId
author { login }
body
path
line
originalLine
diffHunk
url
createdAt
}
}
}
}
}
}
}' -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER"
Field mapping (important for API calls later):
| Response field | Variable name | Used for |
|---|---|---|
thread.id | THREAD_NODE_ID | GraphQL resolveReviewThread |
thread.comments[0].databaseId | COMMENT_DATABASE_ID | REST API reactions and replies |
Limits: Query fetches up to 100 threads with 10 comments each. If a thread has more than 10 comments, only the first 10 are returned. Note this to user if relevant.
PR not found: If the GraphQL response returns pullRequest: null, the PR doesn't exist:
PR #123 not found. Check the PR number and try again.
Exit gracefully.
Zero threads: If PR exists but no unresolved threads found, report "No unresolved review threads found" and exit.
Filter criteria:
isResolved: false--author provided, only include threads where first comment's author login contains the filter string (case-insensitive)createdAt of first commentLine number handling:
line: Current line number in the latest version of the file (may be null if code moved)originalLine: Line number when the comment was made (always present)line if available, fall back to originalLineisOutdated: true, note this in the display - the code may have changed since the commentAnalyze threads for potential grouping:
Only group if HIGH confidence. Criteria:
If grouping is proposed, present to user:
I notice these threads might be related:
1. @copilot on file.ts:45 - "Type casting needed..."
2. @copilot on file.ts:52 - "Similar type issue..."
Group these together? [Yes / No, keep separate]
If no high-confidence groupings found, skip this step silently.
Use TodoWrite to create one task per item:
[pending] #1 @author · file.ts:45 · "first 50 chars..."
[pending] #2 @author · file.ts:89 · "first 50 chars..."
For EACH item, complete this entire loop before moving to next:
Display:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ITEM 1 of N (3 threads)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Author: @username
File: path/to/file.ts:45
URL: https://github.com/...
Comment:
> [full text of first comment]
[If thread has multiple comments, show conversation:]
Reply from @other_user:
> [reply text]
Reply from @username:
> [reply text]
Diff context:
[show diffHunk from the API response]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Item header: Show (K threads) only if item contains multiple threads (was grouped). Single-thread items don't need the count.
If isOutdated: true, add a warning:
⚠️ OUTDATED: This thread may reference code that has changed.
Suggestion blocks: If the comment body contains a GitHub suggestion block (```suggestion ... ```), highlight this:
📝 Contains code suggestion - can be applied directly if approved.
Analysis block: After presenting the thread, analyze and display a triage assessment with a suggested action:
─── Analysis ──────────────────────────────────────────────────────
<SUGGESTED ACTION>
reason: <why this action>
evidence: <commits, policies, code refs - if applicable>
response: <what happens on GitHub thread>
note: <caveats, follow-up ideas - if applicable>
───────────────────────────────────────────────────────────────────
The suggested action is one of: ADDRESS, DISMISS, PRIOR FIX, DEFER, or DISCUSS (see Glossary).
Analysis fields:
| Field | Required | Purpose |
|---|---|---|
reason: | Yes | Why this action is suggested (logic, diagnosis) |
evidence: | If applicable | Specific proof (commits, policies, code locations) |
response: | Yes | What happens on GitHub thread (resolve + comment text, etc.) |
note: | If applicable | Free-form: caveats, follow-up ideas |
Example analyses:
─── Analysis ──────────────────────────────────────────────────────
DISMISS
reason: ARIA not enforced per project policy
evidence: CLAUDE.md § Accessibility, HEA-3834
response: resolve, no comment
───────────────────────────────────────────────────────────────────
─── Analysis ──────────────────────────────────────────────────────
PRIOR FIX
evidence: commit 15762eb
reason: Changed to color="primary" per design
response: resolve + "Fixed in 15762eb"
───────────────────────────────────────────────────────────────────
─── Analysis ──────────────────────────────────────────────────────
ADDRESS
reason: Selector runs before early return, causes unnecessary work
response: after fix → resolve + thumbs up
───────────────────────────────────────────────────────────────────
Use AskUserQuestion:
| Option | Description |
|---|---|
| Go with suggestion | Accept the suggested action + response from analysis |
| Address | Plan and implement a fix (requires approval before code changes) |
| Dismiss | Invalid/out-of-scope feedback, close thread without code changes |
| Prior fix | Already fixed in earlier work, close thread |
| Defer | Too complex, leave thread open for manual handling later |
| Discuss | Talk through the issue before deciding |
| Abort | Stop processing entirely and show summary |
"Go with suggestion" behavior: Accepts the suggested action from the analysis block and proceeds with the specified response:. If the suggested action is ADDRESS, still show the plan for approval before code changes (user is agreeing to the direction, not blanket-accepting the final resolution).
If "Discuss" selected: Have a conversation about the thread. When user indicates they're ready to decide (e.g., "ok let's address it", "skip this one", "I think we can move on"), proceed with that action. If unclear, ask "Ready to choose an action?" and present the same options again.
If "Abort" selected: Jump directly to step 5 (Summary), marking remaining threads as "Not processed".
CRITICAL: No code changes without explicit approval.
Read the relevant file(s) at the specified lines
Analyze what change is needed
If comment contains a suggestion block, extract the suggested code
Present proposed change to user:
Proposed change for: file.ts:45
The thread suggests: [summary]
I propose:
- [specific change 1]
- [specific change 2]
Approve this approach? [Yes / No, let's discuss]
Wait for explicit approval before proceeding
If user says "No, let's discuss": Enter discussion mode. Talk through concerns, refine the approach, then present an updated plan. Repeat until user approves or decides to skip.
pnpm check:types or project equivalentIf user says no (revision needed):
Run this step for all actions except Defer (Address, Dismiss, Prior fix all close the thread).
Batch mode (--batch): Skip execution. Store pending operation {thread_ids, action, reply_text} for batch execution at summary step.
Incremental mode (default): Execute immediately with optimizations below.
Ask about reply first (before any API calls):
Ask: "Add a reply comment? [Yes / No]"
If yes: "What should the reply say?"
Execute GitHub operations with performance optimizations:
Single-thread items - parallel calls with suppressed output:
# Reaction + reply in parallel, suppress verbose JSON
gh api "repos/$R/pulls/comments/$ID/reactions" -X POST -f content='+1' --silent &
[ -n "$REPLY" ] && gh api "repos/$R/pulls/$PR/comments" -X POST \
-f body="$REPLY" -F in_reply_to=$ID --silent &
wait
# Resolve
gh api graphql -f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' \
-f id="$NODE_ID" --silent
Multi-thread items - batch GraphQL mutation:
# Reactions + replies in parallel
for ID in $COMMENT_IDS; do
gh api "repos/$R/pulls/comments/$ID/reactions" -X POST -f content='+1' --silent &
[ -n "$REPLY" ] && gh api "repos/$R/pulls/$PR/comments" -X POST \
-f body="$REPLY" -F in_reply_to=$ID --silent &
done
wait
# Batch resolve ALL threads in ONE call
gh api graphql -f query='mutation {
t1: resolveReviewThread(input:{threadId:"ID1"}){thread{isResolved}}
t2: resolveReviewThread(input:{threadId:"ID2"}){thread{isResolved}}
}' --silent
Background resolution (incremental mode):
Use Claude Code's run_in_background: true parameter to run resolution while presenting next item:
Mark task as completed in TodoWrite.
Performance notes:
--silent suppresses 70+ line JSON responses& + wait for independent REST callsError handling: If any API call fails:
Flow summary:
Batch mode (--batch): Before showing the summary, execute all pending GitHub operations:
Show pending operations for confirmation:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PENDING OPERATIONS N items → M threads
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#1 ADDRESSED @copilot
└─ "Selector runs before early return"
> Moved early return above selector call.
#2 DISMISSED @copilot (3 threads)
├─ "aria-label for filter button"
├─ "aria-label for dropdown buttons"
└─ "ARIA menu roles"
> Out of scope - accessibility strategy pending (HEA-3834).
...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Use AskUserQuestion to let user select which items to execute (all selected by default, can deselect to skip). Include "Edit replies" and "Abort" as additional options.
If "Edit replies" selected: Let user modify reply text for specific items, then re-present selection.
If confirmed, execute all operations with progress indicator:
Resolving threads... [████████░░] 8/10
Continue to summary display.
Incremental mode: Verify any background resolution tasks completed, then show summary.
After all threads processed (or aborted):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SUMMARY N items → M threads
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
─── CLOSED (X threads) ────────────────────────────────────────────
#1 ADDRESSED @author
└─ "Truncated feedback summary..."
https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
> Reply text that was posted.
#2 DISMISSED @author
├─ "First thread feedback summary"
│ https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
├─ "Second thread feedback summary"
│ https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
└─ "Third thread feedback summary"
https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
> Reply posted to all threads.
#3 PRIOR FIX @author
└─ "Feedback that was already addressed"
https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
> Fixed in abc123.
─── REMAINS OPEN (Y threads) ──────────────────────────────────────
#4 DEFERRED @author
└─ "Complex issue needing manual review"
https://github.com/owner/repo/pull/NNN#discussion_rNNNNNN
─── Artifacts ─────────────────────────────────────────────────────
• [any files created/modified]
• [any issues created]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Summary structure:
| Element | Description |
|---|---|
| Header | SUMMARY left, N items → M threads right-aligned |
| CLOSED section | Items where thread was resolved (Addressed, Dismissed, Prior fix) |
| REMAINS OPEN section | Items where thread stays open (Deferred, Aborted) |
| Artifacts section | Only if files modified or issues created |
Item format:
#N ACTION @author
├─ "Truncated feedback summary (~40 chars)"
│ https://full-github-url-to-thread
└─ "Another thread if grouped"
https://full-github-url-to-thread
> Reply text that was posted (or "(no reply)" if none)
#N ACTION @author (no file names)├─ / └─ / │ for visual hierarchyNotes:
If changes were made, ask: "Create a commit for these changes?"
| Action | Description |
|---|---|
| Go with suggestion | Accept suggested action + response from analysis |
| Address | Plan and implement fix with user approval |
| Dismiss | Invalid/out-of-scope, close thread without changes |
| Prior fix | Already fixed earlier, close thread |
| Defer | Too complex, leave thread open for manual handling |
| Discuss | Talk through approach before deciding |
| Abort | Stop processing and show summary |
# Process all Copilot feedback
/pr-address-feedback --author=copilot
# Process feedback from specific reviewer
/pr-address-feedback --author=ceremonious
# Process all feedback from current PR
/pr-address-feedback
# Process feedback from specific PR
/pr-address-feedback --pr=626
# Combine: Copilot feedback on specific PR
/pr-address-feedback --author=copilot --pr=626
gh CLI authenticated: gh auth statuscopilot-pull-request-reviewer but --author=copilot should match it (case-insensitive contains)isOutdated: true) may reference code that has moved or changed - verify before applying fixesPR replies come from the user's GitHub account. Keep them:
Good examples:
Use when working with Payload CMS projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.