From resolve-copilot-pr-feedback
Process and resolve GitHub Copilot automated PR review comments. Use when the user says "check copilot review", "handle copilot comments", "resolve copilot feedback", "address copilot suggestions", or mentions Copilot PR comments. Also use after PR creation when Copilot has left automated review comments.
How this skill is triggered — by the user, by Claude, or both
Slash command
/resolve-copilot-pr-feedback:resolve-copilot-pr-feedbackThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Process and resolve GitHub Copilot's automated PR review comments systematically.
Process and resolve GitHub Copilot's automated PR review comments systematically.
NEVER leave comments directly on GitHub PRs. This is strictly forbidden:
gh pr review --comment - FORBIDDENgh pr comment - FORBIDDEN (except the single required final workflow summary in step 7)This skill ONLY processes GitHub Copilot threads. Never interact with threads created by human reviewers.
Permitted operations:
fetch commandreply commandresolve commandreply-and-resolve commandSingle exception: Step 7 uses gh pr comment with --body-file to post one required final workflow summary after terminal workflow state once PR context exists. This is the ONLY permitted use of gh pr comment in this skill. The final summary is blocking: if it cannot be posted, the workflow is incomplete.
All GraphQL operations use a dedicated script that handles pagination, variable binding, and Copilot author filtering automatically.
At the start of your session, locate the script by searching for **/resolve-copilot-pr-feedback/scripts/resolve-copilot-threads. Note the absolute path and use it with bash as the command prefix in all subsequent invocations. Do not use a shell variable, since shell state does not persist between commands.
In the examples below, resolve-copilot-threads is a placeholder for the script's quoted absolute path (e.g., "/absolute/path/to/resolve-copilot-pr-feedback/scripts/resolve-copilot-threads"). Always invoke via bash followed by the quoted path, e.g., bash "/absolute/path/to/scripts/resolve-copilot-threads" fetch .... This ensures the command token is bash, which matches stable allowlist patterns regardless of the plugin's installed path or version.
After fixing any Copilot feedback, you MUST:
git push)Addressing feedback without resolving the thread is INCOMPLETE WORK.
The thread resolution is NOT optional - it's the primary deliverable of this skill. Code changes alone are insufficient.
# Replace THREAD_ID with actual thread ID (e.g., PRRT_kwDONZ...)
bash resolve-copilot-threads resolve THREAD_ID
Outputs true on success. The reply-and-resolve command also outputs true on success.
You MUST call this for EVERY thread you address.
When Copilot feedback is categorized as INCORRECT (conflicts with project conventions/patterns), you MUST:
Failure to update Copilot instructions = INCOMPLETE WORK for Incorrect category feedback.
Copilot supports two types of instruction files in the .github/ directory:
copilot-instructions.md: General instructions for the whole repository*.instructions.md (path-specific): Targeted instructions with applyTo frontmatterPrefer path-specific instructions files when the incorrect feedback applies to a specific language or file pattern. Use copilot-instructions.md only for repo-wide conventions.
Copilot's PR review may not read the full instructions file. Long files risk having instructions truncated or ignored. To maximize effectiveness:
---
applyTo: "**/*.go"
---
- **Pattern X**: Intentional in this project, do not flag
- **Pattern Y**: Required for Z reason
Use the applyTo glob to target specific languages or paths. Use excludeAgent to limit which Copilot agent reads the file (e.g., excludeAgent: copilot-coding-agent to target only code review).
copilot-instructions.md)Reserve for repo-wide conventions that apply to all file types:
# GitHub Copilot Instructions
## PR Review
- **Pattern X**: Intentional, do not flag
- **Convention Y**: Required for Z reason
## Code Style
- General conventions here
ONLY process UNRESOLVED comments. NEVER touch, modify, or re-process already resolved comments. Skip them entirely.
bash resolve-copilot-threads fetch OWNER REPO PR_NUMBER
The script automatically handles pagination and filters for unresolved Copilot-authored threads.
Record the OWNER, REPO, and PR_NUMBER values used for the fetch. This establishes PR context for the required final workflow summary in step 7. If PR context or GitHub authentication cannot be established, report that the required final summary could not be posted and do not mark the workflow complete.
Output format (JSON array):
[
{
"id": "PRRT_kwDONZ...",
"path": "src/foo.ts",
"location": "src/foo.ts:42",
"isOutdated": false,
"comments": [{ "author": "copilot", "body": "[nitpick] Consider..." }]
}
]
location: Uses the first non-null of line, originalLine, startLine, originalStartLine. If all line fields are null, reports path:(no-line).copilot-pull-request-reviewer, copilot, github-copilot[bot], and github-actions[bot] (with severity tag verification for the latter).An empty array [] means no unresolved Copilot threads remain.
Treat [] as "no currently unresolved Copilot threads," not proof that no work happened in a previous attempt. Before using the no-op summary form, check whether this invocation is recovering from a prior failed summary-post step. If a previous run resolved threads or made code changes but failed to post the required final summary, reuse the preserved summary body from that run or reconstruct it from the prior local output, resolved review threads, branch commits, and branch diff. Do not downgrade that recovery summary to the no-op form just because a later fetch returns [].
For each unresolved Copilot comment:
| Category | Indicator | Action |
|---|---|---|
| Nitpick | Contains [nitpick] prefix | Auto-resolve immediately |
| Outdated | Refers to code that no longer exists | Reply with explanation, resolve |
| Incorrect | Misunderstands project conventions | Reply with explanation, resolve, update Copilot instructions |
| Valid | Current, actionable concern | Fix directly, push, and resolve thread |
| Deferred | Valid but out of scope for this PR | Track in PROJECT.md, reply, resolve |
bash resolve-copilot-threads resolve THREAD_ID
[nitpick] prefix)CRITICAL: Reply directly to the Copilot review thread, NOT to the PR.
CRITICAL: Always use --body-file to pass reply bodies. Write the response to a temp file first using the Write tool, then reference it with --body-file. This keeps the Bash command short and avoids permission prompts from long inline strings.
# Step 1: Generate a unique tmpfile path:
mktemp /tmp/copilot-reply-XXXXXX
# Returns a unique path, e.g.: /tmp/copilot-reply-r7s8t9
# Step 2: Write the response body to TMPFILE using the Write tool (not shown here as bash)
# Step 3: Pass TMPFILE to the script:
bash resolve-copilot-threads reply THREAD_ID --body-file TMPFILE
# Or reply and resolve in one step:
bash resolve-copilot-threads reply-and-resolve THREAD_ID --body-file TMPFILE
# Step 4: Clean up — issue this as a SEPARATE Bash tool call, not chained onto step 3:
rm -f TMPFILE
Replace TMPFILE with the actual path returned by mktemp. The cleanup must be a separate Bash tool call: each tool invocation runs unconditionally, so the tmpfile is removed whether step 3 succeeded or failed, and the harness preserves step 3's exit code without any shell wrapping. Never combine the two with ; status=$?; rm -f TMPFILE; exit $status — in zsh (the macOS default shell), status is a read-only built-in alias for $?, so the assignment fails with read-only variable: status. See plugins/use-git/skills/use-git/references/tmpfile-pattern.md for the full rationale.
NEVER pass the reply body inline (e.g., via echo "..." | or heredocs). Always use the Write tool + --body-file pattern.
FORBIDDEN COMMANDS - NEVER USE:
gh pr review <PR_NUMBER> --comment - adds PR-level comments, not thread repliesgh pr comment - adds PR-level commentsbash resolve-copilot-threads resolve THREAD_ID.github/css.instructions.md with applyTo: "**/*.css") when the feedback targets a specific language or file patterncopilot-instructions.md only for repo-wide conventions- Do not suggest removing .sr-only classes - required accessibility utilitiesWhen feedback is valid but out of scope for the current PR:
CRITICAL: Never defer feedback without tracking it. "Acknowledged for follow-up" without creating a trackable task is INCOMPLETE WORK.
After all code changes are made (from Valid or Incorrect categories), run the lint-and-fix skill to catch lint errors before pushing.
This step prevents CI failures from lint issues introduced while resolving feedback.
Check for changes: If no files were modified during steps 2-4 (only nitpicks auto-resolved or threads replied to), skip this step. Run git status --porcelain to verify: empty output means a clean working tree and you may skip; any output means files were changed and you should continue.
Invoke the lint-and-fix skill using the Skill tool with --no-push:
lint-and-fix --no-push
Parent continuation:
- Caller: resolve-copilot-pr-feedback
- Resume target: Step 6, push changes, re-fetch Copilot threads, then Step 7 summary comment.
- On lint success: Continue immediately to Step 6 without asking the user for confirmation.
- On lint failure or skipped required lint work: Record a workflow failure, skip Step 6 push and verification, then continue directly to the required terminal summary path in Step 7 because PR context exists.
This runs all detected project linters and formatters, fixes issues, and commits the fixes without pushing.
If lint-and-fix reports Lint status: success or Lint status: no-tools, proceed to step 6. Any fix commits created by lint-and-fix will be included in the push.
If lint-and-fix reports unresolved lint issues, skipped required lint work, missing required tools, or tool execution failures, record a workflow-level failure. Do not claim lint success, do not push potentially non-compliant changes, skip step 6, and post the required partial or failed summary in step 7 because PR context exists.
Do not run this step if step 5 recorded a lint failure or skipped required lint work. In that case, go directly to step 7 and report the lint failure in the final summary.
Push any changes: git push
Re-fetch to confirm all Copilot threads resolved:
bash resolve-copilot-threads fetch OWNER REPO PR_NUMBER
Expected output: [] (empty array)
Determine terminal workflow status and counts:
[]Track thread metrics separately from workflow-level failures. Thread metrics cover fetched, resolved, pending, failed, deferred, and code-change threads. Workflow-level failures cover non-thread steps such as instruction updates, follow-up tracking, lint runs, pushes, and verification checks.
Proceed to step 7 before claiming completion
Required: Once PR context exists, always post exactly one final PR summary comment after terminal workflow state. Do this for every outcome: no unresolved comments, fully resolved comments, only non-code-change resolutions, code-change resolutions, partial processing, failures, and pending items.
Post a summary comment to the PR so reviewers can see the workflow outcome at a glance. Do not post interim PR comments.
Comment format:
## Copilot Feedback Summary
Status: Completed
Head SHA: `abc1234`
| File | Category | Outcome | Action |
| --------------- | --------- | -------- | ------------------------------------------------- |
| `src/foo.ts:42` | Valid | Resolved | Fixed null check |
| `lib/util.js:8` | Incorrect | Resolved | Updated error handling; added Copilot instruction |
| `src/ui.tsx:20` | Deferred | Resolved | Tracked follow-up work |
| `docs/api.md:5` | Nitpick | Resolved | Auto-resolved |
Counts: 4 fetched, 3 resolved, 1 deferred, 2 code-change threads.
Completed, No unresolved Copilot feedback, Partial, or FailedCounts: line is one short sentence at the end of the comment. Include only non-zero counts from this set: fetched, resolved, pending, failed, deferred, code-change threads, workflow failures. Omit zero-valued metrics; do not render an empty table or "0" entries. If every count is zero, omit the Counts: line entirely.1 fetched, 2 fetched; 1 code-change thread, 2 code-change threads; 1 workflow failure, 2 workflow failures).If no unresolved Copilot comments were found, use this no-op form:
## Copilot Feedback Summary
Status: No unresolved Copilot feedback
Head SHA: `abc1234`
No unresolved Copilot comments were found.
If processing was partial or failed, include failure details, the remaining required action, and the trailing counts line:
## Copilot Feedback Summary
Status: Partial
Head SHA: `abc1234`
| File | Category | Outcome | Action |
| --------------- | -------- | -------- | ----------------------------- |
| `src/foo.ts:42` | Valid | Resolved | Fixed null check |
| `src/bar.ts:7` | Outdated | Failed | Reply failed |
| `lib/baz.ts:9` | Nitpick | Pending | Resolution still required |
### Failure Details
| Scope | Item | Outcome | Remaining action |
| -------- | ---------- | ------- | ------------------- |
| Workflow | `git push` | Failed | Push branch changes |
### Remaining Required Action
- Resolve the failed reply for `src/bar.ts:7`
- Resolve the pending nitpick at `lib/baz.ts:9`
- Push branch changes
Counts: 3 fetched, 2 resolved, 1 pending, 1 failed, 1 code-change thread, 1 workflow failure.
No-op summary idempotency: Before posting a No unresolved Copilot feedback summary, inspect existing top-level PR comments for a ## Copilot Feedback Summary comment with the same head SHA and no-op status. If one already exists and this invocation did not recover a failed summary-post attempt, do not add another no-op comment. Report the existing summary comment URL locally and treat that existing same-head no-op summary as satisfying the final summary requirement for this no-op run. This idempotency exception applies only to empty-fetch no-op runs; if this invocation processed threads, made code changes, or is recovering a failed summary-post attempt, post the required outcome summary.
Mechanics:
# Step 1: Generate a unique tmpfile path:
mktemp /tmp/copilot-summary-XXXXXX
# Step 2: Write comment body to TMPFILE using the Write tool (not shown here as bash)
# Step 3: Post the comment:
gh pr comment PR_NUMBER --repo OWNER/REPO --body-file TMPFILE
# Step 4: Clean up — issue this as a SEPARATE Bash tool call, not chained onto step 3:
rm -f TMPFILE
Replace OWNER, REPO, PR_NUMBER, and TMPFILE with actual values recorded during fetch. Always pass --repo OWNER/REPO so the final summary targets the intended PR even if the current checkout or working directory changes. The cleanup must be a separate Bash tool call (see Outdated/Incorrect Copilot Comments above for the rationale): chaining with ; status=$?; rm -f TMPFILE; exit $status breaks under zsh because status is a read-only built-in alias for $?.
If the comment fails, log the error and do not claim completion. Thread resolution, code changes, and the required final PR summary are all workflow deliverables.
When the final summary comment fails, preserve the exact intended summary Markdown in the local final output. A later retry must use that preserved body, or reconstruct the same outcome from available PR and git evidence, before falling back to any no-op summary.
First, generate a unique tmpfile path with mktemp /tmp/copilot-reply-XXXXXX. Write these to the returned path using the Write tool, then pass via --body-file. Clean up the tmpfile (rm -f TMPFILE) after each reply operation as a separate Bash tool call, not chained onto the reply command.
For outdated comments:
This comment refers to code that has been refactored in commit [hash]. The issue is no longer applicable.
For incorrect/convention conflicts:
This suggestion conflicts with our {convention name} convention. {Brief explanation of why}. See {reference file} for project guidelines.
Task is INCOMPLETE until ALL of these are done:
*.instructions.md preferred, or copilot-instructions.md for repo-wide conventions)lint-and-fix skill, if any files were changed while addressing feedback)[] for all processed threadsIf PR context or GitHub authentication is unavailable, or if gh pr comment fails, the workflow is incomplete. Report the failure locally and include the remaining action needed to post the required summary.
You MUST output this table after processing all threads:
| Thread ID | File:Line | Category | Action Taken | Status |
|-----------|-----------|----------|--------------|--------|
| PRRT_xxx | src/foo.ts:42 | Nitpick | Auto-resolved | Resolved |
| PRRT_yyy | src/bar.ts:15 | Valid | Fixed null check | Resolved |
| PRRT_zzz | lib/util.js:8 | Outdated | Code refactored | Resolved |
| PRRT_aaa | src/ui.tsx:20 | Deferred | Tracked in PROJECT.md | Resolved |
Column definitions:
Common failure mode: Fixing code but forgetting to resolve the threads. This leaves the PR with unresolved conversations even though the issues are fixed. ALWAYS run the resolution command after pushing code.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub cboone/agent-harness-plugins --plugin resolve-copilot-pr-feedback