github-graphql
npx machina-cli add skill JacobPEvans/ai-assistant-instructions/github-graphql --openclawGitHub 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 graphqlcommands 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 mergedCONFLICTING- Has merge conflictsUNKNOWN- 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)
-
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 |
|---|---|---|
{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-threads [all]- Primary consumer for thread resolution/finalize-pr- Thread resolution during PR management/review-pr- Creating and reading review threads
Best Practices
- Always use
last: 100: Never usefirst: ##to avoid missing threads - No loops: Run individual commands, don't batch with loops
- Verify resolution: After resolving, query again to confirm
isResolved: true - Sign all commits: Use
git commit -Sfor all direct commits - Use worktrees: Prefer worktrees over /tmp folders for code changes
- Check permissions first: Run
gh auth statusbefore GraphQL operations - Use jq for parsing: Extract specific fields with
jqrather than parsing raw JSON
Source
git clone https://github.com/JacobPEvans/ai-assistant-instructions/blob/main/agentsmd/skills/github-graphql/SKILL.mdView on GitHub Overview
Standardizes how you query GitHub via GraphQL for PR threads, comments, and mutations. This skill provides single-line query templates, enforces last: 100 pagination, and includes mutation patterns to avoid duplicating queries.
How This Skill Works
Utilizes gh api graphql with --raw-field to send single-line GraphQL queries. It enforces last: 100 for complete results, avoids loops, and covers core patterns like fetching reviewThreads, resolving a thread, and checking mergeable status.
When to Use It
- To fetch all review threads for a PR to assess decisions, resolutions, and comments.
- To resolve a specific review thread via a GraphQL mutation using its threadId.
- To verify that all review threads are resolved before attempting a merge.
- To check a PR's mergeable status and related checks before merging.
- When updating threads individually without using for/while loops.
Quick Start
- Step 1: Identify the PR owner, repository, and number.
- Step 2: Run a single-line GraphQL query with gh api graphql --raw-field to fetch reviewThreads(last: 100).
- Step 3: If updating, perform per-thread mutations and ensure commits are signed for PR changes.
Best Practices
- Always use single-line GraphQL queries with gh api graphql --raw-field.
- Always use last: 100 to ensure you don't miss recent threads or comments.
- Avoid for loops or while loops; process threads one at a time with individual commands.
- When making PR changes, ensure all commits are signed.
- Reference the core patterns (Get Review Threads, Resolve Review Thread, Verify All Threads Resolved, Get PR Mergeable Status) to stay consistent.
Example Use Cases
- Fetch all review threads for a PR to inspect IDs, resolution status, and comments.
- Resolve a specific review thread by its threadId to mark it as addressed.
- Verify there are no unresolved threads remaining on a PR before merging.
- Check the PR's mergeable status and associated checks to decide next steps.
- Execute per-thread operations to avoid loops and ensure precise updates.