Claude-skill-registry github-graphql
Use when querying GitHub via GraphQL. Provides patterns for PR threads, comments, and mutations.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/github-graphql" ~/.claude/skills/majiayu000-claude-skill-registry-github-graphql && rm -rf "$T"
skills/data/github-graphql/SKILL.mdGitHub GraphQL Patterns
<!-- markdownlint-disable-file MD013 -->Standardized GraphQL patterns for GitHub PR and review thread operations. All commands that interact with GitHub's GraphQL API should reference this skill instead of duplicating queries.
Critical Requirements
1. Single-Line Format Required
ALWAYS use single-line GraphQL queries with
in Claude Code.--raw-field
Multi-line GraphQL queries cause encoding issues. Use this pattern:
# CORRECT: Single-line with --raw-field gh api graphql --raw-field 'query=query { repository(owner: "{OWNER}", name: "{REPO}") { pullRequest(number: {NUMBER}) { reviewThreads(last: 100) { nodes { id isResolved } } } } }'
Shell Quoting Notes:
- Single quotes (as above) prevent shell variable expansion - use when query contains literal placeholders like
{OWNER} - Double quotes needed only for shell variable substitution (e.g.,
) - must escape inner quotes with$OWNER\" - Single-line refers to the GraphQL query itself (no newlines), not shell quoting style
- Placeholders like
,{OWNER}
,{REPO}
are documentation notation - replace with actual values before running{NUMBER}
2. Always Use last: 100
Not first: ##
last: 100first: ##NEVER use
in GraphQL queries. Always use first: ##
last: 100 to ensure you get ALL recent
items and don't miss threads/comments due to pagination cutoff.
3. No For Loops
NEVER use for loops or while loops - they require permission prompts and break automation. Instead:
- Run single
commands against single thread IDsgh api graphql - Process threads one at a time with individual approved commands
- If possible, include multiple thread IDs as separate parameters in a single call
4. Commits Must Be Signed
When making direct commits for PR changes, ALL commits MUST be signed.
Core Query Patterns
1. Get Review Threads
Purpose: Fetch all review threads for a PR with resolution status and comments.
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 } } } } } } }'
Key Fields:
| Field | Description |
|---|---|
| Thread ID for resolution (format: ) |
| Boolean resolution status |
| File path the comment is on |
/ | Line numbers in the file |
| Comment text |
| Numeric ID for REST API operations |
2. Resolve Review Thread
Purpose: Mark a review thread as resolved.
gh api graphql --raw-field 'query=mutation { resolveReviewThread(input: {threadId: "{THREAD_ID}"}) { thread { id isResolved } } }'
Requirements:
- Thread ID must be a valid GraphQL node ID starting with
PRRT_ - You must have write access to the repository
3. Verify All Threads Resolved
Purpose: Check if any unresolved threads remain on a PR.
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'
Success Criteria: Returns
0 (no unresolved threads).
4. Get PR Mergeable Status
Purpose: Check if a PR can be merged.
gh api graphql --raw-field 'query=query { repository(owner: "{OWNER}", name: "{REPO}") { pullRequest(number: {NUMBER}) { mergeable statusCheckRollup { state } reviewDecision } } }'
Mergeable Values:
- Can be mergedMERGEABLE
- Has merge conflictsCONFLICTING
- Status still being calculatedUNKNOWN
Thread Resolution Workflow
Step 1: Get Unresolved Thread IDs
Run the query to get all threads, then use jq to extract unresolved thread IDs:
gh api graphql --raw-field 'query=query { repository(owner: "{OWNER}", name: "{REPO}") { pullRequest(number: {NUMBER}) { reviewThreads(last: 100) { nodes { id isResolved } } } } }' | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id'
Step 2: Resolve Each Thread Individually
For each thread ID from Step 1, run the resolve mutation as a separate command:
gh api graphql --raw-field 'query=mutation { resolveReviewThread(input: {threadId: "PRRT_kwDOxxxxx"}) { thread { id isResolved } } }'
Important: Do NOT use loops. Run each resolve command individually.
Step 3: Verify Resolution
After resolving all threads, verify none remain unresolved:
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'
Node ID Handling
GitHub uses two ID systems. Understanding when to use each is critical.
GraphQL Node IDs (base64 encoded)
Used for GraphQL operations:
- Review thread:
PRRT_kwDOO1m-OM5gtgeQ - PR comment:
PRRC_kwDOO1m-OM5gtgeR - Pull request:
PR_kwDOO1m-OM4...
Get via GraphQL query
nodes[].id fields.
REST API Numeric IDs
Used for REST API operations:
- Get via:
gh api repos/{OWNER}/{REPO}/pulls/{NUMBER}/comments | jq '.[].id' - Or via GraphQL:
comments.nodes[].databaseId
ID Usage Table
| Operation | ID Type | How to Get |
|---|---|---|
| Resolve thread | GraphQL node ID () | From |
| Reply to comment | Numeric ID | From REST API or |
| React to comment | Numeric ID | From REST API or |
| Get thread status | GraphQL node ID | From |
Making Changes to PRs
When resolving review threads requires code changes:
Option 1: Use Worktree (Preferred)
-
Create or switch to the PR's worktree:
BRANCH="{BRANCH}" SANITIZED_BRANCH="$(printf '%s' "$BRANCH" | tr -c 'A-Za-z0-9._-' '_')" git worktree add "$HOME/git/{REPO}/$SANITIZED_BRANCH" "$BRANCH" cd "$HOME/git/{REPO}/$SANITIZED_BRANCH" -
Make changes normally
-
Commit with signature:
git commit -S -m "message" -
Push:
git push origin {BRANCH}
Option 2: Direct Signed Commit (Small Changes Only)
For small single-file fixes, you can commit directly if and only if commits are signed:
# Ensure GPG signing is configured git config --global commit.gpgsign true git config --global user.signingkey {YOUR_KEY_ID} # Make the change and commit with signature git commit -S -m "fix: address review feedback" git push origin {BRANCH}
Never:
- Create branches in /tmp folders
- Output temporary scripts
- Make unsigned commits
Placeholder Reference
NOTE: Placeholders below use
{CURLY_BRACES} notation for documentation clarity. These are NOT bash variables and will NOT be expanded by the shell. You must manually replace them with actual values before running commands.
| Placeholder | Description | Example |
|---|---|---|
| Repository owner (replace with actual value) | |
| Repository name (replace with actual value) | |
| PR number integer (replace with actual value) | |
| Thread ID from GraphQL query (replace with actual value) | |
| Branch name (replace with actual value) | |
Common Errors and Solutions
| Error | Cause | Solution |
|---|---|---|
| "Field 'reviewThreads' doesn't exist" | Wrong API version | Use GraphQL v4 (default) |
| "Resource not accessible by integration" | Missing permissions | Check , ensure repo access |
| "Invalid node ID" | Wrong ID format | Verify ID starts with correct prefix (, etc.) |
| Encoding/parsing issues | Multi-line query | Use single-line format with |
| "Could not resolve to a PullRequest" | Wrong PR number | Verify PR exists and number is correct |
Commands Using This Skill
- Primary consumer for thread resolution/resolve-pr-review-thread [all]
- Thread resolution during PR management/manage-pr
- Creating and reading review threads/review-pr
- Reference documentation for GraphQL patterns/pr-review-feedback
Best Practices
- Always use
: Never uselast: 100
to avoid missing threadsfirst: ## - No loops: Run individual commands, don't batch with loops
- Verify resolution: After resolving, query again to confirm
isResolved: true - Sign all commits: Use
for all direct commitsgit commit -S - Use worktrees: Prefer worktrees over /tmp folders for code changes
- Check permissions first: Run
before GraphQL operationsgh auth status - Use jq for parsing: Extract specific fields with
rather than parsing raw JSONjq