Skip to content

Instantly share code, notes, and snippets.

@mxschmitt
Last active April 4, 2026 01:16
Show Gist options
  • Select an option

  • Save mxschmitt/4a0935e25019f2ab70d60042fd789da8 to your computer and use it in GitHub Desktop.

Select an option

Save mxschmitt/4a0935e25019f2ab70d60042fd789da8 to your computer and use it in GitHub Desktop.
Claude Code skill that triages GitHub Copilot PR reviews for you — fetches all comments, evaluates each like a senior engineer, lets you pick which to apply, then commits, resolves threads, and minimizes noise. One command, clean PR. Place it in ~/.claude/skills/copilot-review/SKILL.md and run /copilot-review on any open PR.
name copilot-review
description Review GitHub Copilot PR comments, evaluate and apply valid ones, resolve all threads
argument-hint [PR-number-or-url]
disable-model-invocation true
allowed-tools Bash(gh *), Read, Edit, Write, Grep, Glob, Agent

Review Copilot PR Comments

Fetch all GitHub Copilot review comments on a PR, evaluate each one, apply the valid suggestions, and resolve all Copilot threads.

Step 1 — Resolve the PR

If $ARGUMENTS is a full URL, extract the owner/repo and PR number. If $ARGUMENTS is just a number, use the current repo. If $ARGUMENTS is empty, detect the current branch's open PR:

gh pr view --json number,url,headRefName,baseRefName,title

Print the PR title, number, and branch. Confirm you are on the correct branch (check out if needed).

Extract owner and repo:

OWNER=$(gh repo view --json owner -q '.owner.login')
REPO=$(gh repo view --json name -q '.name')

Step 2 — Fetch review threads via GraphQL

Use the GraphQL API to get all review threads with their thread IDs (needed for resolution):

gh api graphql -F owner="$OWNER" -F repo="$REPO" -F prNumber=$PR_NUMBER -f query='
query($owner: String!, $repo: String!, $prNumber: Int!) {
  repository(owner: $owner, name: $repo) {
    pullRequest(number: $prNumber) {
      reviewThreads(first: 100) {
        edges {
          node {
            id
            isResolved
            isOutdated
            path
            line
            startLine
            originalLine
            originalStartLine
            diffSide
            comments(first: 50) {
              edges {
                node {
                  id
                  body
                  author { login }
                  createdAt
                }
              }
            }
          }
        }
      }
    }
  }
}'

Filter for threads where the first comment author login contains "copilot" (case-insensitive). Known logins: Copilot, copilot-pull-request-reviewer. Discard threads that are already resolved (isResolved: true).

Collect all Copilot thread IDs — you will need them ALL in Step 7.

Also fetch REST comment IDs (needed for replies in Step 7 — the GraphQL node IDs do NOT work with the REST reply endpoint):

gh api repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments \
  --jq '.[] | select(.user.login | test("copilot"; "i")) | {rest_id: .id, node_id: .node_id, path, line}'

Build a mapping of GraphQL node ID → REST numeric ID. You will need the REST IDs to post replies.

Step 3 — Evaluate each comment

For each unresolved Copilot thread:

  1. Read the referenced file around the indicated lines to understand context

  2. Read the Copilot comment body carefully

  3. Assess the suggestion:

    • Valid — real bug fix, meaningful improvement, correct style/security/performance concern
    • Reject — false positive, doesn't apply in context, overly pedantic, would break things, or contradicts project conventions

Be pragmatic. Apply the same judgment a senior engineer would: fix real issues, skip noise.

Step 4 — Present summary

Show the user a numbered table:

#  | File:Line          | Summary of suggestion              | Verdict (Valid/Reject) | Reasoning
1  | src/foo.py:42      | Add null check for edge case       | Valid                  | Param can be None from caller
2  | src/bar.py:10      | Use const instead of let           | Reject                 | Variable is reassigned on L15
3  | src/baz.py:99      | Add error handling for API call    | Valid                  | Unhandled exception risk

Ask the user (via AskUserQuestion) which comments to apply:

  • All valid (recommended) — apply all items marked Valid
  • Let me pick — user selects specific numbers
  • Skip all — don't apply any changes, just resolve threads

Step 5 — Apply fixes

For each accepted comment:

  1. Read the file around the referenced lines for full context
  2. Make the minimal, focused fix that addresses the suggestion
  3. Do NOT over-engineer or make changes beyond what the comment asks for

Step 6 — Verify and commit

If any fixes were applied:

  1. Run fast validation if applicable (tests for modified files, linter/formatter)
  2. Stage only modified files
  3. Commit:
Address Copilot review suggestions

- <one-line summary per fix applied>
  1. Push to the PR's head branch

Step 7 — Resolve ALL Copilot threads and reply

For each Copilot thread that was applied, post a reply using the numeric REST comment ID (from the mapping built in Step 2), then resolve.

IMPORTANT: The REST reply endpoint requires numeric IDs (e.g. 2982458496), NOT GraphQL node IDs (e.g. PRRC_kwDOROHpZc6xxLQe). Using node IDs will return 404.

# Use the numeric REST comment ID from the Step 2 mapping
gh api repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments/{REST_COMMENT_ID}/replies \
  -f body="Applied — fixed in <short-sha>"

Then resolve every Copilot thread (both applied and rejected) using the GraphQL mutation.

IMPORTANT: Do NOT use -F threadId="$tid" — GraphQL will try to parse $tid as a GraphQL variable and fail. Instead, inline the thread ID directly in the query string:

gh api graphql -f query="mutation { resolveReviewThread(input: {threadId: \"THREAD_NODE_ID\"}) { thread { isResolved } } }"

Loop through ALL collected Copilot thread IDs from Step 2 and resolve each one. This clears all Copilot review noise from the PR.

Step 8 — Minimize the main Copilot review comment

Copilot posts a top-level review summary comment on the PR (not an inline thread). Minimize it to reduce noise.

Fetch PR comments to find the Copilot summary comment (it's an issue comment, not a review comment):

gh api repos/$OWNER/$REPO/issues/$PR_NUMBER/comments \
  --jq '.[] | select(.user.login | test("copilot"; "i")) | {id: .node_id, login: .user.login}'

For each Copilot comment found, minimize it using GraphQL:

gh api graphql -f query="mutation { minimizeComment(input: {subjectId: \"COMMENT_NODE_ID\", classifier: OUTDATED}) { minimizedComment { isMinimized } } }"

Also minimize review-level comments (the review body itself, not inline threads):

gh api repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews \
  --jq '.[] | select(.user.login | test("copilot"; "i")) | {id: .node_id, state: .state}'

For each Copilot review found, minimize it using the same GraphQL mutation:

gh api graphql -f query="mutation { minimizeComment(input: {subjectId: \"REVIEW_NODE_ID\", classifier: OUTDATED}) { minimizedComment { isMinimized } } }"

Print a final summary: how many threads resolved, how many fixes applied, how many comments minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment