Back to skills
extension
Category: Development & EngineeringNo API key required

github-graphql

Use when querying GitHub via GraphQL. Provides patterns for PR threads, comments, and mutations.

personAuthor: jakexiaohubgithub

GitHub 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 --raw-field in Claude Code.

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., $OWNER) - must escape inner quotes with \"
  • Single-line refers to the GraphQL query itself (no newlines), not shell quoting style
  • Placeholders like {OWNER}, {REPO}, {NUMBER} are documentation notation - replace with actual values before running

2. Always Use last: 100 Not first: ##

NEVER use first: ## in GraphQL queries. Always use 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 gh api graphql commands against single thread IDs
  • 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 | | ----- | ----------- | | id | Thread ID for resolution (format: PRRT_xxx) | | isResolved | Boolean resolution status | | path | File path the comment is on | | line/startLine | Line numbers in the file | | comments.nodes[].body | Comment text | | comments.nodes[].databaseId | 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:

  • MERGEABLE - Can be merged
  • CONFLICTING - Has merge conflicts
  • UNKNOWN - Status still being calculated

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 (PRRT_xxx) | From reviewThreads.nodes[].id | | Reply to comment | Numeric ID | From REST API or databaseId | | React to comment | Numeric ID | From REST API or databaseId | | Get thread status | GraphQL node ID | From reviewThreads.nodes[].id |

Making Changes to PRs

When resolving review threads requires code changes:

Option 1: Use Worktree (Preferred)

  1. 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"
    
  2. Make changes normally

  3. Commit with signature: git commit -S -m "message"

  4. 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 | | ----------- | ----------- | ------- | | {OWNER} | Repository owner (replace with actual value) | JacobPEvans | | {REPO} | Repository name (replace with actual value) | ai-assistant-instructions | | {NUMBER} | PR number integer (replace with actual value) | 123 | | {THREAD_ID} | Thread ID from GraphQL query (replace with actual value) | PRRT_kwDOO1m-OM5gtgeQ | | {BRANCH} | Branch name (replace with actual value) | fix/my-feature |

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 gh auth status, ensure repo access | | "Invalid node ID" | Wrong ID format | Verify ID starts with correct prefix (PRRT_, etc.) | | Encoding/parsing issues | Multi-line query | Use single-line format with --raw-field | | "Could not resolve to a PullRequest" | Wrong PR number | Verify PR exists and number is correct |

Commands Using This Skill

  • /resolve-pr-review-thread [all] - Primary consumer for thread resolution
  • /manage-pr - Thread resolution during PR management
  • /review-pr - Creating and reading review threads
  • /pr-review-feedback - Reference documentation for GraphQL patterns

Best Practices

  1. Always use last: 100: Never use first: ## to avoid missing threads
  2. No loops: Run individual commands, don't batch with loops
  3. Verify resolution: After resolving, query again to confirm isResolved: true
  4. Sign all commits: Use git commit -S for all direct commits
  5. Use worktrees: Prefer worktrees over /tmp folders for code changes
  6. Check permissions first: Run gh auth status before GraphQL operations
  7. Use jq for parsing: Extract specific fields with jq rather than parsing raw JSON