utilities
Manage Pr Comments
Review open GitHub PR comments, propose accept/reject/defer decisions, implement accepted changes, post replies, and resolve threads with resilient, project-agnostic execution.
Manage PR Comments
Purpose
Use this skill to run an end-to-end PR comment handling workflow:
- Discover open PR feedback
- Classify and prioritize actionable comments
- Propose decisions (
accept,reject,defer,needs-split) - Get user confirmation before write actions
- Implement accepted code changes
- Reply to comments with evidence
- Resolve review threads when appropriate
This skill is designed to be universal across company repositories and must not rely on project-specific build/test commands.
Non-Goals
- Do not commit, push, merge, or force-push.
- Do not assume one language/framework/toolchain.
- Do not auto-accept low-confidence or ambiguous requests.
Run Modes
analyze-only: discover + classify + summarize, no writes.propose: include decision proposals and draft replies, no writes.execute: perform approved changes/replies/resolutions.
Default mode: propose.
Inputs
Required
- PR target:
- Default: active/current PR context
- Optional override:
{owner, repo, prNumber}
- Explicit user confirmation for any write operation in
executemode
Optional
- Decision map (pre-approved dispositions per comment)
- Verification strictness (
minimal,standard,strict) - Max retries, timeout budget
Outputs
- Comment inventory (open/actionable/skipped)
- Decision table (proposed + confirmed)
- Execution report (implemented, replied, resolved, deferred, failed)
- Verification summary (detected checks run + results)
- Handoff note that developer handles commit/push/merge
Capability & Permission Preflight (Mandatory)
Before discovery, detect and record:
- API/tool capabilities (fetch comments, reply, resolve thread)
- Auth scopes and write permissions
- PR topology constraints:
- same-repo vs fork
- branch protection constraints
- whether source branch is writable
- Integration path selection:
- Prefer native PR management tools when available
- Fall back to GitHub CLI/API only for unsupported operations
- Record which operation uses which path
If write capability is missing, downgrade to propose and return actionable instructions.
GitHub Integration (gh CLI + GraphQL)
Use gh as the command surface and prefer GraphQL for thread-centric operations.
Command Discipline
- Execute one command at a time.
- Avoid shell chaining (
&&,;) to keep failures isolated. - Log every mutating operation with: timestamp, operation name, target id, result.
Non-Interactive Shell Hardening (Pager Safety)
Before running any gh command, force non-interactive output in the shell session:
export GH_PAGER=cat
export PAGER=cat
export LESS=FRX
Additional safeguards:
- Prefer JSON mode (
--json/gh api) for machine-readable output. - For long API responses, pipe through
jqor write to a temp file instead of opening a pager. - If a command still enters alternate buffer, stop and rerun with explicit env prefix:
GH_PAGER=cat PAGER=cat gh <command>
- Treat pager entry as a recoverable integration error and record it in the run report.
Auth and Access Preflight
Run these checks before any read/write workflow:
gh auth status
gh repo view OWNER/REPO
gh pr view PR_NUMBER --repo OWNER/REPO --json number,state,isDraft,headRefName,headRepositoryOwner,maintainerCanModify
If any command fails due to permissions, downgrade to propose mode and provide a handoff plan.
Data Retrieval (GraphQL Preferred)
Schema-Safe Query Strategy (Mandatory)
Do not assume GraphQL fields exist across all GitHub environments/versions.
- Start with a conservative base query (only widely available fields).
- If additional fields are needed, add them incrementally in small query edits.
- On
undefinedFielderrors, remove unsupported fields and retry immediately. - Record unsupported fields in the run report and continue with degraded metadata.
Known variable fields that may be unavailable and must be optional in the workflow:
PullRequestReviewThread.updatedAtPullRequestReviewComment.diffSide
If those fields are absent, use fallback fields already in the base model (comments.nodes.updatedAt, position, originalPosition, line, originalLine).
Optional Schema Probe
When a run repeatedly fails due to schema mismatch, probe schema support before building full queries:
gh api graphql -f query='query { __type(name:"PullRequestReviewThread") { fields { name } } __type(name:"PullRequestReviewComment") { fields { name } } }'
Then construct the query using only available fields.
Fetch PR metadata + review threads + thread comments in one query where possible.
gh api graphql -f query='\
query($owner:String!, $repo:String!, $number:Int!, $threadsCursor:String) {\
repository(owner:$owner, name:$repo) {\
pullRequest(number:$number) {\
id\
number\
url\
state\
isDraft\
headRefOid\
reviewThreads(first: 100, after: $threadsCursor) {\
pageInfo { hasNextPage endCursor }\
nodes {\
id\
isResolved\
isOutdated\
updatedAt\
comments(first: 100) {\
nodes {\
id\
databaseId\
body\
createdAt\
updatedAt\
path\
line\
originalLine\
diffSide\
author { login }\
url\
}\
}\
}\
}\
comments(first: 100) {\
nodes {\
id\
databaseId\
body\
createdAt\
updatedAt\
author { login }\
url\
}\
}\
}\
}\
}' -F owner='OWNER' -F repo='REPO' -F number=PR_NUMBER
Notes:
- Paginate
reviewThreadsandcommentsuntilhasNextPage=false. - Keep both GraphQL node ids (
id) and REST ids (databaseId) for fallback operations. - Prefer this base field set for maximum portability:
id,isResolved,isOutdated,isCollapsed,body,createdAt,updatedAt,path,line,originalLine,position,originalPosition.
Error-Driven Query Downgrade
If GraphQL responds with field errors (for example, undefinedField):
- Parse the error and extract
typeName.fieldName. - Remove only the failing fields from the query template.
- Retry with the reduced query.
- If still failing after two downgrades, switch to REST fallbacks for discovery and replies.
Example fallback trigger patterns:
Field '\''<name>'\'' doesn't exist on type '\''<type>'\''- GraphQL validation errors for selected comment/thread fields
REST Fallbacks via gh api
Use REST endpoints when GraphQL operation is unavailable or fails:
- List review comments:
GET /repos/{owner}/{repo}/pulls/{pull_number}/comments - Reply to review comment (portable primary):
POST /repos/{owner}/{repo}/pulls/{pull_number}/commentswithin_reply_to=<comment_id> - Add PR conversation comment:
POST /repos/{owner}/{repo}/issues/{issue_number}/comments
Optional variant (may be unavailable depending on environment/API behavior):
POST /repos/{owner}/{repo}/pulls/comments/{comment_id}/replies
Example reply to review comment:
gh api repos/OWNER/REPO/pulls/PR_NUMBER/comments -f body='REPLY_TEXT' -F in_reply_to=COMMENT_ID
Example PR conversation response:
gh api repos/OWNER/REPO/issues/PR_NUMBER/comments -f body='REPLY_TEXT'
Thread Resolution (GraphQL)
Resolve review thread:
gh api graphql -f query='\
mutation($threadId:ID!) {\
resolveReviewThread(input:{threadId:$threadId}) {\
thread { id isResolved }\
}\
}' -F threadId='THREAD_NODE_ID'
Unresolve (for compensation/recovery):
gh api graphql -f query='\
mutation($threadId:ID!) {\
unresolveReviewThread(input:{threadId:$threadId}) {\
thread { id isResolved }\
}\
}' -F threadId='THREAD_NODE_ID'
Posting Replies (Decision-Aware)
accept: include concrete change summary + verification evidence.reject: include rationale + alternative when possible.defer: include explicit blocker and requested follow-up.
If thread reply mutation path is unavailable, reply to the latest review comment via REST fallback using databaseId and in_reply_to.
Concurrency Guards Before Mutations
Immediately before posting reply or resolving:
- Re-fetch the specific thread/comment by id.
- Compare
updatedAtwith manifest snapshot. - If drift detected, transition item to
stale-retriage.
Suggested Operation Order Per Accepted Review Item
- Apply code changes locally
- Run discovered verification checks
- Post reply (
gh apiGraphQL or REST fallback) - Resolve thread (GraphQL)
- Record state transition
For PR conversation comments, step 4 is not applicable.
Rate Limits and Retries
- On HTTP 403 with rate-limit signals: exponential backoff + jitter.
- On HTTP 5xx: bounded retries.
- On HTTP 401/permission failures: stop mutations, downgrade to
propose.
Canonical Data Model
Normalize every feedback item into a single schema:
itemKey: stable unique key (source + id)sourceType:review-thread|pr-conversationcommentId/threadIdauthor,authorRole,isBotstate: open/closed/outdatedfilePath,line,side,commitSha(if present)body,createdAt,updatedAtclassification,confidenceproposedDecision,confirmedDecisionexecutionState(state machine below)
If source IDs are unstable/unavailable for an item, derive a fallback key from
{sourceType, filePath, line, author, createdAt, normalizedBodyHash}.
Lifecycle
Phase 0: Build Immutable Run Manifest
Capture a snapshot of PR/comment/thread/head SHA state and create a manifest hash. All actions in this run must reference this manifest.
Phase 1: Discover and Normalize
- Fetch review-thread comments + PR conversation comments
- Handle pagination
- Deduplicate repeats
- Exclude already closed/resolved items unless explicitly requested
- Mark outdated comments using source metadata
Phase 2: Classify and Triage
Classify each item as:
actionableinformationalduplicateblocked(missing context or permissions)
If confidence is below threshold, force defer and request user input.
Outdated review comments default to defer unless explicitly reconfirmed by the user.
Phase 3: Propose Decisions (No Writes)
For each actionable item, propose one of:
accept: implement change and resolve when completereject: reply with rationale, do not resolve by defaultdefer: reply with blocker/context neededneeds-split: feedback bundles multiple concerns; split into sub-items first
Phase 4: Confirmation Gate (Mandatory)
Require explicit user approval of decisions (per-item or batch) before any write action.
Phase 5: Two-Stage Execution (Per Item)
For each confirmed item, run:
Stage A: Prepare
- Re-check item freshness against current PR state
- Re-check head SHA and thread/comment open state
- Build implementation + reply + resolution intent
If drift is detected, move item to stale-retriage.
Stage B: Execute (Transactional Order)
- Apply code change (for accepted items)
- Run verification checks relevant to changed scope
- Post reply with concrete evidence
- Resolve thread only if source supports it and acceptance criteria are met
Use atomic per-item transitions. Do not continue silently past failed transitions.
For PR conversation comments (non-thread), do not emulate thread resolution; mark as handled via reply + report status.
Execution State Machine
Allowed states:
queuedpreparedimplementedverifiedrepliedresolvedreply_posted_resolve_pendingdeferredfailedstale-retriageskipped
Transition rules:
resolvedis allowed only afterrepliedand successful verification for accepted items- if verification fails after implementation, transition to
failedand post defer-style response - if reply succeeds and resolve fails, transition to
reply_posted_resolve_pending - if a newer reviewer follow-up appears in the same thread after prepare phase, transition to
stale-retriagebefore resolve
Compensation rules:
- implementation succeeded, verification failed: keep changes local, do not resolve, post deferred response
- reply posted, resolve failed: keep
reply_posted_resolve_pendingand include explicit retry instructions - resolve posted but later drift detected: mark
stale-retriageand warn that thread state may need manual review
Conflict, Dependency, and Concurrency Handling
- Detect overlapping file/hunk edits across accepted items
- Serialize conflicting items, parallelize independent items
- Revalidate item state before each write (optimistic concurrency check)
- If new comments appear mid-run, add them to
next-runqueue unless user opts in to refresh manifest - Re-check thread/comment ETag or updated timestamp immediately before write operations when available
Universal Verification Strategy
Never hardcode project-specific commands. Use discovery-based checks:
- Run smallest scoped checks first (changed-file lint/type/unit if detectable)
- Run repository-declared checks (from workspace config/scripts/CI metadata when available)
- If no checks are discoverable, mark
manual-verification-required
If checks are discoverable but execution environment cannot run them, mark verification-blocked with reason and required human action.
Verification level behavior:
minimal: syntax/static checks only where availablestandard: lint + relevant tests where availablestrict: broader project test/build checks where available
Reply Quality Contract
Every posted reply must include:
- Disposition (
accepted,rejected,deferred) - What was changed (or why it was not changed)
- Evidence (file/behavior/check result)
- Any remaining limitation or follow-up
Avoid vague replies like "fixed" without evidence.
Retry, Timeout, and Resumability
- Bounded retries with exponential backoff + jitter
- Per-item timeout budget
- Global circuit breaker for repeated platform failures
- Persist checkpoints after each item transition so reruns can resume safely
- Ensure idempotency: rerun with same manifest must not duplicate replies/resolutions
Security and Safety Guardrails
- Do not include secrets/tokens/internal credentials in replies or logs
- Treat bot comments as informational by default unless explicitly actionable
- Escalate security-sensitive requests for explicit human approval
- Never claim resolution when no verifiable action was completed
- Never post replies that imply policy approval/compliance signoff unless explicitly provided by humans
Recommended Execution Script
- Preflight capability and permission matrix
- Build immutable run manifest
- Discover + normalize comments
- Classify and propose decisions
- Get explicit user approval
- Execute per-item transactional flow
- Produce audit report + handoff
Final Report Format
Include:
- Run mode and manifest hash
- Totals by status (
accepted,rejected,deferred,failed,resolved,pending) - Per-item summary with current state and blockers
- Files touched and verification outcomes
- Items queued for next run (
stale-retriage, new comments) - Clear handoff: developer performs commit/push/merge
Examples
Example A: Mixed Decisions
- 8 open items discovered
- Proposed: 4 accept, 2 reject, 1 defer, 1 needs-split
- User confirms all except 1 reject (changed to defer)
- Execution result: 4 implemented, 5 replied, 3 resolved, 1 pending due to permission
Example B: Fork PR with No Write Access
- Preflight detects read-only constraints
- Skill auto-downgrades to
propose - Outputs patch plan + reply drafts + explicit maintainer handoff steps
Example C: Mid-Run Drift
- Manifest SHA no longer matches current head during item 3
- Item transitions to
stale-retriage - Remaining independent items continue
- Final report flags rerun needed for stale item