Agent skill

resolve-review

Interactive PR review resolution - one thread at a time with plan-execute loop. Invoke with /resolve-review [--author=<name>] [--pr=<number>] [--batch] [--self].

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/pr-resolve-review

SKILL.md

Resolve Review

Goal

Interactively process PR review threads one at a time. Each thread gets full attention: discussion, planning, execution, and resolution before moving to the next.

Glossary

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
Part A distinct feedback point within a PR comment - multi-point comments are split into parts
PR Comment An issue comment on the PR (not tied to specific code lines), distinct from review threads

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

Usage

  • /resolve-review - Process all unresolved threads from current branch's PR
  • /resolve-review --author=copilot - Only Copilot feedback
  • /resolve-review --author=<username> - Only feedback from specific user
  • /resolve-review --pr=123 - Specific PR number
  • /resolve-review --batch - Batch mode: defer all GitHub ops to end for confirmation
  • /resolve-review --author=copilot --pr=626 - Combine filters
  • /resolve-review --self - Include your own comments and threads (for testing or self-review)
  • /resolve-review --self --pr=123 - Test against specific PR including own feedback

Arguments

  • All arguments: $ARGUMENTS
  • --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 executing
  • --self: Include own comments and review threads (disabled by default). Useful for testing or reviewing your own notes.
  • --no-commit: Disable per-item commits. Changes accumulate, user commits manually after session.

Instructions

1. Fetch Unresolved Review Threads

Get repo info and PR number:

bash
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:

  • Extract --author=<value> if present → store as AUTHOR_FILTER
  • Extract --pr=<number> if present → override PR_NUMBER
  • Extract --self flag if present → store as INCLUDE_SELF=true
  • Extract --no-commit flag if present → store as NO_COMMIT=true

If --pr was provided, use it directly:

bash
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: /resolve-review --pr=123
2. Push your branch and open a PR first

Exit gracefully - do not proceed.

Fetch review threads and PR comments via unified GraphQL query:

bash
gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
  viewer { login }
  repository(owner: $owner, name: $repo) {
    pullRequest(number: $pr) {
      id
      reviewThreads(first: 100) {
        nodes {
          id
          isResolved
          isOutdated
          comments(first: 10) {
            nodes {
              id
              author { login }
              body
              path
              line
              originalLine
              diffHunk
              url
              createdAt
            }
          }
        }
      }
      comments(first: 100) {
        nodes {
          id
          author { login }
          body
          url
          createdAt
          isMinimized
          minimizedReason
        }
      }
    }
  }
}' -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUMBER"

Field mapping (important for API calls later):

Response field Variable name Used for
pullRequest.id PR_NODE_ID GraphQL replies and summary comment
thread.id THREAD_NODE_ID GraphQL resolveReviewThread
thread.comments[0].id COMMENT_NODE_ID GraphQL addReaction, addPullRequestReviewComment
comments[].id COMMENT_NODE_ID GraphQL addReaction, minimizeComment
viewer.login CURRENT_USER Self-exclusion filter

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 for review threads:

  • Only include threads where isResolved: false
  • If --author provided, only include threads where first comment's author login contains the filter string (case-insensitive)
  • Exclude threads where first comment's author matches viewer.login (unless --self flag)
  • Sort by createdAt of first comment

Filter criteria for PR comments:

  • Only include comments where isMinimized: false
  • If --author provided, filter by author login (case-insensitive contains)
  • Exclude comments where author matches viewer.login (unless --self flag)
  • Sort by createdAt

Note: GitHub's GraphQL API doesn't support server-side filtering. These filters are applied client-side after fetching.

Line 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)
  • Use line if available, fall back to originalLine
  • If isOutdated: true, note this in the display - the code may have changed since the comment

1.5. PR Comments Discovery

After filtering, if any PR comments remain, prompt the user:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Found N unresolved review threads.

Also found M PR comments (not on specific code lines):
  • @author: "First 40 chars of comment..." (2 days ago)
  • @author: "Another comment preview..." (1 day ago)

Include these as feedback to resolve? [Yes / No]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  • If Yes: PR comments are processed after review threads
  • If No: PR comments are ignored for this session
  • If zero review threads but PR comments exist: show prompt without "Also found" phrasing

1.6. Part Analysis for PR Comments

If PR comments are included, analyze each comment for distinct feedback points.

Analysis process:

  1. Parse comment body for distinct feedback points
  2. Look for: numbered lists, bullet points, separate paragraphs with different topics, "also"/"and"/"another thing" transitions
  3. Create one "part" per distinct point
  4. Single-point comments get one part (no splitting needed)

Part data:

  • comment_node_id: Parent comment ID (for minimization)
  • comment_url: Link to parent comment
  • part_index: 1-based index within comment
  • part_total: Total parts in this comment
  • part_text: Extracted text for this part
  • full_body: Full comment body (for context)

