From github-workflows
Orchestrates resolution of GitHub PR review threads AND reads recent non-thread PR comments (top-level + review bodies) by grouping related feedback, processing each group sequentially inline with superpowers:receiving-code-review, and resolving threads via GraphQL. Use when you need to batch-process review feedback to unblock a PR merge.
npx claudepluginhub jacobpevans/claude-code-plugins --plugin github-workflowsThis skill is limited to using the following tools:
<!-- cspell:words PRRT oneline databaseId -->
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Orchestrates resolution of all unresolved PR review comments by grouping related threads, processing each group sequentially inline to implement fixes or provide explanations, then resolving threads via GitHub's GraphQL API.
/resolve-pr-threads # Current branch PR
/resolve-pr-threads 142 # Specific PR
/resolve-pr-threads all # All open PRs with unresolved threads (sequential)
gh api repos/{owner}/{repo}/pulls/{number}/comments/{databaseId}/replies (REST) or addPullRequestReviewThreadReply (GraphQL)resolveReviewThread (GraphQL)--raw-field queries with literal value substitution (see graphql-queries.md)gh auth status — then retrygh pr comment or the Issues comments API) as a fallback; top-level comments are fine for general PR feedback but cannot be used to resolve specific review threads and are blocked by git-guards for that purpose.addPullRequestReviewComment (creates new comments, not replies) and resolvePullRequestReviewThread (does not exist)Context inference: Infer owner/repo/PR from current git context, then substitute
these values for {owner}, {repo}, and {number} placeholders in all commands below:
owner=$(gh repo view --json owner --jq '.owner.login')
repo=$(gh repo view --json name --jq '.name')
number=$(gh pr view --json number --jq '.number')
Run 1a and 1b in parallel.
gh api graphql --raw-field 'query=query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {number}) { reviewThreads(last: 100) { nodes { id isResolved path line startLine comments(last: 100) { nodes { id databaseId body author { login } createdAt } } } } } } }'
Filter to isResolved == false. Extract: id (PRRT_* node ID), path, line, comments.nodes[].databaseId, comments.nodes[].body, comments.nodes[].author.login.
gh pr view {number} --json commits --jq '.commits[-1].committedDate'
Then run 1c and 1d in parallel.
gh api "repos/{owner}/{repo}/issues/{number}/comments?since={lastCommitDate}"
gh api "repos/{owner}/{repo}/pulls/{number}/reviews" --jq '[.[] | select(.submitted_at > "{lastCommitDate}" and (.body | length > 0)) | {id, body, author: .user.login, submitted_at}]'
First: Invoke superpowers:receiving-code-review via the Skill tool once.
Read and follow its full pattern. This applies to all thread and comment processing below.
Process each thread group sequentially (one group at a time, no sub-agents).
For each thread group:
gh api repos/{owner}/{repo}/pulls/{number}/comments/{databaseId}/replies -f body="your reply"
{databaseId} is the NUMERIC value from the fetch response, NOT the PRRT_ node ID.
Track results per thread:
PRRT_xxx: handled [commit:abc1234]PRRT_xxx: needs-human [reason]Process each comment group sequentially after all thread groups. Skip if no comments.
For each comment group:
gh api repos/{owner}/{repo}/issues/{number}/comments -f body="..."Do not use the Issues comments endpoint as a fallback for review-thread replies; threaded review comments must be handled only via the dedicated thread-resolution flow.
Track results per comment:
COMMENT({author}, {date}): actionable [commit:abc1234]COMMENT({author}, {date}): acknowledged [replied]COMMENT({author}, {date}): needs-human [reason]After all groups are processed, resolve each handled thread one at a time (not in parallel) to avoid cascade failures:
gh api graphql --raw-field 'query=mutation { resolveReviewThread(input: {threadId: "{threadId}"}) { thread { id isResolved } } }'
Skip needs-human threads; flag for manual attention.
gh api graphql --raw-field 'query=query { repository(owner: "{owner}", name: "{repo}") { pullRequest(number: {number}) { reviewThreads(last: 100) { nodes { isResolved } } } } }' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'
Must return 0. Then push: git push.
gh pr list --state open --json number,headRefNameThis skill is a single-pass resolver — it processes all threads and comments found at invocation time, then returns. If the caller needs to handle late-arriving reviews, it is responsible for re-invoking this skill.
PR #{number} - Review Feedback Summary
Threads: {groupCount} groups ({threadCount} total) | Handled: {n} | Needs human: {n}
Resolved via GraphQL: {n} | Verification: {0 unresolved}/{total}
Comments: {n} since last commit | Actionable: {n} | Acknowledged: {n} | Needs human: {n}
Status: COMPLETE | PARTIAL ({n} need attention)
Omit "Threads:" when zero threads; omit "Comments:" when zero comments.
| Error | Cause | Fix |
|---|---|---|
Could not resolve to a node | Invalid thread ID | Re-fetch threads, IDs may have changed |
Resource not accessible | Permission issue | Check gh auth status, need repo write access |
| Verification shows >0 | Thread not resolved | Re-run mutation for remaining threads |
| Empty reviewThreads | No reviews yet | Exit cleanly |
| Exactly 100 threads returned | Pagination cap hit | Resolve visible threads first, then re-run |
| REST reply fails | Invalid databaseId or permissions | Verify numeric databaseId (not node ID) and ensure token has required repo permissions (403 = permission issue) |
since filter returns all comments | Invalid date format | Verify ISO 8601 format |
| Reviews endpoint returns empty | No reviews submitted | Proceed with threads only |
\! in jq expression | Claude Code Bash escapes ! | Use (.x == y | not) or .x | length > 0 instead of != |