Skill: PR Review Workflow
This skill defines how to handle pull request workflows: creation, review comments, and CI status.
Activation context
This skill activates when:
- •Creating a PR (see section 8 for PowerShell quoting)
- •The agent has just pushed commits to a PR branch.
- •The developer asks about PR comments, review feedback, or CI status.
- •The developer mentions "check comments", "review feedback", "CI status", or "workflow status".
1. Post-push workflow
After every git push to a PR branch, do ALL of the following in order:
Step 1: Copilot review (automated)
Copilot review is triggered automatically by the copilot-review.yml GitHub Actions workflow
on PR open and ready_for_review. There is no reliable CLI command to request it manually.
See Section 8 for details.
Step 2: Fetch and present review comments
Always run BOTH of these commands:
- •Top-level PR comments:
gh pr view --json comments,reviews - •Inline code review comments:
gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments --paginate
The inline comments API call is where Copilot and human reviewers leave code-level feedback. Never skip it.
After fetching comments, summarize them (see section 3) and ask which to address.
For CI status, offer to check:
CI passed. Would you like me to check the workflow details?
Completion checklist for each comment (all boxes required):
- • Code fix implemented
- • Committed with descriptive message
- • Pushed to remote
- • Replied to comment with commit SHA
- • Thread resolved via GraphQL API immediately after replying
⚠️ CRITICAL: Reply + Resolve are INSEPARABLE. After replying to a comment, you MUST resolve the thread in the same operation. Never batch replies without also batching resolutions. The resolve loop must run immediately after the reply loop - not "later" or "at the end".
Do not consider a comment "handled" until ALL steps are complete. After fixing and pushing, return to sections 4 and 6 to reply and resolve.
2. Fetching PR comments
⚠️ CRITICAL: NEVER use built-in IDE tools for PR comments. Tools like
github-pull-request_activePullRequestor similar VS Code/Copilot integrations may return stale/cached data and miss recent review comments. This has caused missed feedback in production. ALWAYS usegh apiorgh api graphqldirectly.
CRITICAL: You MUST check BOTH top-level comments AND inline review comments. The
gh pr view --json comments,reviewscommand does NOT return inline code comments. Skipping inline comments means missing Copilot's code suggestions and human review feedback.
2.0 PREFERRED: GraphQL reviewThreads (comments + resolution status)
This is the most reliable method. It returns all review threads with their resolution status in one query:
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
comments(first: 5) {
nodes {
body
path
author { login }
}
}
}
}
}
}
}
' -f owner="<OWNER>" -f repo="<REPO>" -F pr=<PR>
Why this is preferred:
- •Returns both comments AND resolution status in one call
- •Never stale - queries GitHub directly
- •Includes the
threadIdneeded for resolution (theidfield) - •Shows which threads are already resolved vs still open
Filter for unresolved threads only:
gh api graphql -f query='...' | jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false))'
2.1 Identify PR context
Determine the PR number and repository from:
- •The current branch name and
gh pr viewoutput. - •Repository information from git remote.
Propose running the following commands (or use a shell tool if available and the developer agrees):
# Get current PR number gh pr view --json number -q '.number' # Get repo owner/name gh repo view --json owner,name -q '"\(.owner.login)/\(.name)"'
2.2 Fetch conversation comments
Propose running gh pr view for top-level conversation comments:
gh pr view <PR> --json comments -q '.comments[] | {author: .author.login, body: .body, createdAt: .createdAt}'
2.3 Fetch inline review comments (REST API alternative)
Note: The GraphQL method in section 2.0 is preferred because it includes resolution status. Use this REST API method only when you need the REST-style comment IDs for replies.
gh pr view --json comments and gh pr view --json reviews do NOT return inline code review comments. They only return PR-level conversation comments and review summaries. The REST API returns inline comments:
gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments
This returns an array of review comments with:
- •
path: File path the comment is on. - •
line/original_line: Line number. - •
body: Comment text. - •
user.login: Author. - •
id: Comment ID (needed for replies/resolution). - •
in_reply_to_id: If this is a reply to another comment.
Limitation: This does NOT show whether threads are resolved. Use GraphQL (section 2.0) to check resolution status.
2.4 Fetch review summaries
Propose fetching overall review status:
gh pr view <PR> --json reviews -q '.reviews[] | {author: .author.login, state: .state, body: .body}'
3. Assessing and summarizing comments
After fetching comments, provide a structured summary:
3.1 Categorize comments
Group comments into:
- •Actionable: Suggestions for code changes, bug fixes, or improvements.
- •Questions: Clarifications needed from the author.
- •Informational: FYI comments, praise, or general observations.
- •Blocking: Changes requested that must be addressed before merge.
3.2 Summary format
Present a summary like:
PR #123 Review Summary
Actionable (3):
- •file.py#L42: @reviewer suggests using
pathlibinstead ofos.path- •config.json#L15: @reviewer: Missing required field
timeout- •tests/test_api.py#L88: @reviewer: Add test for error case
Questions (1):
- •README.md#L20: @reviewer asks: Why was this section removed?
Informational (1):
- •General: @reviewer: "Nice refactoring of the database module!"
3.3 Critically assess automated suggestions
When comments are from copilot-pull-request-reviewer, github-actions, or other bots:
- •Do not blindly apply suggestions. Bots lack full codebase and domain context.
- •Verify correctness: Check if the suggestion applies to this project's conventions and APIs.
- •Watch for false positives:
- •API payload format suggestions (e.g., Jira field names, REST body structure) - the bot may not know the actual API.
- •Security warnings that don't apply to the deployment context.
- •Style suggestions that conflict with project conventions or tooling.
- •When uncertain: Present the suggestion to the developer with your assessment. Do not auto-apply.
- •When the suggestion is wrong: Point out why it's incorrect rather than silently skipping it.
Example assessment:
Bot suggestion: "Use
{"name": "username"}instead of{"assignee": "email"}"
3.4 Present before acting
Before making any changes based on review comments:
- •Present all comments to the developer with your assessment of each (agree, disagree, need clarification).
- •Wait for developer confirmation on which comments to address.
- •Do not proceed to commit/push until the developer explicitly confirms the plan.
This prevents silently skipping valid feedback or applying incorrect suggestions.
4. Responding to comments
4.1 When agreeing with a comment
- •Make the fix: Edit the file to address the feedback.
- •Stage and commit: Use a descriptive commit message referencing the feedback.
- •Push the changes.
- •Reply to the comment - propose running:
# Use -F (not -f) for the numeric in_reply_to parameter gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments \ -X POST -f body="Fixed in <COMMIT_SHA>. Thanks for catching this!" \ -F in_reply_to=<COMMENT_ID>
Important: Use
-Fforin_reply_tobecause it's a numeric parameter. Using-fcauses a type error.
- •Resolve the conversation (if the comment is on a review thread) - propose running:
WARNING: Replying does NOT resolve the thread. You MUST call the GraphQL mutation separately to resolve it.
gh api graphql -f query='
mutation {
resolveReviewThread(input: {threadId: "<thread_id>"}) {
thread { isResolved }
}
}
'
Note: The threadId is a GraphQL node ID, not the REST API comment_id. To obtain it, first fetch review threads:
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 comments(first: 1) { nodes { body } } }
}
}
}
}
' -f owner="<OWNER>" -f repo="<REPO>" -F pr=<PR>
Match the thread by its first comment body, then use the id field as threadId.
4.2 When disagreeing with a comment
- •Analyze the suggestion against the codebase context.
- •Reply with reasoning - propose running:
gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments \ -X POST -f body="I considered this, but <REASONING>. The current approach <JUSTIFICATION>." \ -F in_reply_to=<COMMENT_ID>
- •Resolve the conversation after explaining the disagreement (see thread resolution in 4.1).
4.3 Batch processing
When multiple comments need addressing:
- •Group related fixes into logical commits.
- •Push all changes at once.
- •Reply to all comments in a loop - collect comment IDs and iterate:
bash
# Use -F for numeric in_reply_to parameter for id in ID1 ID2 ID3; do gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments \ -X POST -f body="Fixed in <COMMIT_SHA>." -F in_reply_to=$id done - •Resolve all threads in a loop - fetch thread IDs, then iterate:
bash
for thread_id in THREAD1 THREAD2 THREAD3; do gh api graphql -f query="mutation { resolveReviewThread(input: {threadId: \"$thread_id\"}) { thread { isResolved } } }" done
REMINDER: Replying and resolving are separate operations. Never skip the resolve loop.
5. Checking CI/workflow status
5.1 Fetch workflow runs
Propose running the following commands (or use a shell tool if available and the developer agrees):
# List recent workflow runs for the current branch gh run list --branch <branch_name> --limit 5 # Get detailed status of a specific run gh run view <run_id> # Get failed jobs and their logs gh run view <run_id> --log-failed
5.2 Assess workflow failures
When a workflow fails:
- •Identify the failing job from the run output.
- •Fetch the logs for the failed step.
- •Analyze the error:
- •Is it a test failure? → Identify which test and why.
- •Is it a lint/format issue? → Run the linter locally and fix.
- •Is it an infrastructure issue? → Check if it's a flaky test or transient error.
- •Suggest or implement a fix.
5.3 Status summary format
Present CI status like:
CI Status for PR #123
Workflow Status Duration Details test.yml Pass 3m 42s lint.yml Fail 1m 15s ruff check failed security.yml Pass 2m 08s Failure Analysis:
lint.ymlfailed due to unused import insrc/api/routes.py:15. Would you like me to fix this?
6. Iterative workflow
After addressing comments and fixing CI issues:
- •Push the fixes.
- •Reply to each addressed comment explaining how it was fixed (see section 4.1).
- •Resolve the review threads for comments that were addressed.
- •Offer to re-check: "Changes pushed. Want me to check for new comments or CI status?"
- •Repeat until the PR is ready for merge.
Critical: Do not consider a comment "handled" just because you pushed a commit that addresses it. The review thread remains open until explicitly replied to and resolved.
The workflow is incomplete if you stop after pushing. Reviewers see unresolved threads as outstanding issues. Always complete the reply→resolve loop before moving on or reporting completion to the developer.
7. Command reference
| Task | Command |
|---|---|
| Get PR number | gh pr view --json number -q '.number' |
| Get PR comments (top-level only) | gh pr view <PR> --json comments |
| Get review threads + resolution (PREFERRED) | gh api graphql -f query='{ repository(...) { pullRequest(...) { reviewThreads(first:100) { nodes { id isResolved comments(first:5) { nodes { body path } } } } } } }' |
| Get inline review comments (REST, no resolution) | gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments --paginate |
| Get review status | gh pr view <PR> --json reviews |
| Reply to inline comment | gh api repos/<OWNER>/<REPO>/pulls/<PR>/comments -X POST -f body="..." -F in_reply_to=<ID> |
| Resolve thread | gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<ID>"}) { thread { isResolved } } }' |
| List workflow runs | gh run list --branch <branch> --limit 5 |
| View failed workflow logs | gh run view <run_id> --log-failed |
| Re-run failed workflow | gh run rerun <run_id> --failed |
8. Creating PRs
Copilot review automation
Copilot review is requested automatically via GitHub Actions (.github/workflows/copilot-review.yml).
There is no reliable CLI command to request Copilot review:
- •
gh pr create --reviewer copilot→ fails with "'copilot' not found", aborts PR creation - •
gh pr edit <PR> --add-reviewer copilot→ unreliable, sometimes works but not guaranteed
The workflow uses the gh-copilot-review extension
and triggers on opened, ready_for_review, and reopened events.
Requires a fine-grained PAT secret (
GH_TOKEN_COPILOT_REVIEW) withPull requests: Read and writepermission.
Multi-line bodies (PowerShell)
NEVER pass backtick-containing text via --body in PowerShell — backticks are parsed as escape characters causing Unicode parse errors.
Required approach — write to temp file:
# 1. Write body to temp file (use create_file tool) # 2. Create PR with --body-file gh pr create --title "feat: ..." --body-file tmp_pr_body.md # 3. Delete temp file Remove-Item tmp_pr_body.md
9. Multi-repo workflow
When working across multiple repositories with the same or similar files (e.g., shared skills, copilot-instructions):
- •Fetch comments from ALL repos first. Do not assume identical files receive identical feedback. Different reviewers or bots may flag different issues.
- •Aggregate and deduplicate comments. Group similar feedback across repos to avoid redundant work.
- •Apply fixes to the source-of-truth repo first. Make changes in one place, then sync to others.
- •Sync files before committing. Ensure all repos have identical content for shared files.
- •Commit and push to all repos. Use a loop to ensure consistency.
- •Reply to and resolve comments in ALL repos. Each repo's PR has its own review threads that must be addressed individually.
10. Skåne Trails project context
For this project (Skåne Trails Streamlit app on GCP free tier):
- •Streamlit multi-page app: Many PRs change UI behavior and page interactions (
app/_Home_.py,app/pages/). When reviewing, consider both code quality and user experience impacts. - •Firestore + Cloud Run on GCP free tier: All data persistence uses Firestore and the app runs on Cloud Run. PR changes must respect free-tier limits (reads/writes, requests, CPU/memory) and avoid introducing costly polling or chatty database patterns.
- •Infrastructure via Terraform only: Any change that affects GCP resources must be implemented in
infra/with Terraform. Do not suggest or approve manual console orgcloud-only changes. - •Security and CI workflows: CI runs Trivy scans, SBOM and license checks, and tests via GitHub Actions. When reviewing PRs, ensure new dependencies, workflows, or patterns align with these existing checks and keep the project zero-cost and public-repo safe.
- •Pre-commit hooks may auto-format files—always run
git diffafter committing to verify the actual changes. - •mdformat can alter markdown structure—be aware that deeply indented markdown after code blocks may be reformatted.