Grouping: Parts participate in semantic grouping (Step 2). A part from one comment could be grouped with a review thread or part from another comment if they address the same issue.

1.7. Session Preferences

After determining items to process, prompt for session preferences using AskUserQuestion with multiSelect.

Display format:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Found N items to process.

ℹ️  Each addressed item creates a commit (disable: --no-commit)

After resolving:
  [ ] Post summary comment to PR
  [ ] Push commits to remote
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

AskUserQuestion options (both default: checked):

  • POST_SUMMARY: Post summary comment to PR
  • PUSH_COMMITS: Push commits to remote

If --no-commit flag is set, show modified message (omit PUSH_COMMITS option):

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Found N items to process.

ℹ️  Per-item commits disabled (--no-commit)

After resolving:
  [ ] Post summary comment to PR
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Store selections in SESSION_PREFS.

SESSION_PREFS data:

  • post_summary: boolean (from POST_SUMMARY selection)
  • push_commits: boolean (from PUSH_COMMITS selection)

Step 5 (Summary) uses these preferences for end-of-session actions.

2. Semantic Grouping (Optional)

Analyze threads for potential grouping:

  • Same file + adjacent lines (within 10 lines) = potential group
  • Same reviewer + same conceptual issue = potential group
  • PR comment parts can be grouped with review threads or other parts
  • Same conceptual issue across different feedback types = potential group

Only group if HIGH confidence. Criteria:

  • Threads reference the same function/block
  • Threads describe the same issue type (e.g., "missing type cast" appearing twice)

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]

Mixed grouping (review thread + PR comment part):

I notice these items might be related:
1. @copilot on file.ts:45 - "Type casting needed..."
2. @copilot PR comment part 2/3 - "Similar type issue mentioned..."

Group these together? [Yes / No, keep separate]

If no high-confidence groupings found, skip this step silently.

3. Create Task List

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..."

4. Process Each Item (Serial Loop)

For EACH item, complete this entire loop before moving to next:

4a. Present Item

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.

PR Comment presentation (single-point):

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ITEM 5 of 9                                              PR COMMENT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Author: @username
URL: https://github.com/...

Comment:
> Full comment text here.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

PR Comment presentation (multi-point, showing one part):

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ITEM 6 of 9                                    PR COMMENT · part 1/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Author: @username
URL: https://github.com/...

Full comment:
> Can we add a loading state? Also the error handling seems
> incomplete. And should we add types for the response?

This part:
> Can we add a loading state?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Header badge rules:

  • Review thread: (K threads) only if grouped
  • Single-point PR comment: PR COMMENT
  • Multi-point PR comment: PR COMMENT · part N/M

PR comment differences:

  • No File: line (not tied to specific code)
  • No Diff context: section
  • Multi-point comments show both full comment and extracted part

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
───────────────────────────────────────────────────────────────────

4b. Get User Direction

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".

4c. Plan (if addressing)

CRITICAL: No code changes without explicit approval.

  1. Read the relevant file(s) at the specified lines

  2. Analyze what change is needed

  3. If comment contains a suggestion block, extract the suggested code

  4. 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]
    
  5. 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.

4d. Execute (if approved)

  1. Make the agreed-upon changes

  2. Run type checks: pnpm check:types or project equivalent

  3. If type checks fail:

    • Show the errors to user
    • Ask: "Type errors found. [Show full errors / Fix and retry / Skip this thread]"
    • If "Fix and retry": analyze errors, fix, re-run type checks
    • Repeat until passing or user skips
  4. Show the diff to user

  5. Ask: "Changes look correct? [Yes / No, needs revision]"

  6. Commit the change (if approved and --no-commit not set):

    If NO_COMMIT is not set (from --no-commit flag):

    bash
    # Stage changed files
    git add <modified_files>
    
    # Commit with descriptive message
    git commit -m "fix(<scope>): <brief description from feedback>"
    

    Store commit SHA in item's commit_sha field for summary comment.

    Commit message format:

    • fix(file): <action taken> for bug fixes
    • feat(file): <action taken> for new functionality
    • refactor(file): <action taken> for refactoring

    Example: fix(user): add null check before accessing name

If user says no (revision needed):

  1. Ask: "What should be different?"
  2. Discuss the issue
  3. Make revised changes
  4. Run type checks again (with same error handling)
  5. Show updated diff
  6. Repeat until user approves or decides to skip

