Problem
When using gh api with REST endpoints, the entire API response is downloaded and --jq filters it client-side. For many common operations, this transfers far more data than needed:
| Call |
Downloaded |
Used |
Waste |
gh api repos/cli/cli --jq '.default_branch' |
~15KB (entire repo object, 100+ fields) |
6 bytes |
~99.9% |
gh api repos/cli/cli/issues/1 --jq '.title' |
Full issue + all comments |
~20 bytes |
>95% |
Meanwhile, the high-level commands already solve this. When you run gh issue view 1 --json title,body, it generates a targeted GraphQL query via IssueGraphQL(fields) in api/query_builder.go. But this infrastructure is only accessible through commands like gh issue/pr/repo view — the raw gh api command that LLM agents and automation tools rely on has no way to leverage it.
Related: #13333 (batch mode for gh api)
Proposed Solution
Add a --select flag to gh api that translates recognized REST endpoint patterns into targeted GraphQL queries, fetching only the specified fields from the server.
Usage
# Server-side field selection — only ~100 bytes transferred
gh api repos/{owner}/{repo} --select name,defaultBranchRef
# Combine with --jq for minimal transfer + formatted output
gh api repos/{owner}/{repo} --select defaultBranchRef --jq '.defaultBranchRef.name'
# Works for issues
gh api repos/{owner}/{repo}/issues/42 --select title,state,labels
# Works for pull requests
gh api repos/{owner}/{repo}/pulls/7 --select title,isDraft,reviewDecision
How it works
- Recognizes the REST endpoint pattern (e.g.,
repos/{owner}/{repo})
- Validates fields against the known lists (
RepositoryFields, IssueFields, PullRequestFields)
- Builds a GraphQL query using the existing
RepositoryGraphQL(), IssueGraphQL(), or PullRequestGraphQL() functions from api/query_builder.go
- Sends the query to the GraphQL endpoint
- Unwraps the GraphQL response envelope so the output matches the REST structure
- Passes the result through
--jq / --template as normal
Supported patterns
| REST pattern |
GraphQL resource |
Builder function |
repos/{owner}/{repo} |
Repository |
RepositoryGraphQL() |
repos/{owner}/{repo}/issues/{n} |
Issue |
IssueGraphQL() |
repos/{owner}/{repo}/pulls/{n} |
PullRequest |
PullRequestGraphQL() |
Unsupported endpoints produce a clear error with the list of supported patterns.
Field validation
Fields are validated against the same lists used by gh repo/issue/pr view --json:
$ gh api repos/cli/cli --select nonexistent
Error: unknown Repository field: "nonexistent"
Available fields:
id
name
nameWithOwner
...
Architecture Fit
This feature reuses 100% of the existing query_builder.go infrastructure. No new GraphQL query building code is needed — it calls the same RepositoryGraphQL(), IssueGraphQL(), and PullRequestGraphQL() functions that power the high-level commands.
The implementation is ~160 lines of new code (plus tests) in a single new file select_fields.go, with minimal changes to api.go.
Prototype
Working implementation with 20 unit + integration tests: SebTardif/cli@feat/api-batch (second commit on the branch).
Files:
pkg/cmd/api/select_fields.go — Pattern matching, query building, response unwrapping
pkg/cmd/api/select_fields_test.go — 15 unit tests
pkg/cmd/api/api.go — Flag registration, validation, execution path
pkg/cmd/api/api_test.go — 5 integration tests
All existing tests pass. Lint clean.
Why this matters
LLM coding agents (GitHub Copilot, Cursor, etc.) increasingly use gh api as their primary GitHub interface. They make dozens of gh api calls per session. This feature would let them request only the fields they need, reducing:
- Network bandwidth — by 90-99% for typical calls
- GitHub server load — GraphQL naturally fetches less data
- Agent response latency — less data to parse
Problem
When using
gh apiwith REST endpoints, the entire API response is downloaded and--jqfilters it client-side. For many common operations, this transfers far more data than needed:gh api repos/cli/cli --jq '.default_branch'gh api repos/cli/cli/issues/1 --jq '.title'Meanwhile, the high-level commands already solve this. When you run
gh issue view 1 --json title,body, it generates a targeted GraphQL query viaIssueGraphQL(fields)inapi/query_builder.go. But this infrastructure is only accessible through commands likegh issue/pr/repo view— the rawgh apicommand that LLM agents and automation tools rely on has no way to leverage it.Related: #13333 (batch mode for
gh api)Proposed Solution
Add a
--selectflag togh apithat translates recognized REST endpoint patterns into targeted GraphQL queries, fetching only the specified fields from the server.Usage
How it works
repos/{owner}/{repo})RepositoryFields,IssueFields,PullRequestFields)RepositoryGraphQL(),IssueGraphQL(), orPullRequestGraphQL()functions fromapi/query_builder.go--jq/--templateas normalSupported patterns
repos/{owner}/{repo}RepositoryGraphQL()repos/{owner}/{repo}/issues/{n}IssueGraphQL()repos/{owner}/{repo}/pulls/{n}PullRequestGraphQL()Unsupported endpoints produce a clear error with the list of supported patterns.
Field validation
Fields are validated against the same lists used by
gh repo/issue/pr view --json:Architecture Fit
This feature reuses 100% of the existing
query_builder.goinfrastructure. No new GraphQL query building code is needed — it calls the sameRepositoryGraphQL(),IssueGraphQL(), andPullRequestGraphQL()functions that power the high-level commands.The implementation is ~160 lines of new code (plus tests) in a single new file
select_fields.go, with minimal changes toapi.go.Prototype
Working implementation with 20 unit + integration tests:
SebTardif/cli@feat/api-batch(second commit on the branch).Files:
pkg/cmd/api/select_fields.go— Pattern matching, query building, response unwrappingpkg/cmd/api/select_fields_test.go— 15 unit testspkg/cmd/api/api.go— Flag registration, validation, execution pathpkg/cmd/api/api_test.go— 5 integration testsAll existing tests pass. Lint clean.
Why this matters
LLM coding agents (GitHub Copilot, Cursor, etc.) increasingly use
gh apias their primary GitHub interface. They make dozens ofgh apicalls per session. This feature would let them request only the fields they need, reducing: