Task involves reading file contents directly from the API when curl is missing or disallowed.
Need to perform precise, authenticated curl-like interactions with GitHub.
Task requires interacting with GitHub resources not supported by native gh subcommands
(e.g., repository variables, environment secrets, discussions).
Task requires complex GraphQL queries or mutations.
Task to resolve outdated PR comments.
User specifically asks for gh api or gh api graphql usage.
When Not to Use
When a native gh command (like gh issue view or gh pr create) already provides the exact functionality and fields needed.
When performing heavy, sustained data scraping where a dedicated script using octokit/PyGithub handles rate limiting and pagination better.
For interacting with raw git mechanisms like pushing commits or resolving merges (use git instead).
Common Pitfalls
Blind Pagination: Using --paginate on endpoints with thousands of items without piping to a file or jq filter, crashing the terminal or hitting memory limits.
Incorrect Field Types: Using -f instead of -F for file uploads or boolean values, causing the API to interpret the input as a literal string.
Ignoring Caching/Delays: Expecting newly created GitHub Actions runs or comments to be instantly visible in the API without accounting for indexing delays.
Mindmap of Commands
mindmap
root((gh-api))
api
REST
GET
POST
PATCH
PUT
DELETE
GraphQL
query
mutation
Output
--json
--jq
--template
Parameters
-f (raw-field)
-F (field)
-H (header)
--input
API Parameter Handling
When using gh api (including gh api graphql), choose the correct flag for parameters:
CAUTION: -f DOES NOT expand @. Using -f body=@file posts the literal string "@file".
For GraphQL, query is usually passed with -f to avoid accidental expansion or type conversion
of the query string itself.
Large Bodies & Files:
Prefer -F body=@path/to/file.md for large content.
Process Substitution: Avoid -F body=@<(...) in gh api; it is brittle across shells. Write to a temporary
file first, then use -F body=@tempfile.
GraphQL Variables:
For gh api graphql, all fields other than query and operationName are automatically passed as GraphQL variables.
Example: gh api graphql -f query='mutation($title: String!) { ... }' -F title=@title.txt
Reading Files via API
If you need to fetch from a repository using the CLI's authentication,
use the contents endpoint. The response is base64 encoded.
Example to fetch a file from a repository using gh api + base64:
gh api /repos/<org>/<repo>/contents/<path/to/file.md>?ref=<SHA> --jq .content | base64 -d
Example with just gh api:
gh api -H "Accept: application/vnd.github.raw" /repos/<org>/<repo>/contents/<path/to/file.md>?ref=<SHA>
Notes:
Above are robust alternatives to curl -s https://raw.githubusercontent.com/<org>/<repo>/<SHA>/<path>.
It uses native GitHub CLI auth, avoiding 401s for internal repositories.
Especially useful when curl is not available or restricted.
Downloading Workflow Logs via API
When gh run view --log fails to retrieve logs (often returning empty strings for canceled matrix jobs or cached runs),
you can download the full artifact zip via the REST API, bypassing CLI streaming limits.
GitHub Actions Job Summaries (written to $GITHUB_STEP_SUMMARY) are NOT directly accessible via the REST API
check-runs or jobs endpoints. They are only visible in the GitHub web UI or as raw markdown via an
undocumented web endpoint.
Common Mistake: Attempting to read output.summary from the check run associated with a GitHub Actions job.
For standard Action jobs, this field is almost always null.
Proper Alternatives:
Check for separate Check Runs: Some tools (like agent-auditor) might create a separate check run
(distinct from the job itself) and populate its output.summary.
Inspect logs: Start with gh run view --job <job_id> --log, but be aware that gh run view --log
frequently fails for some runs or attempts. If that happens, use the ZIP log download approach documented
just above (/actions/runs/<run_id>/logs) and inspect the extracted logs instead.
Even if the script only writes to $GITHUB_STEP_SUMMARY, the raw summary text can often be scraped from the
step's initialization logs where evaluated environment variables (like $RESPONSE) or expanded echo
commands are echoed by the runner preamble.
Check PR Comments: Many actions post summaries as PR comments. Use gh pr view <number> --json comments.
Discussion Patterns (via GraphQL)
Since gh often lacks a native discussion subcommand, use gh api graphql.
Avoid process substitution for the body; use a temporary file.
Get repositoryId and categoryId:
gh api graphql -f query='query {
repository(owner: "OWNER", name: "REPO") {
id
discussionCategories(first: 10) {
nodes { id name }
}
}
}'
gh uses GH_TOKEN or GITHUB_TOKEN environment variables if set.
By default, it uses the token stored in ~/.config/gh/hosts.yml (from gh auth login).
Some API operations (e.g., fine-grained scopes, cross-org access) might require a Personal Access Token (PAT)
with specific permissions.
In GitHub Actions, secrets.GITHUB_TOKEN is available by default but may have restricted permissions
(e.g., no access to private repositories in other orgs).
Fetching PR Workflow Runs via API
Due to gh pr checks' limitation of only evaluating the current HEAD commit, it frequently
misses manually triggered (workflow_dispatch) or comment-triggered (issue_comment) runs.
The most robust way to list all workflow runs associated with a Pull Request is via the REST API.
You can query the /actions/runs endpoint filtering by both the PR branch name and the PR title
(since PR comment triggers map the PR title to display_title):
Use it when you need a visual overview of PR review threads categorized by status
(active, outdated, resolved) with metadata like author and file path.
List Unresolved PR Inline Review Comments (GraphQL):
Note: Using -f implicitly changes the underlying request to POST.
You must specify -X GET explicitly or encode parameters directly into the URL like ...?branch=<branch>&event=pull_request.