4e. Resolve on GitHub

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.

  1. Ask about reply first (before any API calls):

    Ask: "Add a reply comment? [Yes / No]"

    If yes: "What should the reply say?"

  2. Execute GitHub operations via pure GraphQL:

    Review thread resolution (single or batched):

    bash
    gh api graphql -f query='
    mutation($commentId: ID!, $prId: ID!, $threadId: ID!, $body: String!) {
      addReaction(input: {subjectId: $commentId, content: THUMBS_UP}) {
        reaction { content }
      }
      addPullRequestReviewComment(input: {
        body: $body,
        pullRequestId: $prId,
        inReplyTo: $commentId
      }) {
        comment { id }
      }
      resolveReviewThread(input: {threadId: $threadId}) {
        thread { isResolved }
      }
    }' -f commentId="$COMMENT_NODE_ID" -f prId="$PR_NODE_ID" \
       -f threadId="$THREAD_NODE_ID" -f body="$REPLY" --silent
    

    If no reply needed, omit the addPullRequestReviewComment mutation.

    Multi-thread batch (all in one call):

    bash
    gh api graphql -f query='
    mutation {
      r1: addReaction(input: {subjectId: "ID1", content: THUMBS_UP}) { reaction { content } }
      r2: addReaction(input: {subjectId: "ID2", content: THUMBS_UP}) { reaction { content } }
      t1: resolveReviewThread(input: {threadId: "TID1"}) { thread { isResolved } }
      t2: resolveReviewThread(input: {threadId: "TID2"}) { thread { isResolved } }
    }' --silent
    

    PR comment resolution:

    PR comments don't get individual replies. Track part resolution state:

    • When first part of a comment is processed: add reaction (once per comment)
    • When ALL parts are resolved (addressed, dismissed, prior-fix): minimize the comment
    • If ANY part is deferred: comment stays visible (not minimized)
    bash
    # Reaction (once per comment, on first part)
    gh api graphql -f query='
    mutation($commentId: ID!) {
      addReaction(input: {subjectId: $commentId, content: THUMBS_UP}) {
        reaction { content }
      }
    }' -f commentId="$COMMENT_NODE_ID" --silent
    
    # Minimize (after all parts processed, if eligible)
    gh api graphql -f query='
    mutation($commentId: ID!) {
      minimizeComment(input: {subjectId: $commentId, classifier: RESOLVED}) {
        minimizedComment { isMinimized }
      }
    }' -f commentId="$COMMENT_NODE_ID" --silent
    
  3. Background resolution (incremental mode):

    Use Claude Code's run_in_background: true parameter to run resolution while presenting next item:

    • Start background task for GitHub ops
    • Present next item to user immediately (no waiting)
    • Verify background task completed before summary
  4. Mark task as completed in TodoWrite.

Tracking: Store {item_id, action, commit_sha, thread_url} for summary comment generation.

Performance notes:

  • Pure GraphQL: single API surface, single ID type (node IDs)
  • Batched mutations reduce HTTP round-trips
  • --silent suppresses verbose JSON responses
  • Background tasks eliminate user wait time between items

Error handling: If any API call fails:

  • Show the error to user
  • Ask: "Retry / Skip resolution / Abort session?"

4f. Move to Next

Flow summary:

  • Go with suggestion: Same as the suggested action
  • Address: 4a → 4b → 4c → 4d → 4e → 4f (code change, close thread)
  • Dismiss: 4a → 4b → 4e → 4f (no code, close thread)
  • Prior fix: 4a → 4b → 4e → 4f (no code, close thread)
  • Defer: 4a → 4b → 4f (no code, thread stays open for manual handling)
  • Discuss: 4a → 4b → conversation → user chooses action → proceed accordingly
  • Abort: 4a → 4b → jump to step 5

5. Summary

Batch mode (--batch): Before showing the summary, execute all pending GitHub operations:

  1. 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).
    
    ...
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
    
  2. 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.

  3. If "Edit replies" selected: Let user modify reply text for specific items, then re-present selection.

  4. If confirmed, execute all operations with progress indicator:

    Resolving threads... [████████░░] 8/10
    
  5. Continue to summary display.

Incremental mode: Verify any background resolution tasks completed, then show summary.

Summary comment (posted if POST_SUMMARY selected and any Address actions):

  1. Compose draft from all actions:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PR SUMMARY COMMENT (draft)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

## Feedback Summary

### Review Threads
- [Add null check](https://...) → [`abc1234`](https://github.com/.../commit/abc1234)
- [Also null check here](https://...) → [`abc1234`](https://github.com/.../commit/abc1234)

### PR Comments
- [Add loading state](https://...) → [`def5678`](https://github.com/.../commit/def5678)

### Deferred
- [Complex refactor needed](https://...) - left open for manual handling

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  1. Show draft to user for review. If user wants to edit, adjust content.

  2. Format rules:

    • Group by: Review Threads, PR Comments, Deferred
    • Each addressed item links to thread AND commit (if commits enabled)
    • Grouped items sharing a commit show same commit link
    • Deferred items listed separately, no commit link
    • Dismissed/Prior-fix items omitted entirely
    • If --no-commit or no commits made, omit commit links
    • Omit empty sections
  3. Post via GraphQL:

bash
gh api graphql -f query='
mutation($prId: ID!, $body: String!) {
  addComment(input: {subjectId: $prId, body: $body}) {
    commentEdge { node { id url } }
  }
}' -f prId="$PR_NODE_ID" -f body="$SUMMARY_BODY" --silent

Batch mode: Include summary comment in pending operations for batch confirmation.

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)
  • Item line: #N ACTION @author (no file names)
  • Thread lines: truncated feedback summary + full clickable URL
  • Tree connectors: ├─ / └─ / │ for visual hierarchy
  • Reply block: quoted text of what was posted, for spot-checking

Notes:

  • Items grouped by outcome (CLOSED vs REMAINS OPEN), not processing order
  • Thread count in section header (visually self-evident from tree)
  • Full URLs required (must be cmd-clickable)
  • Reply block shows what user authored into the PR

End of session (no prompts - executes upfront selections):

  1. If SESSION_PREFS.post_summary is true and any Address actions:

    • Post summary comment via GraphQL
    • Display: Posted summary comment: <url>
  2. If SESSION_PREFS.push_commits is true and commits were made:

    • Push to remote: git push
    • Display: Pushed N commits to origin/<branch>
  3. Display terminal summary (existing format)

No additional prompts - session preferences were collected upfront.

Operations

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

Examples

bash
# Process all Copilot feedback
/resolve-review --author=copilot

# Process feedback from specific reviewer
/resolve-review --author=ceremonious

# Process all feedback from current PR
/resolve-review

# Process feedback from specific PR
/resolve-review --pr=626

# Combine: Copilot feedback on specific PR
/resolve-review --author=copilot --pr=626

# Include your own comments (for testing)
/resolve-review --self

# Test against specific PR including own feedback
/resolve-review --self --pr=456

Notes

  • Requires gh CLI authenticated: gh auth status
  • Thread resolution requires write access to the repo
  • See Field mapping table in step 1 for which IDs to use where
  • If a thread was resolved by someone else mid-session, the resolve call will succeed silently (idempotent)
  • Copilot's login is copilot-pull-request-reviewer but --author=copilot should match it (case-insensitive contains)
  • Outdated threads (isOutdated: true) may reference code that has moved or changed - verify before applying fixes
  • PR comments use minimizeComment with RESOLVED classifier - comment becomes collapsed but expandable
  • Multi-point PR comments are split into parts - each part is processed separately
  • Summary comment is always posted if any items were addressed (provides consolidated reference)
  • --self flag is useful for testing or when reviewing your own feedback/notes

Reply Tone

PR replies come from the user's GitHub account. Keep them:

  • Brief (1-2 sentences)
  • Direct and factual
  • Reference commits/code when relevant
  • No AI pleasantries ("Great catch!", "Thanks for pointing this out!")
  • No hedging ("I think", "perhaps", "might")
  • Human but utilitarian

Good examples:

  • "Fixed in abc123."
  • "Moved early return above the selector call."
  • "Intentional - added comment for clarity."
  • "Out of scope for this PR, tracking in HEA-1234."

Critical Rules

  1. NEVER make code changes without user approval - Always present plan first
  2. ONE item at a time - Complete full loop before moving to next
  3. Defer = thread stays open - User must handle manually later
  4. Dismiss/Prior fix = thread closes - No code changes, but thread is resolved
  5. Only unresolved threads - Never show already-resolved threads
  6. Resolve = thumbs up + optional reply + mark thread resolved
  7. User controls pace - Wait for user input at each decision point
  8. Abort exits cleanly - Show summary of what was done

Appendix: API Strategy

Principle: Use pure GraphQL for all GitHub operations. Single API surface, single ID type (node IDs), single request per resolution batch.

Rationale:

  • GraphQL mutations can be batched into one HTTP request
  • Only need node IDs (id field), not database IDs
  • Consistent approach across review threads and PR comments
  • Easier to reason about and maintain

Available mutations:

Operation Mutation Input
Add reaction addReaction subjectId, content
Reply to review thread addPullRequestReviewComment pullRequestId, inReplyTo, body
Resolve thread resolveReviewThread threadId
Minimize PR comment minimizeComment subjectId, classifier
Post PR comment addComment subjectId (PR ID), body

ID types:

Field Used for
pullRequest.id Reply target, summary comment target
reviewThread.id Resolve thread
comment.id (in thread) Reaction, reply inReplyTo
comment.id (PR comment) Reaction, minimize

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results