
Gh
- 68 installs
- Updated January 1, 1970
- dagster-io/erk
Wraps the GitHub CLI so a solo builder can manage PRs, issues, and repos through their coding agent.
About
gh is a skill from Dagster's erk toolkit that wraps the GitHub CLI so an agent can manage pull requests, issues, and repositories. A solo builder reaches for it to open PRs, check statuses, and handle GitHub operations without leaving their agent workflow.
- GitHub CLI integration
- Manage PRs and issues
- Agent-driven repo operations
Gh by the numbers
- 68 all-time installs (skills.sh)
- Ranked #269 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dagster-io/erk --skill ghAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 68 |
|---|---|
| Last updated | January 1, 1970 |
| Repository | dagster-io/erk ↗ |
What it does
Wraps the GitHub CLI so a solo builder can manage PRs, issues, and repos through their coding agent.
Who is it for?
GitHub PR and issue workflows
Skip if: Non-GitHub VCS
Files
GitHub CLI (gh)
Overview
GitHub CLI (gh) is the official command-line tool for GitHub that brings pull requests, issues, releases, and other GitHub concepts to the terminal. This skill provides comprehensive guidance for using gh to streamline GitHub workflows, including PR management, issue tracking, repository operations, and API access.
When to Use This Skill
Invoke this skill when users:
- Mention GitHub CLI (
gh) commands or workflows - Ask about creating, viewing, or managing pull requests from the command line
- Need help with GitHub issue management via CLI
- Want to understand gh's mental model or command structure
- Request guidance on GitHub automation or scripting
- Ask about GitHub API access through gh
- Need help with gh authentication or configuration
- Request integration patterns between gh, git, and other tools (like erk)
Core Concepts
Before providing guidance, understand these key concepts:
Three-Layer Architecture:
1. High-Level Commands (porcelain): gh pr, gh issue, gh repo - user-friendly workflows 2. API Access: gh api - direct REST/GraphQL access with built-in auth 3. Git Integration: Smart repo detection from git remotes and current branch
Context Resolution:
ghautomatically detects repository from git remotes- Uses current branch to infer PR context
- Falls back to interactive selection when ambiguous
Mental Model: Think of gh as "GitHub workflows made CLI-native" - each command maps to a common GitHub workflow optimized for terminal use.
Using the Reference Documentation
When providing gh guidance, load the comprehensive reference documentation:
references/gh.mdThis reference contains:
- Complete mental model and terminology
- Full command reference for PRs, issues, repos, releases, and more
- Authentication and configuration patterns
- Workflow patterns for common scenarios
- Integration details (erk, git, CI/CD)
- GitHub API access patterns
- Practical examples for daily development
Loading Strategy:
- Always load
references/gh.mdwhen user asks gh-related questions - The reference is comprehensive (~1480 lines) but optimized for progressive reading
- Use grep patterns to find specific sections when needed:
gh pr- Pull request commandsgh issue- Issue management commandsgh repo- Repository operationsgh api- API access patternsPattern [0-9]:- Workflow patternsAuthentication- Auth setuperk Integration- Integration with erk
Common Operations
When users ask for help with gh, guide them using these patterns:
First-Time Setup
1. Check if gh is installed: gh --version 2. Authenticate: gh auth login (interactive) or gh auth status (check current) 3. Configure defaults: gh config set <key> <value> 4. Test connection: gh repo view (in a git repo)
Pull Request Operations
Load references/gh.md and search for "gh pr" section to provide:
- Creating PRs:
gh pr create(interactive or with flags) - Viewing PRs:
gh pr view,gh pr list - Checking out PRs:
gh pr checkout <number> - Reviewing PRs:
gh pr review,gh pr diff - Merging PRs:
gh pr merge - PR status checks:
gh pr checks
Issue Management
Load references/gh.md and search for "gh issue" section to provide:
- Creating issues:
gh issue create - Listing issues:
gh issue list(with filters) - Viewing issues:
gh issue view <number> - Updating issues:
gh issue edit,gh issue close - Issue assignment and labels
Repository Operations
Load references/gh.md and search for "gh repo" section to provide:
- Viewing repos:
gh repo view - Cloning repos:
gh repo clone - Creating repos:
gh repo create - Forking repos:
gh repo fork - Repository settings and visibility
API Access
Load references/gh.md and search for "gh api" section to provide:
- REST API calls:
gh api <endpoint> - GraphQL queries:
gh api graphql -f query='...' - Pagination handling
- JSON processing with
--jq - Authentication details
For advanced GraphQL use cases, load references/graphql.md:
- Projects V2 management (no REST API exists)
- Discussion API operations
- Batch queries across multiple repos
- Complex nested data retrieval
- Advanced issue search
- See GraphQL API Reference section below
Release Management
Load references/gh.md and search for "gh release" section to provide:
- Creating releases:
gh release create - Listing releases:
gh release list - Downloading assets:
gh release download - Uploading assets:
gh release upload
Workflow Guidance
When users describe their workflow needs, map them to patterns in the reference:
Pattern 1: Daily PR Workflow - Create, review, merge PRs Pattern 2: Issue Triage - List, filter, and manage issues Pattern 3: Release Automation - Script release creation and asset management Pattern 4: PR Checks and Status - Monitor CI/CD and review status Pattern 5: Multi-Repo Operations - Work across multiple repositories Pattern 6: GitHub API Scripting - Automate complex GitHub workflows Pattern 7: Code Review Workflow - Review PRs from command line
Load the appropriate pattern sections from references/gh.md based on user needs.
Output Formatting
When users need to parse or format gh output:
1. Load the Output Formatting section from references/gh.md 2. Explain format options: --json, --jq, --template 3. Show JSON field selection: gh pr list --json number,title,state 4. Demonstrate jq filtering: gh api /repos/{owner}/{repo}/pulls | jq '.[] | select(.draft==false)' 5. Provide template examples for custom output
Authentication and Configuration
When users need auth or config help:
1. Load the Authentication & Configuration section from references/gh.md 2. Distinguish between:
- Authentication:
gh auth login, token management - Configuration:
gh config set, per-command defaults
3. Explain authentication methods: browser, token, SSH 4. Show common config settings: git_protocol, editor, pager 5. Handle multiple accounts and enterprise instances
Integration Guidance
Erk Integration
When users mention erk or worktree workflows:
- Load the Erk Integration section from
references/gh.md - Explain how gh detects repos in worktrees
- Show PR operations across multiple worktrees
- Guide on using
--repoflag when needed - Reference erk documentation for worktree-specific patterns
Git Integration
When users need to understand gh + git workflows:
- Load the Git Integration section from
references/gh.md - Explain repo detection from git remotes
- Show how current branch affects PR commands
- Demonstrate combined git + gh workflows
- Clarify when to use git vs gh commands
CI/CD Integration
When users want to integrate gh with CI/CD:
- Load the CI/CD patterns from
references/gh.md - Show authentication in CI environments:
GH_TOKEN - Provide examples of automated PR creation/merging
- Demonstrate status check monitoring
- Guide on release automation
Scripting and Automation
When users want to script GitHub workflows:
1. Load the Scripting section from references/gh.md 2. Show how to use gh in shell scripts 3. Demonstrate error handling: --jq, exit codes 4. Explain pagination for large datasets 5. Provide examples of common automation patterns:
- Bulk operations across PRs/issues
- Custom notifications
- Release workflows
- Repository management
Advanced Features
When users need advanced capabilities:
1. Aliases: Custom commands via gh alias set 2. Extensions: Third-party gh extensions 3. GraphQL: Complex queries beyond REST API (see GraphQL API Reference) 4. Webhooks: Trigger workflows (via API) 5. GitHub Actions: Interact with workflows via gh workflow
Load the relevant sections from references/gh.md for each advanced feature.
GraphQL API Reference
When standard gh commands are insufficient, use GraphQL via gh api graphql. Load references/graphql.md for comprehensive GraphQL guidance.
When to Use GraphQL:
Use GraphQL when the porcelain commands (gh pr, gh issue, etc.) cannot accomplish the task:
- Projects V2: No REST API exists - all operations require GraphQL
- Create/update projects
- Add items and update field values
- Query custom fields and project data
- Discussions: No porcelain commands available
- Create/manage discussions
- Add comments and replies
- Query discussion categories
- Batch Operations: Query multiple resources in one API call
- Compare multiple repositories
- Aggregate data across repos
- Reduce rate limit consumption
- Complex Queries: Fetch nested data efficiently
- PR with reviews, comments, and status checks in one call
- Issue with timeline, reactions, and linked PRs
- Repository with open issues, PRs, and contributors
- Advanced Search: Complex filtering beyond basic commands
- Multi-criteria issue/PR searches
- Boolean logic and date ranges
- Advanced sorting options
- Custom Fields: Precise field selection
- Request only needed fields
- Optimize for performance
- Build custom data aggregations
GraphQL Resources:
references/graphql.md- Complete GraphQL guide including:- Use cases requiring GraphQL
- Common patterns (variables, pagination, batching, etc.)
- Complete examples (Projects V2, Discussions, batch queries)
- Best practices and troubleshooting
references/graphql-schema-core.md- Core schema types (load only when needed):- Detailed field information for Repository, Issue, PullRequest, etc.
- Projects V2 field types and mutations
- Discussion types and operations
- Input types and enums
Loading Strategy:
1. Start with references/graphql.md for use cases and patterns 2. Load references/graphql-schema-core.md only when detailed schema info is needed 3. Use grep patterns to find specific sections:
Projects V2- Project automation examplesDiscussion- Discussion API examplesBatch- Batch query patternsPagination- Cursor-based paginationExample [0-9]- Complete working examples
Rate Limits and API Backend
When users encounter rate limit issues or need to optimize API usage:
1. Load references/api-backend-audit.md for complete command-to-API mapping 2. Understand the difference:
- REST: 5,000 requests/hour, counted per request
- GraphQL: 5,000 points/hour, cost based on query complexity
- Search: 30 requests/minute (separate limit)
3. Key insights:
- PR/Issue commands use GraphQL (query cost varies)
- Run/Workflow/Gist commands use REST (predictable cost)
- Project commands require GraphQL exclusively
- Search always uses REST with stricter limits
4. Check current limits: gh api rate_limit --jq '.resources'
Troubleshooting
When users encounter issues:
1. Check authentication: gh auth status 2. Verify repository detection: gh repo view 3. Test API access: gh api user 4. Review configuration: gh config list 5. Check rate limits: gh api rate_limit 6. Enable debug mode: GH_DEBUG=api gh <command>
Load the Troubleshooting section from references/gh.md for specific error patterns.
Command Discovery
When users ask "what can gh do?":
- Start with overview of main commands:
pr,issue,repo,release,workflow - Show command help:
gh <command> --help - Demonstrate interactive mode: most commands work interactively
- Point to
gh apifor anything not covered by porcelain commands - Reference the full command reference in
references/gh.md
Resources
references/
gh.md- Comprehensive GitHub CLI mental model and command reference (~1480 lines)- Load for all standard gh command guidance
- Full workflow patterns and examples
- Integration patterns (erk, git, CI/CD)
graphql.md- GitHub GraphQL API comprehensive guide (~1000 lines)- Load when porcelain commands are insufficient
- Use cases requiring GraphQL (Projects V2, Discussions, batch queries)
- Complete patterns and examples
- Best practices and troubleshooting
graphql-schema-core.md- Core GraphQL schema types (~500 lines)- Load only when detailed schema info needed
- Detailed field definitions for core types
- Mutation input types and examples
api-backend-audit.md- REST vs GraphQL API backend audit (~850 lines)- Load when understanding which API type a command uses
- Rate limit guidance and optimization strategies
- Complete mapping of all gh commands to their API backends
- Batch operation alternatives and caching strategies
These references should be loaded as needed to ensure accurate, detailed information. Use progressive disclosure: start with the main reference, then load specialized GraphQL docs when needed.
GitHub CLI API Backend Audit
Audit Metadata
| Field | Value |
|---|---|
| Analysis Date | 2025-12-08 |
| gh CLI Version | v2.83.1 |
| Source Commit | c8ab18323ee47721cba857bf82d55a21143566cb (2025-12-02) |
| Repository | https://github.com/cli/cli |
| Source Location | /Users/schrockn/code/githubs/cli |
Quick Reference Summary
| Command Family | Primary API | Notes |
|---|---|---|
gh pr | GraphQL | All PR operations use GraphQL for rich nested data |
gh issue | GraphQL | Issue queries and mutations via GraphQL |
gh repo | Mixed | GraphQL for queries, REST for some mutations |
gh release | Mixed | GraphQL for listing, REST for create/edit/delete |
gh run | REST | All workflow run operations use REST |
gh workflow | REST | Workflow management via REST |
gh gist | REST | All gist operations use REST |
gh project | GraphQL | Projects V2 requires GraphQL exclusively |
gh search | REST | Search API is REST-only |
gh secret | REST | Secrets management via REST |
gh variable | REST | Variables management via REST |
gh cache | REST | Actions cache management via REST |
gh label | Mixed | GraphQL for list, REST for create/edit/delete |
gh ruleset | Mixed | GraphQL for list, REST for view/check |
gh codespace | REST | Codespaces API via REST |
gh ssh-key | REST | SSH key management via REST |
gh gpg-key | REST | GPG key management via REST |
gh org | GraphQL | Organization listing via GraphQL |
gh status | Mixed | GraphQL for search, REST for notifications |
gh extension | REST | Extension discovery via REST |
gh attestation | REST | Attestation verification via REST |
Rate Limit Guidance
GitHub REST API Rate Limits
- Authenticated requests: 5,000 requests/hour
- Unauthenticated requests: 60 requests/hour
- Search API: 30 requests/minute (authenticated)
- Rate limit is per-user, not per-token
Checking rate limit status:
gh api rate_limit --jq '.resources'GitHub GraphQL API Rate Limits
- Point-based system: 5,000 points/hour
- Cost calculation: Based on query complexity
- Each connection costs 1 point + (first/last \* node cost)
- Nested connections multiply costs
- Minimum cost: 1 point per query
Checking GraphQL rate limit:
gh api graphql -f query='{ rateLimit { cost remaining resetAt } }'Key Differences
| Aspect | REST | GraphQL |
|---|---|---|
| Counting | Per request | Per query complexity |
| Predictability | Highly predictable | Varies by query structure |
| Pagination impact | Each page = 1 request | Deep pagination = higher cost |
| Bulk operations | Multiple requests | Single request, higher cost |
Rate Limit Strategies by API Type
For REST-heavy workflows (run, workflow, gist, search):
- Implement exponential backoff on 403/429 responses
- Use conditional requests (
If-None-Match) for caching - Batch operations where possible (e.g., delete multiple caches)
For GraphQL-heavy workflows (pr, issue, project):
- Request only needed fields to reduce query cost
- Use pagination efficiently (smaller page sizes for nested data)
- Avoid deeply nested queries when possible
- Consider
--paginateflag overhead
---
Command Family Details
Pull Request Commands (gh pr)
All PR commands use GraphQL for the primary operations, leveraging its ability to fetch nested data (reviews, checks, comments) efficiently.
| Subcommand | API Type | Query/Mutation/Endpoint | Notes |
|---|---|---|---|
list | GraphQL | PullRequestList query | Paginated, supports search filters |
view | GraphQL | PullRequest query | Fetches nested reviews, checks, comments |
create | GraphQL | PullRequestCreate mutation | Plus metadata mutations for labels/reviewers |
edit | GraphQL | PullRequestUpdate mutation | Updates title, body, base branch |
close | GraphQL | ClosePullRequest mutation | |
reopen | GraphQL | ReopenPullRequest mutation | |
merge | GraphQL | MergePullRequest mutation | Supports auto-merge enable/disable |
ready | GraphQL | MarkPullRequestReadyForReview mutation | Removes draft status |
review | GraphQL | AddPullRequestReview mutation | Comment, approve, or request changes |
comment | GraphQL | AddComment mutation | |
checks | GraphQL | StatusCheckRollup query | Fetches CI status and check runs |
status | GraphQL | PullRequestStatus query | Shows PRs needing attention |
diff | REST | GET repos/{owner}/{repo}/pulls/{number} | Accept: application/vnd.github.diff |
checkout | GraphQL | PullRequest query | Fetches head ref for git checkout |
update-branch | GraphQL | UpdatePullRequestBranch mutation | Updates branch with base |
Source files: pkg/cmd/pr/*/, api/queries_pr.go
---
Issue Commands (gh issue)
Issue commands primarily use GraphQL, with some REST for specific operations.
| Subcommand | API Type | Query/Mutation/Endpoint | Notes |
|---|---|---|---|
list | GraphQL | IssueList query | Paginated with filters |
view | GraphQL | Issue query | Rich nested data |
create | GraphQL | CreateIssue mutation | With label/assignee mutations |
edit | GraphQL | UpdateIssue mutation | |
close | GraphQL | CloseIssue mutation | |
reopen | GraphQL | ReopenIssue mutation | |
comment | GraphQL | AddComment mutation | |
delete | GraphQL | DeleteIssue mutation | |
transfer | GraphQL | TransferIssue mutation | |
pin | GraphQL | PinIssue mutation | |
unpin | GraphQL | UnpinIssue mutation | |
lock | GraphQL | LockLockable mutation | |
unlock | GraphQL | UnlockLockable mutation | |
status | GraphQL | IssueStatus query | Shows assigned/mentioned issues |
develop | GraphQL | CreateLinkedBranch mutation | Creates branch linked to issue |
Source files: pkg/cmd/issue/*/, api/queries_issue.go
---
Repository Commands (gh repo)
Repository commands use a mix of GraphQL and REST.
| Subcommand | API Type | Query/Mutation/Endpoint | Notes |
|---|---|---|---|
view | Mixed | GraphQL query + REST for README | GET repos/{owner}/{repo}/readme |
list | GraphQL | RepositoryList query | Paginated |
create | Mixed | GraphQL CreateRepository or REST | REST for user repos, GraphQL for orgs |
clone | GraphQL | Repository query | Fetches clone URL |
fork | GraphQL | ForkRepository mutation | |
edit | REST | PATCH repos/{owner}/{repo} | Plus PUT repos/{owner}/{repo}/topics |
delete | GraphQL | DeleteRepository mutation | |
rename | REST | PATCH repos/{owner}/{repo} | |
archive | GraphQL | ArchiveRepository mutation | |
unarchive | GraphQL | UnarchiveRepository mutation | |
sync | REST | POST repos/{owner}/{repo}/merge-upstream | Plus ref operations |
set-default | GraphQL | RepositoryNetwork query | Detects forks/parents |
credits | REST | GET repos/{owner}/{repo}/contributors | Hidden command |
deploy-key list | REST | GET repos/{owner}/{repo}/keys | |
deploy-key add | REST | POST repos/{owner}/{repo}/keys | |
deploy-key delete | REST | DELETE repos/{owner}/{repo}/keys/{id} | |
autolink list | REST | GET repos/{owner}/{repo}/autolinks | |
autolink create | REST | POST repos/{owner}/{repo}/autolinks | |
autolink view | REST | GET repos/{owner}/{repo}/autolinks/{id} | |
autolink delete | REST | DELETE repos/{owner}/{repo}/autolinks/{id} | |
gitignore list | REST | GET gitignore/templates | |
gitignore view | REST | GET gitignore/templates/{name} | |
license list | REST | GET licenses | |
license view | REST | GET licenses/{key} |
Source files: pkg/cmd/repo/*/, api/queries_repo.go
---
Release Commands (gh release)
Release commands use a mix of GraphQL for querying and REST for mutations.
| Subcommand | API Type | Query/Mutation/Endpoint | Notes |
|---|---|---|---|
list | GraphQL | RepositoryReleaseList query | Paginated |
view | Mixed | GraphQL query, REST fallback | GET repos/{owner}/{repo}/releases/tags/{tag} |
create | REST | POST repos/{owner}/{repo}/releases | Plus asset uploads |
edit | REST | PATCH repos/{owner}/{repo}/releases/{id} | |
delete | REST | DELETE repos/{owner}/{repo}/releases/{id} | |
download | REST | GET repos/{owner}/{repo}/releases/assets/{id} | Binary download |
upload | REST | POST uploads.github.com/.../assets | Multipart upload |
Source files: pkg/cmd/release/*/
---
Workflow Run Commands (gh run)
All workflow run commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET repos/{owner}/{repo}/actions/runs | Paginated |
view | REST | GET repos/{owner}/{repo}/actions/runs/{id} | Plus jobs endpoint |
watch | REST | GET repos/{owner}/{repo}/actions/runs/{id} | Polling |
rerun | REST | POST repos/{owner}/{repo}/actions/runs/{id}/rerun | Or rerun-failed-jobs |
cancel | REST | POST repos/{owner}/{repo}/actions/runs/{id}/cancel | |
delete | REST | DELETE repos/{owner}/{repo}/actions/runs/{id} | |
download | REST | GET repos/{owner}/{repo}/actions/runs/{id}/artifacts | Plus artifact download |
Source files: pkg/cmd/run/*/
---
Workflow Commands (gh workflow)
All workflow commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET repos/{owner}/{repo}/actions/workflows | |
view | REST | GET repos/{owner}/{repo}/actions/workflows/{id} | |
run | REST | POST repos/{owner}/{repo}/actions/workflows/{id}/dispatches | |
enable | REST | PUT repos/{owner}/{repo}/actions/workflows/{id}/enable | |
disable | REST | PUT repos/{owner}/{repo}/actions/workflows/{id}/disable |
Source files: pkg/cmd/workflow/*/
---
Project Commands (gh project)
All project commands use GraphQL exclusively (Projects V2 has no REST API).
| Subcommand | API Type | Mutation/Query | Notes |
|---|---|---|---|
list | GraphQL | ProjectV2List query | User or org projects |
view | GraphQL | ProjectV2 query | With items and fields |
create | GraphQL | CreateProjectV2 mutation | |
edit | GraphQL | UpdateProjectV2 mutation | |
close | GraphQL | CloseProjectV2 mutation | |
delete | GraphQL | DeleteProjectV2 mutation | |
copy | GraphQL | CopyProjectV2 mutation | |
mark-template | GraphQL | MarkProjectV2AsTemplate mutation | |
field-list | GraphQL | ProjectV2Fields query | |
field-create | GraphQL | CreateProjectV2Field mutation | |
field-delete | GraphQL | DeleteProjectV2Field mutation | |
item-list | GraphQL | ProjectV2Items query | Paginated |
item-add | GraphQL | AddProjectV2ItemById mutation | |
item-create | GraphQL | AddProjectV2DraftIssue mutation | |
item-edit | GraphQL | UpdateProjectV2ItemFieldValue mutation | |
item-delete | GraphQL | DeleteProjectV2Item mutation | |
item-archive | GraphQL | ArchiveProjectV2Item mutation | |
link | GraphQL | LinkProjectV2ToRepository mutation | |
unlink | GraphQL | UnlinkProjectV2FromRepository mutation |
Source files: pkg/cmd/project/*/, pkg/cmd/project/shared/queries/
---
Search Commands (gh search)
All search commands use REST API (GitHub Search API).
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
repos | REST | GET search/repositories | 30 req/min limit |
issues | REST | GET search/issues | Includes PRs |
prs | REST | GET search/issues | With is:pr filter |
commits | REST | GET search/commits | |
code | REST | GET search/code | Requires repo scope |
Rate limit: Search API has a separate rate limit of 30 requests/minute (authenticated).
Source files: pkg/cmd/search/*/, pkg/search/
---
Secret Commands (gh secret)
All secret commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET repos/{owner}/{repo}/actions/secrets | Or org/env secrets |
set | REST | PUT repos/{owner}/{repo}/actions/secrets/{name} | Requires public key |
delete | REST | DELETE repos/{owner}/{repo}/actions/secrets/{name} |
Source files: pkg/cmd/secret/*/
---
Variable Commands (gh variable)
All variable commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET repos/{owner}/{repo}/actions/variables | Paginated |
get | REST | GET repos/{owner}/{repo}/actions/variables/{name} | |
set | REST | POST/PATCH repos/{owner}/{repo}/actions/variables/{name} | |
delete | REST | DELETE repos/{owner}/{repo}/actions/variables/{name} |
Source files: pkg/cmd/variable/*/
---
Cache Commands (gh cache)
All cache commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET repos/{owner}/{repo}/actions/caches | Paginated |
delete | REST | DELETE repos/{owner}/{repo}/actions/caches/{id} | Or by key |
Source files: pkg/cmd/cache/*/
---
Label Commands (gh label)
Label commands use a mix of GraphQL and REST.
| Subcommand | API Type | Endpoint/Query | Notes |
|---|---|---|---|
list | GraphQL | LabelList query | Paginated |
create | REST | POST repos/{owner}/{repo}/labels | |
edit | REST | PATCH repos/{owner}/{repo}/labels/{name} | |
delete | REST | DELETE repos/{owner}/{repo}/labels/{name} | |
clone | Mixed | GraphQL list + REST create | Copies labels between repos |
Source files: pkg/cmd/label/
---
Gist Commands (gh gist)
All gist commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET gists | Paginated |
view | REST | GET gists/{id} | |
create | REST | POST gists | |
edit | REST | PATCH gists/{id} | |
delete | REST | DELETE gists/{id} | |
clone | REST | GET gists/{id} | Fetches for git clone |
rename | REST | PATCH gists/{id} |
Source files: pkg/cmd/gist/*/
---
Ruleset Commands (gh ruleset)
Ruleset commands use a mix of GraphQL and REST.
| Subcommand | API Type | Endpoint/Query | Notes |
|---|---|---|---|
list | GraphQL | RepositoryRulesets query | |
view | REST | GET repos/{owner}/{repo}/rulesets/{id} | |
check | REST | GET repos/{owner}/{repo}/rules/branches/{branch} |
Source files: pkg/cmd/ruleset/*/
---
Codespace Commands (gh codespace)
All codespace commands use REST API via the Codespaces API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET user/codespaces | |
view | REST | GET user/codespaces/{name} | |
create | REST | POST user/codespaces | |
delete | REST | DELETE user/codespaces/{name} | |
edit | REST | PATCH user/codespaces/{name} | |
stop | REST | POST user/codespaces/{name}/stop | |
rebuild | REST | POST user/codespaces/{name}/rebuild | |
code | REST | Fetches codespace URL | |
ssh | REST | Fetches SSH details | |
ports | REST | GET user/codespaces/{name}/ports | |
logs | REST | Fetches log stream URL | |
jupyter | REST | Fetches Jupyter URL |
Source files: pkg/cmd/codespace/*/
---
SSH Key Commands (gh ssh-key)
All SSH key commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET user/keys | |
add | REST | POST user/keys | Or user/ssh_signing_keys |
delete | REST | DELETE user/keys/{id} |
Source files: pkg/cmd/ssh-key/*/
---
GPG Key Commands (gh gpg-key)
All GPG key commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
list | REST | GET user/gpg_keys | |
add | REST | POST user/gpg_keys | |
delete | REST | DELETE user/gpg_keys/{id} |
Source files: pkg/cmd/gpg-key/*/
---
Organization Commands (gh org)
Organization commands use GraphQL.
| Subcommand | API Type | Query | Notes |
|---|---|---|---|
list | GraphQL | OrganizationList query | User's orgs |
Source files: pkg/cmd/org/*/
---
Status Command (gh status)
The status command uses a mix of GraphQL and REST.
| Operation | API Type | Endpoint/Query | Notes |
|---|---|---|---|
| Search mentions | GraphQL | Search query | Finds mentions/assignments |
| Notifications | REST | GET notifications | Paginated |
| Comment details | REST | GET repos/{owner}/{repo}/issues/comments/{id} |
Source files: pkg/cmd/status/
---
Extension Commands (gh extension)
Extension commands use REST for GitHub API access.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
search | REST | GET search/repositories | Topic: gh-extension |
browse | REST | GET search/repositories | |
install | REST | GET repos/{owner}/{repo}/releases | |
upgrade | REST | GET repos/{owner}/{repo}/releases/latest |
Source files: pkg/cmd/extension/*/
---
Auth Commands (gh auth)
Auth commands primarily use REST for validation.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
login | REST | GET / (root) | Validates token scopes |
status | REST | GET / (root) | Checks auth and scopes |
token | N/A | Local only | Retrieves stored token |
refresh | OAuth | OAuth flow | Re-authenticates |
logout | N/A | Local only | Removes stored credentials |
setup-git | N/A | Local only | Configures git credential helper |
switch | N/A | Local only | Switches active account |
Source files: pkg/cmd/auth/*/
---
Attestation Commands (gh attestation)
Attestation commands use REST API.
| Subcommand | API Type | Endpoint | Notes |
|---|---|---|---|
download | REST | Attestation API | |
inspect | REST | Attestation API | |
verify | REST | Attestation API | |
trustedroot | REST | Attestation API |
Source files: pkg/cmd/attestation/*/
---
API Detection Methodology
This audit was performed by analyzing the gh CLI source code:
Patterns Used
REST API detection:
client.REST(hostname, method, path, body, data)
client.RESTWithNext(...) // Paginated REST
ghinstance.RESTPrefix(host) + path // Direct HTTPGraphQL API detection:
client.GraphQL(hostname, query, variables, data) // Raw query
client.Query(hostname, name, query, variables) // Structured query
client.Mutate(hostname, name, mutation, variables) // Mutations
gql.Query(...) / gql.Mutate(...) // Via gql clientFile Naming Conventions
http.go- HTTP/API layer implementationqueries_*.go- GraphQL query definitions (inapi/)*_test.go- Test files with mock API patterns
Source Code Locations
| Package | Purpose |
|---|---|
api/ | Core API client and GraphQL queries |
pkg/cmd/*/ | Command implementations |
pkg/search/ | Search API implementation |
internal/ghinstance/ | API endpoint URL construction |
---
Rate Limit Optimization Strategies
Commands to Avoid in Tight Loops
High-cost operations:
gh pr viewwith--commentsor--json(deep nested GraphQL)gh project item-listwith many fieldsgh searchcommands (30 req/min limit)- Any
--paginateoperation with large datasets
Commands Safe for Bulk Operations
Efficient REST operations:
gh run list/gh workflow listgh cache listgh secret list/gh variable listgh gist list
Batch Operation Alternatives
Instead of multiple single queries:
# Bad: Multiple API calls
for pr in 1 2 3 4 5; do gh pr view $pr; done
# Better: Single GraphQL query with aliases (via gh api graphql)
gh api graphql -f query='
query {
pr1: repository(owner:"owner", name:"repo") { pullRequest(number:1) { title } }
pr2: repository(owner:"owner", name:"repo") { pullRequest(number:2) { title } }
}
'Caching Strategies
Use `--cache` flag where available:
gh api /repos/{owner}/{repo} --cache 1hConditional requests (automatic with gh api):
- gh CLI sends
If-None-Matchheaders automatically - 304 responses don't count against primary rate limit
Pagination Best Practices
For GraphQL (pr, issue, project):
- Use smaller
--limitvalues for nested data - Prefer
--jsonwith specific fields over full view
For REST (run, workflow, search):
- Use
--limitto avoid fetching unnecessary pages - Consider
--jqfiltering before pagination to reduce data
---
See Also
gh.md- Command reference and workflowsgraphql.md- GraphQL API patternsgraphql-schema-core.md- GraphQL schema reference- GitHub REST API docs
- GitHub GraphQL API docs
GitHub CLI (gh) Mental Model
Last Updated: 2025-10-13
A comprehensive guide to understanding GitHub CLI's mental model, command structure, and integration patterns.
---
Table of Contents
- What is GitHub CLI?
- Core Mental Model
- Terminology
- Authentication & Configuration
- Command Reference
- Workflow Patterns
- Erk Integration
- Practical Examples
- Key Insights for AI Agents
- Additional Resources
---
What is GitHub CLI?
GitHub CLI (gh) is the official command-line tool for GitHub. It brings pull requests, issues, releases, and other GitHub concepts to the terminal.
The Problem It Solves
Without gh, working with GitHub requires:
1. Switching to browser for PR operations 2. Manual URL construction 3. Context switching between terminal and web 4. No scriptable GitHub workflows
With gh, you can:
- Create, view, and merge PRs from terminal
- Manage issues without leaving your editor
- Script GitHub workflows
- Query GitHub API with built-in authentication
Core Philosophy
GitHub in your terminal. gh mirrors GitHub's web interface structure but optimized for CLI workflows and automation.
---
Core Mental Model
The Three-Layer Architecture
GitHub CLI operates on three conceptual layers:
┌─────────────────────────────────────────┐
│ High-Level Commands (pr, issue, repo) │ ← User-friendly, porcelain commands
├─────────────────────────────────────────┤
│ REST API & GraphQL Layer (gh api) │ ← Direct API access
├─────────────────────────────────────────┤
│ Git Integration & Auth │ ← Credentials, git protocol
└─────────────────────────────────────────┘Layer 1: High-Level Commands (Porcelain)
These are the commands you use daily: gh pr create, gh issue list, etc.
Mental model: Think of these as "GitHub workflows made CLI-native"
- Each command maps to a common GitHub workflow
- Designed for interactive use and scripting
- Automatically handle common cases (current branch, repo detection)
Layer 2: API Access (gh api)
Direct access to GitHub's REST and GraphQL APIs.
Mental model: Think of this as "curl for GitHub with auth built-in"
- Full API access for advanced use cases
- Automatic authentication and token management
- Supports both REST endpoints and GraphQL queries
- Used when porcelain commands don't cover your needs
Layer 3: Git Integration
How gh connects to your local git repository.
Mental model: Think of this as "smart repo detection"
- Reads git remotes to determine GitHub repository
- Uses current branch to infer PR context
- Integrates with git credentials
The Resource Model
GitHub CLI organizes around GitHub's core resources:
Repository (owner/name)
├── Pull Requests (pr)
│ ├── Number (e.g., #123)
│ ├── Branch (e.g., feature-branch)
│ └── URL (e.g., https://github.com/owner/repo/pull/123)
├── Issues (issue)
│ ├── Number (e.g., #456)
│ └── URL
├── Releases (release)
├── Actions (run, workflow, cache)
└── Projects (project)Key insight: Most gh commands follow this pattern:
gh <resource> <action> [identifier] [flags]Examples:
gh pr view 123- view pull request #123gh issue create- create a new issuegh repo fork- fork the current repository
Context Resolution
gh is context-aware. It automatically determines:
1. Repository: From git remote (or -R flag) 2. Pull Request: From current branch (or explicit number/URL) 3. Authentication: From stored credentials
This means you can often omit arguments:
# In a repo with a remote and on a branch with a PR:
gh pr view # ← Automatically finds the PR for your current branch
gh pr merge # ← Merges the current branch's PR---
Terminology
Core Concepts
| Term | Definition | Example |
|---|---|---|
| Repository | A GitHub repository, identified by owner/repo | cli/cli |
| Remote | Git remote URL pointing to GitHub | origin → git@github.com:cli/cli.git |
| PR | Pull Request - a request to merge changes | PR #123 |
| Head | The branch containing your changes | feature-branch |
| Base | The branch you want to merge into | main |
| Draft | A PR marked as "work in progress" | Draft PR |
| Review | Approval/change requests on a PR | Approved, Changes Requested |
| Check | CI/CD status check on a PR | GitHub Actions, CircleCI |
| State | Current status of PR/issue | open, closed, merged |
Resource Identifiers
GitHub CLI accepts resources in multiple formats:
Pull Requests & Issues:
gh pr view 123 # By number
gh pr view feature-branch # By branch name
gh pr view https://github.com/owner/repo/pull/123 # By URL
gh pr view owner:feature-branch # By owner:branch (for forks)Repositories:
gh repo view cli/cli # By owner/repo
gh repo view https://github.com/cli/cli # By URL
gh repo view # Current repo (from git remote)JSON Fields
When using --json, GitHub CLI provides structured data. Common fields:
| Field | Type | Description |
|---|---|---|
number | int | PR or issue number |
title | string | Title text |
body | string | Description text |
state | string | OPEN, CLOSED, MERGED |
headRefName | string | Head branch name |
baseRefName | string | Base branch name |
author | object | Author login and info |
url | string | Full GitHub URL |
isDraft | bool | Draft PR status |
statusCheckRollup | array | CI/CD check status |
reviews | array | Review information |
labels | array | Labels applied |
---
Authentication & Configuration
Authentication Flow
# First time setup - interactive login
gh auth login
# Check authentication status
gh auth status
# Refresh credentials (e.g., to add scopes)
gh auth refresh -s read:org,repo,workflowWhat happens during `gh auth login`:
1. Prompts for GitHub.com or GitHub Enterprise 2. Asks for authentication method (browser or token) 3. Requests permission scopes 4. Stores credentials securely in system keyring
Authentication Storage
Credentials stored in:
- macOS: Keychain
- Linux: libsecret or encrypted file
- Windows: Credential ManagerToken scopes determine what gh can do:
repo: Full repo access (required for most operations)read:org: Read organization dataworkflow: Trigger GitHub Actionsgist: Manage gistsproject: Manage projects
Configuration
View current configuration:
gh config listCommon config options:
gh config set git_protocol https # Use HTTPS for git operations
gh config set editor vim # Set default editor
gh config set prompt enabled # Enable interactive prompts
gh config set browser firefox # Set browser for --web flagConfiguration file location: ~/.config/gh/config.yml
Repository Context
gh determines the repository from:
1. -R owner/repo flag (highest priority) 2. GH_REPO environment variable 3. Git remote named origin 4. Git remote named upstream
Override for specific command:
gh pr list -R cli/cliSet default repo for directory:
gh repo set-default cli/cli---
Command Reference
Pull Request Commands (gh pr)
The most commonly used gh commands revolve around pull requests.
gh pr list - List Pull Requests
# Basic listing
gh pr list # Open PRs in current repo
gh pr list --state all # All PRs (open, closed, merged)
gh pr list --state merged # Only merged PRs
# Filtering
gh pr list --author @me # Your PRs
gh pr list --author username # Specific author
gh pr list --label bug # PRs with "bug" label
gh pr list --base main # PRs targeting main branch
gh pr list --head feature-branch # PRs from feature-branch
# Searching (advanced)
gh pr list --search "status:success" # Successful checks
gh pr list --search "review:required" # Needs review
gh pr list --search "status:success review:required" # Both
# Limiting results
gh pr list --limit 50 # Show 50 PRs (default 30)
# JSON output
gh pr list --json number,title,state,headRefName
gh pr list --json number,title --jq '.[].number' # Just PR numbersJSON fields available: additions, assignees, author, autoMergeRequest, baseRefName, baseRefOid, body, changedFiles, closed, closedAt, comments, commits, createdAt, deletions, files, fullDatabaseId, headRefName, headRefOid, headRepository, headRepositoryOwner, id, isCrossRepository, isDraft, labels, latestReviews, maintainerCanModify, mergeCommit, mergeStateStatus, mergeable, mergedAt, mergedBy, milestone, number, potentialMergeCommit, projectCards, projectItems, reactionGroups, reviewDecision, reviewRequests, reviews, state, statusCheckRollup, title, updatedAt, url
gh pr create - Create Pull Request
# Interactive (prompts for title and body)
gh pr create
# Quick creation with title and body
gh pr create --title "Fix bug" --body "This fixes the bug"
# Auto-fill from commits
gh pr create --fill # Uses last commit for title/body
gh pr create --fill-first # Uses first commit
gh pr create --fill-verbose # Uses all commits for body
# Draft PR
gh pr create --draft
# With reviewers and assignees
gh pr create --reviewer username1,username2
gh pr create --reviewer myorg/team-name
gh pr create --assignee @me
# With labels and milestone
gh pr create --label bug,urgent
gh pr create --milestone "Sprint 23"
# Target specific branches
gh pr create --base develop # Target develop instead of main
gh pr create --head user:feature # Explicitly specify head branch
# Open browser to create PR
gh pr create --web
# Using template file
gh pr create --template .github/pull_request_template.md
# Dry run (see what would be created)
gh pr create --dry-run --title "Test" --body "Test body"Body file from stdin:
cat pr-description.md | gh pr create --body-file -gh pr view - View Pull Request
# View current branch's PR
gh pr view
# View specific PR
gh pr view 123
gh pr view https://github.com/owner/repo/pull/123
gh pr view feature-branch
# In browser
gh pr view --web
gh pr view 123 --web
# With comments
gh pr view 123 --comments
# JSON output
gh pr view 123 --json title,body,state,author
gh pr view 123 --json state --jq '.state'
# Pretty output with template
gh pr view 123 --json number,title,author \
--template '{{.number}}: {{.title}} by {{.author.login}}'gh pr checkout - Checkout Pull Request
# Checkout PR by number
gh pr checkout 123
# Checkout with custom branch name
gh pr checkout 123 --branch my-review-branch
# Force update existing branch
gh pr checkout 123 --force
# Detached HEAD (no branch)
gh pr checkout 123 --detach
# With submodules
gh pr checkout 123 --recurse-submodulesWhat happens:
1. Fetches the PR's head branch 2. Creates/updates local branch 3. Checks out the branch
gh pr merge - Merge Pull Request
# Interactive merge (prompts for method)
gh pr merge
# Merge strategies
gh pr merge --merge # Create merge commit
gh pr merge --squash # Squash and merge
gh pr merge --rebase # Rebase and merge
# Auto-merge (when checks pass)
gh pr merge --auto
# Disable auto-merge
gh pr merge --disable-auto
# Custom commit message
gh pr merge --squash --subject "Fix: Bug fix" --body "Details..."
# Delete branch after merge
gh pr merge --delete-branch
# Admin override (bypass requirements)
gh pr merge --admin
# Require head commit match (safety check)
gh pr merge --match-head-commit abc123gh pr status - Show PR Status
gh pr status # PRs for current repoShows:
- Pull requests assigned to you
- Pull requests that mention you
- Pull requests you created
gh pr checks - View CI Status
gh pr checks # Current branch's PR
gh pr checks 123 # Specific PR
# Watch checks in real-time
gh pr checks --watchOther PR Commands
# Close PR
gh pr close 123
gh pr close 123 --delete-branch
# Reopen PR
gh pr reopen 123
# Mark as ready for review
gh pr ready 123
# Add comment
gh pr comment 123 --body "LGTM!"
# Review PR
gh pr review 123 --approve
gh pr review 123 --request-changes --body "Please fix..."
gh pr review 123 --comment --body "Looks good but minor suggestions"
# Edit PR
gh pr edit 123 --title "New title"
gh pr edit 123 --body "New description"
gh pr edit 123 --add-label bug
gh pr edit 123 --remove-label wip
# View diff
gh pr diff 123
# Update PR branch
gh pr update-branch 123 # Merge base into PR branch
# Lock/unlock conversation
gh pr lock 123
gh pr unlock 123Issue Commands (gh issue)
Very similar to PR commands, but for issues.
# List issues
gh issue list
gh issue list --state all
gh issue list --author @me
gh issue list --assignee @me
gh issue list --label bug
gh issue list --search "is:open label:bug"
# Create issue
gh issue create
gh issue create --title "Bug report" --body "Description"
gh issue create --label bug,urgent
gh issue create --assignee @me
gh issue create --web
# View issue
gh issue view 456
gh issue view 456 --web
gh issue view 456 --comments
gh issue view 456 --json title,body,state
# Edit issue
gh issue edit 456 --title "New title"
gh issue edit 456 --add-label help-wanted
# Close/reopen
gh issue close 456
gh issue reopen 456
# Comment
gh issue comment 456 --body "Thanks for reporting"
# Develop (link branch to issue)
gh issue develop 456 --checkout
# Transfer to another repo
gh issue transfer 456 owner/other-repo
# Pin/unpin
gh issue pin 456
gh issue unpin 456
# Lock/unlock
gh issue lock 456
gh issue unlock 456
# Delete (careful!)
gh issue delete 456Repository Commands (gh repo)
# View repository
gh repo view
gh repo view cli/cli
gh repo view --web
# Clone repository
gh repo clone cli/cli
gh repo clone cli/cli custom-directory
# Create repository
gh repo create my-project # Create in current directory
gh repo create owner/my-project # Create remote only
gh repo create --public # Public repo
gh repo create --private # Private repo
gh repo create --template owner/template # From template
# Fork repository
gh repo fork
gh repo fork cli/cli
gh repo fork --clone # Fork and clone
# List repositories
gh repo list # Your repos
gh repo list owner # Specific user/org
gh repo list --limit 100
# Edit repository settings
gh repo edit --description "My awesome project"
gh repo edit --homepage https://example.com
gh repo edit --enable-issues
gh repo edit --enable-wiki=false
# Archive/unarchive
gh repo archive owner/repo
gh repo unarchive owner/repo
# Rename
gh repo rename new-name
# Delete (careful!)
gh repo delete owner/repo
# Sync fork
gh repo sync # Sync fork with upstream
# Set default repo for directory
gh repo set-default owner/repo
# Deploy keys
gh repo deploy-key list
gh repo deploy-key add key.pub --title "CI Key"
gh repo deploy-key delete <key-id>API Commands (gh api)
Direct access to GitHub's REST and GraphQL APIs.
REST API Access
# GET request
gh api repos/cli/cli/releases
# With placeholders
gh api repos/{owner}/{repo}/releases # Auto-fills from current repo
# POST request
gh api repos/cli/cli/issues -f title="Bug" -f body="Description"
# Explicit method
gh api -X PATCH repos/cli/cli -f description="New description"
# Custom headers
gh api repos/cli/cli -H "Accept: application/vnd.github.v3.raw+json"
# Query parameters (for GET)
gh api -X GET search/issues -f q='repo:cli/cli is:open'
# Request body from file
gh api repos/cli/cli/issues --input issue.json
# Include response headers
gh api repos/cli/cli -i
# Pagination (fetch all pages)
gh api --paginate repos/cli/cli/issues
# Filter with jq
gh api repos/cli/cli/issues --jq '.[].title'
# Template output
gh api repos/cli/cli/issues --template '{{range .}}{{.title}}{{"\n"}}{{end}}'
# Nested parameters
gh api gists -F 'files[myfile.txt][content]=@myfile.txt'
# Cache responses
gh api repos/cli/cli --cache 3600s # Cache for 1 hourGraphQL Access
# Basic GraphQL query
gh api graphql -f query='
query {
viewer {
login
name
}
}'
# With variables
gh api graphql -F owner='{owner}' -F name='{repo}' -f query='
query($name: String!, $owner: String!) {
repository(owner: $owner, name: $name) {
releases(last: 3) {
nodes { tagName }
}
}
}
'
# Paginated GraphQL query
gh api graphql --paginate -f query='
query($endCursor: String) {
viewer {
repositories(first: 100, after: $endCursor) {
nodes { nameWithOwner }
pageInfo {
hasNextPage
endCursor
}
}
}
}
'
# Combine pages into single array
gh api graphql --paginate --slurp -f query='...'Workflow Commands (gh run, gh workflow)
# List workflow runs
gh run list
gh run list --workflow=ci.yml
gh run list --branch=main
gh run list --status=failure
# View run details
gh run view 123456
gh run view --log # Show logs
# Watch run in progress
gh run watch 123456
# Re-run workflow
gh run rerun 123456
gh run rerun 123456 --failed # Re-run failed jobs only
# Cancel run
gh run cancel 123456
# Delete run
gh run delete 123456
# List workflows
gh workflow list
# View workflow
gh workflow view ci.yml
# Enable/disable workflow
gh workflow enable ci.yml
gh workflow disable ci.yml
# Trigger workflow
gh workflow run ci.yml
gh workflow run ci.yml -f param=value # With inputsAuthentication Commands (gh auth)
# Login
gh auth login # Interactive
gh auth login --with-token < token.txt # From token
# Check status
gh auth status
# Refresh token (add scopes)
gh auth refresh -s read:org,repo,workflow
# Setup git integration
gh auth setup-git
# Get token (for scripts)
gh auth token
# Switch accounts
gh auth switch
# Logout
gh auth logoutOther Commands
# Search
gh search repos "language:python stars:>1000"
gh search issues "is:open label:bug"
gh search prs "is:merged author:octocat"
# Gist management
gh gist create file.txt # Creates gist with original filename
gh gist create - --filename name.txt # stdin-only: --filename requires stdin input (-)
gh gist list
gh gist view abc123
gh gist edit abc123
gh gist delete abc123
# Aliases
gh alias set pv 'pr view' # Create alias
gh alias list # List aliases
# Extensions
gh extension install owner/gh-extension
gh extension list
gh extension upgrade --all
# Completion
gh completion -s bash > /etc/bash_completion.d/gh
gh completion -s zsh > /usr/local/share/zsh/site-functions/_gh---
Workflow Patterns
Pattern 1: Creating a PR
Standard workflow:
# 1. Make changes and commit
git add .
git commit -m "Fix bug"
# 2. Push branch
git push -u origin feature-branch
# 3. Create PR with autofill
gh pr create --fill
# Or, all in one step (gh will push for you if needed)
gh pr create --fillAdvanced: Create draft PR, then mark ready:
gh pr create --draft --fill
# ... continue working ...
gh pr readyPattern 2: Reviewing PRs
Quick review workflow:
# 1. List PRs needing review
gh pr list --search "review-requested:@me"
# 2. View PR details
gh pr view 123
# 3. Checkout and test locally
gh pr checkout 123
# ... run tests, verify changes ...
# 4. Submit review
gh pr review 123 --approve
# or
gh pr review 123 --request-changes --body "Please fix X"
# 5. Return to main branch
git checkout mainView PR checks before reviewing:
gh pr view 123
gh pr checks 123
gh pr diff 123
gh pr view 123 --commentsPattern 3: Merging PRs
Safe merge workflow:
# 1. Check PR status
gh pr status
# 2. View the PR
gh pr view 123
# 3. Check CI status
gh pr checks 123
# 4. Merge (interactive method selection)
gh pr merge 123
# Or specify merge strategy
gh pr merge 123 --squash --delete-branchAuto-merge when checks pass:
gh pr merge 123 --auto --squashPattern 4: Working with Forks
Fork and contribute workflow:
# 1. Fork repository
gh repo fork owner/repo --clone
# 2. Create feature branch
git checkout -b feature-branch
# 3. Make changes and commit
# ...
# 4. Push to your fork
git push -u origin feature-branch
# 5. Create PR to upstream
gh pr create --repo owner/repoSync fork with upstream:
gh repo syncPattern 5: Scripting with gh
Get all open PRs as JSON:
gh pr list --state open --json number,title,author,createdAt \
--jq '.[] | "\(.number): \(.title) by \(.author.login)"'Find PRs with failing checks:
gh pr list --json number,statusCheckRollup \
--jq '.[] | select(.statusCheckRollup[].conclusion == "failure") | .number'Close all stale PRs:
# Get PRs not updated in 90 days
gh pr list --state open --json number,updatedAt --limit 1000 \
--jq '.[] | select(.updatedAt | fromdateiso8601 < (now - 90*86400)) | .number' \
| xargs -I {} gh pr close {}Batch operations:
# Add label to multiple PRs
for pr in 123 124 125; do
gh pr edit $pr --add-label needs-review
donePattern 6: Finding Information
Find which PR introduced a commit:
gh pr list --search "<commit-sha>" --state mergedList your pending PRs across all repos:
gh search prs "is:open author:@me"Find PRs by label:
gh pr list --label bug --state allPattern 7: CI/CD Integration
Wait for checks to pass in CI script:
#!/bin/bash
PR_NUMBER=$1
while true; do
STATUS=$(gh pr view $PR_NUMBER --json statusCheckRollup \
--jq '.statusCheckRollup[].conclusion')
if echo "$STATUS" | grep -q "FAILURE"; then
echo "Checks failed"
exit 1
elif echo "$STATUS" | grep -qv "SUCCESS"; then
echo "Waiting for checks..."
sleep 30
else
echo "All checks passed"
break
fi
doneAuto-merge after successful deploy:
#!/bin/bash
# In CI after deploy succeeds
gh pr merge $PR_NUMBER --squash --auto---
Erk Integration
How Erk Uses gh
Erk integrates with GitHub CLI to enhance the worktree workflow by providing PR status information directly in the worktree listing.
1. PR Information Retrieval
File: src/erk/github_ops.py:GitHubOps.get_prs()
Command executed:
gh pr list --state all --json number,headRefName,url,state,isDraft,statusCheckRollupWhat it does:
- Fetches ALL PRs (open, closed, merged) for the repository
- Retrieves structured JSON data with key fields
- Parses into
PullRequestInfodataclass - Returns dict mapping
branch_name → PullRequestInfo
JSON fields used:
{
"number": 123,
"headRefName": "feature-branch",
"url": "https://github.com/owner/repo/pull/123",
"state": "OPEN", # or "CLOSED", "MERGED"
"isDraft": false,
"statusCheckRollup": [
{"conclusion": "SUCCESS", "name": "ci/test"}
]
}2. Display in erk ls
File: src/erk/commands/list.py
When you run erk ls, you see:
feature-1 feature/amazing-feature PR #123 ✓
feature-2 feature/bug-fix PR #124 (draft)
feature-3 feature/experimental (no PR)Status indicators:
✓- All checks passing✗- Some checks failing⋯- Checks pending(draft)- Draft PR(closed)- Closed PR(merged)- Merged PR
3. Cleanup with Sync (erk sync)
File: src/erk/commands/sync.py
Uses PR state to identify cleanup candidates:
- Worktrees with merged PRs → Safe to delete
- Worktrees with closed PRs → Prompt user
- Worktrees without PRs → Skip
Use erk sync --dry-run to preview cleanup candidates without removal.
4. Error Handling
Erk gracefully handles gh unavailability:
- If
ghnot installed → Silent fallback (no PR info shown) - If not authenticated → Silent fallback
- If API fails → Continue without PR data
This ensures erk works even without GitHub CLI.
5. Authentication Requirements
Erk relies on existing gh authentication:
# User must authenticate first
gh auth login
# Then erk automatically uses those credentials
erk lsNo separate authentication needed - leverages gh token storage.
---
Practical Examples
Example 1: Daily PR Workflow
# Morning: Check what needs attention
gh pr status
# See PRs needing your review
gh pr list --search "review-requested:@me"
# Review a PR
gh pr view 456
gh pr checkout 456
# ... test locally ...
gh pr review 456 --approve
# Check your own PRs
gh pr list --author @me
# View checks on your PR
gh pr checksExample 2: Feature Development
# Start feature
git checkout -b feature/new-thing
# ... write code ...
git commit -m "Implement new thing"
# Create draft PR
gh pr create --draft --fill
# Continue development
# ... more commits ...
git push
# Mark ready when done
gh pr ready
# After review, merge
gh pr merge --squash --delete-branchExample 3: Hotfix Workflow
# Create hotfix branch
git checkout -b hotfix/critical-bug
# Fix and commit
# ...
git commit -m "Fix critical bug"
# Create PR with reviewers immediately
gh pr create \
--title "HOTFIX: Critical bug fix" \
--body "Fixes production issue XYZ" \
--reviewer team-lead,ops-team \
--label hotfix,urgent
# Watch checks
gh pr checks --watch
# Once approved, merge immediately
gh pr merge --squash --delete-branchExample 4: Managing Stale PRs
# Find old PRs
gh pr list --state open --json number,title,updatedAt \
--jq '.[] | select(.updatedAt | fromdateiso8601 < (now - 2592000))
| "\(.number): \(.title) (updated: \(.updatedAt))"'
# Close specific PR with comment
gh pr close 789 --comment "Closing due to inactivity. Please reopen if still relevant."
# Or update PR branch to trigger CI
gh pr update-branch 789Example 5: Release Management
# List recent releases
gh release list --limit 10
# Create release from tag
git tag v1.2.3
git push origin v1.2.3
gh release create v1.2.3 --generate-notes
# Create release with assets
gh release create v1.2.3 \
--title "Version 1.2.3" \
--notes "See CHANGELOG.md for details" \
./dist/*.tar.gz
# View release
gh release view v1.2.3
# Download release assets
gh release download v1.2.3Example 6: Advanced Searching
# Find all PRs you authored that are merged
gh search prs "is:merged author:@me"
# Find open PRs with failing checks
gh search prs "is:open is:pr status:failure"
# Find PRs with specific label across org
gh search prs "org:myorg label:security"
# Find issues assigned to you across all repos
gh search issues "is:open assignee:@me"Example 7: Templated Output
# Custom PR list format
gh pr list --json number,title,author,updatedAt \
--template '{{range .}}{{printf "#%-4d" .number}} {{.title | truncate 60}} by {{.author.login}}{{"\n"}}{{end}}'
# PR status with checks
gh pr view 123 --json title,statusCheckRollup \
--template '{{.title}}{{"\n"}}Checks:{{"\n"}}{{range .statusCheckRollup}} {{.name}}: {{.conclusion}}{{"\n"}}{{end}}'
# List with custom formatting
gh pr list --json number,title,updatedAt \
--template '{{range .}}{{tablerow (printf "#%v" .number | autocolor "green") (.title | truncate 50) (timeago .updatedAt)}}{{end}}{{tablerender}}'Example 8: GraphQL Power Queries
# Get repository statistics
gh api graphql -f query='
query {
repository(owner: "cli", name: "cli") {
stargazerCount
forkCount
issues {
totalCount
}
pullRequests {
totalCount
}
}
}'
# Get PR review stats
gh api graphql -f owner='cli' -f name='cli' -f query='
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
pullRequests(first: 100, states: MERGED) {
nodes {
number
reviews {
totalCount
}
comments {
totalCount
}
}
}
}
}'---
Key Insights for AI Agents
When to Use gh vs Git
Use `gh` for:
- Creating/viewing/merging PRs
- Managing issues
- Viewing CI status
- Accessing GitHub-specific features (labels, reviews, projects)
Use `git` for:
- Branch operations (checkout, merge, rebase)
- Commit operations
- Push/pull/fetch
- Local repository operations
Use both together:
git checkout -b feature # Git for branches
git commit -m "Fix" # Git for commits
gh pr create --fill # gh for PR creationContext-Aware Operations
gh automatically detects context:
# These are equivalent if you're on feature-branch with PR #123:
gh pr view
gh pr view 123
gh pr view feature-branch
# These are equivalent in a repo with remote:
gh pr list
gh pr list -R owner/repoImplication for agents: Often don't need to specify PR numbers or repo - gh infers from context.
JSON Output for Scripting
Always use `--json` when scripting:
# Bad (fragile, human-readable format)
gh pr list | grep "my-branch"
# Good (structured, parseable)
gh pr list --json headRefName,number \
--jq '.[] | select(.headRefName == "my-branch") | .number'Available JSON fields: Use --json without fields to see available options:
gh pr list --jsonError Handling
gh returns non-zero exit codes on failure:
if gh pr view 123 &>/dev/null; then
echo "PR exists"
else
echo "PR not found or error"
fiCommon exit codes:
0- Success1- General error2- Command not found4- Authentication error
Rate Limiting
GitHub API has rate limits:
- Authenticated: 5,000 requests/hour
- Unauthenticated: 60 requests/hour
gh automatically handles authentication, so you get higher limits.
Check rate limit:
gh api rate_limitPagination Considerations
Default limits:
gh pr list- 30 resultsgh issue list- 30 results
Get more results:
gh pr list --limit 100 # Up to 100 results
gh pr list --limit 1000 # Up to 1000 results
# Get ALL results (may be slow)
gh api --paginate repos/{owner}/{repo}/pullsBest Practices for Agents
1. Check for `gh` availability before using:
if command -v gh &>/dev/null; then
gh pr list
else
echo "gh not installed"
fi2. Use `--json` for reliable parsing:
gh pr list --json number,title3. Prefer explicit repo specification when operating on non-current repos:
gh pr list -R owner/repo4. Handle authentication errors gracefully:
if ! gh auth status &>/dev/null; then
echo "Not authenticated. Run: gh auth login"
exit 1
fi5. Use specific PR identifiers when possible:
# Explicit
gh pr view 123
# Implicit (context-dependent)
gh pr view6. Combine `gh api` with `jq` for complex queries:
gh api repos/{owner}/{repo}/pulls --jq '.[].number'7. Cache API responses when appropriate:
gh api repos/{owner}/{repo} --cache 3600s---
Additional Resources
- Official Docs: https://cli.github.com/manual/
- GitHub REST API: https://docs.github.com/en/rest
- GitHub GraphQL API: https://docs.github.com/en/graphql
- Search Syntax: https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests
- jq Manual: https://jqlang.github.io/jq/manual/
- Exit Codes: Run
gh help exit-codes - Environment Variables: Run
gh help environment
GitHub GraphQL Schema - Core Types
This document provides a focused reference for the most commonly used GraphQL types and fields in GitHub's API. For the complete schema, visit: https://docs.github.com/en/graphql/reference
Load this document only when you need detailed field information for specific types. Most use cases are covered in graphql.md.
---
Repository
Represents a Git repository.
type Repository {
# Identifiers
id: ID!
databaseId: Int!
name: String!
nameWithOwner: String!
# Basic info
description: String
url: URI!
homepageUrl: URI
isPrivate: Boolean!
isFork: Boolean!
isArchived: Boolean!
# Ownership
owner: RepositoryOwner!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
pushedAt: DateTime
# Stats
stargazerCount: Int!
forkCount: Int!
# Language
primaryLanguage: Language
# Connections
issues(
first: Int
after: String
states: [IssueState!]
labels: [String!]
orderBy: IssueOrder
): IssueConnection!
pullRequests(
first: Int
after: String
states: [PullRequestState!]
baseRefName: String
headRefName: String
): PullRequestConnection!
discussions(first: Int, after: String, categoryId: ID): DiscussionConnection!
discussionCategories(first: Int, after: String): DiscussionCategoryConnection!
projectsV2(first: Int, after: String): ProjectV2Connection!
refs(
first: Int
after: String
refPrefix: String! # "refs/heads/" or "refs/tags/"
): RefConnection!
defaultBranchRef: Ref
# Access
viewerCanAdminister: Boolean!
viewerCanUpdateTopics: Boolean!
viewerHasStarred: Boolean!
}Common Queries:
# Basic repo info
query {
repository(owner: "facebook", name: "react") {
id
name
stargazerCount
forkCount
}
}
# Repo with open issues
query {
repository(owner: "myorg", name: "myrepo") {
issues(first: 10, states: OPEN) {
nodes {
number
title
}
}
}
}---
Issue
A trackable work item.
type Issue {
# Identifiers
id: ID!
databaseId: Int!
number: Int!
# Content
title: String!
body: String
bodyHTML: HTML!
bodyText: String!
# Status
state: IssueState! # OPEN or CLOSED
stateReason: IssueStateReason # COMPLETED, NOT_PLANNED, REOPENED
closed: Boolean!
locked: Boolean!
# Metadata
author: Actor
createdAt: DateTime!
updatedAt: DateTime!
closedAt: DateTime
# Repository
repository: Repository!
url: URI!
# Connections
assignees(first: Int, after: String): UserConnection!
labels(first: Int, after: String): LabelConnection!
comments(first: Int, after: String): IssueCommentConnection!
projectItems(
first: Int
after: String
includeArchived: Boolean = true
): ProjectV2ItemConnection!
milestone: Milestone
timelineItems(
first: Int
after: String
itemTypes: [IssueTimelineItemsItemType!]
): IssueTimelineItemsConnection!
# Reactions
reactions(first: Int, content: ReactionContent): ReactionConnection!
# Access
viewerCanUpdate: Boolean!
viewerCanReact: Boolean!
viewerDidAuthor: Boolean!
}Common Queries:
# Issue with assignees and labels
query {
repository(owner: "myorg", name: "myrepo") {
issue(number: 123) {
title
state
assignees(first: 5) {
nodes {
login
}
}
labels(first: 10) {
nodes {
name
color
}
}
}
}
}
# Issue with comments
query {
repository(owner: "myorg", name: "myrepo") {
issue(number: 123) {
title
comments(first: 50) {
nodes {
author {
login
}
body
createdAt
}
}
}
}
}Common Mutations:
# Create issue
mutation ($repoId: ID!, $title: String!, $body: String) {
createIssue(input: { repositoryId: $repoId, title: $title, body: $body }) {
issue {
id
number
url
}
}
}
# Add labels
mutation ($issueId: ID!, $labelIds: [ID!]!) {
addLabelsToLabelable(input: { labelableId: $issueId, labelIds: $labelIds }) {
labelable {
... on Issue {
labels(first: 10) {
nodes {
name
}
}
}
}
}
}
# Close issue
mutation ($issueId: ID!) {
closeIssue(input: { issueId: $issueId, stateReason: COMPLETED }) {
issue {
state
closedAt
}
}
}---
PullRequest
A code review request.
type PullRequest {
# Identifiers
id: ID!
databaseId: Int!
number: Int!
# Content
title: String!
body: String
bodyHTML: HTML!
# Status
state: PullRequestState! # OPEN, CLOSED, MERGED
isDraft: Boolean!
merged: Boolean!
mergeable: MergeableState! # MERGEABLE, CONFLICTING, UNKNOWN
closed: Boolean!
locked: Boolean!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
closedAt: DateTime
mergedAt: DateTime
# Authors
author: Actor
mergedBy: Actor
# Repository
repository: Repository!
url: URI!
# Branches
baseRefName: String!
headRefName: String!
baseRefOid: GitObjectID!
headRefOid: GitObjectID!
# Changes
additions: Int!
deletions: Int!
changedFiles: Int!
# Connections
assignees(first: Int, after: String): UserConnection!
labels(first: Int, after: String): LabelConnection!
reviewRequests(first: Int, after: String): ReviewRequestConnection!
reviews(
first: Int
after: String
states: [PullRequestReviewState!]
author: String
): PullRequestReviewConnection!
comments(first: Int, after: String): IssueCommentConnection!
reviewThreads(first: Int, after: String): PullRequestReviewThreadConnection!
commits(first: Int, after: String): PullRequestCommitConnection!
files(first: Int, after: String): PullRequestChangedFileConnection!
projectItems(
first: Int
after: String
includeArchived: Boolean = true
): ProjectV2ItemConnection!
milestone: Milestone
# Access
viewerCanUpdate: Boolean!
viewerCanReact: Boolean!
viewerDidAuthor: Boolean!
viewerCanApplySuggestion: Boolean!
}Nested Type: PullRequestReview
type PullRequestReview {
id: ID!
author: Actor
body: String!
state: PullRequestReviewState! # PENDING, COMMENTED, APPROVED, CHANGES_REQUESTED, DISMISSED
submittedAt: DateTime
createdAt: DateTime!
comments(first: Int): PullRequestReviewCommentConnection!
}Nested Type: PullRequestChangedFile
type PullRequestChangedFile {
path: String!
additions: Int!
deletions: Int!
changeType: PatchStatus! # ADDED, DELETED, MODIFIED, RENAMED, COPIED, CHANGED
}Common Queries:
# PR with reviews and status
query {
repository(owner: "myorg", name: "myrepo") {
pullRequest(number: 456) {
title
state
isDraft
mergeable
reviews(first: 10) {
nodes {
author {
login
}
state
body
}
}
commits(last: 1) {
nodes {
commit {
statusCheckRollup {
state
}
}
}
}
}
}
}
# PR with files changed
query {
repository(owner: "myorg", name: "myrepo") {
pullRequest(number: 456) {
files(first: 100) {
nodes {
path
additions
deletions
changeType
}
}
}
}
}Common Mutations:
# Create PR
mutation (
$repoId: ID!
$baseRefName: String!
$headRefName: String!
$title: String!
$body: String
) {
createPullRequest(
input: {
repositoryId: $repoId
baseRefName: $baseRefName
headRefName: $headRefName
title: $title
body: $body
}
) {
pullRequest {
id
number
url
}
}
}
# Merge PR
mutation ($prId: ID!, $commitHeadline: String) {
mergePullRequest(
input: {
pullRequestId: $prId
commitHeadline: $commitHeadline
mergeMethod: SQUASH
}
) {
pullRequest {
merged
mergedAt
}
}
}---
ProjectV2
GitHub Projects (current version).
type ProjectV2 {
# Identifiers
id: ID!
databaseId: Int!
number: Int!
# Content
title: String!
shortDescription: String
readme: String
# Status
public: Boolean!
closed: Boolean!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
closedAt: DateTime
# Ownership
owner: ProjectV2Owner!
url: URI!
# Connections
items(
first: Int
after: String
orderBy: ProjectV2ItemOrder
): ProjectV2ItemConnection!
fields(
first: Int
after: String
orderBy: ProjectV2FieldOrder
): ProjectV2FieldConnection!
views(
first: Int
after: String
orderBy: ProjectV2ViewOrder
): ProjectV2ViewConnection!
# Access
viewerCanUpdate: Boolean!
viewerCanClose: Boolean!
}Field Types (Union):
# Base field type
type ProjectV2Field {
id: ID!
name: String!
dataType: ProjectV2FieldType! # TEXT, NUMBER, DATE, SINGLE_SELECT, ITERATION
createdAt: DateTime!
updatedAt: DateTime!
}
# Single select dropdown
type ProjectV2SingleSelectField {
id: ID!
name: String!
dataType: ProjectV2FieldType!
options: [ProjectV2SingleSelectFieldOption!]!
}
type ProjectV2SingleSelectFieldOption {
id: String!
name: String!
color: ProjectV2SingleSelectFieldOptionColor!
description: String
}
# Iteration/Sprint field
type ProjectV2IterationField {
id: ID!
name: String!
dataType: ProjectV2FieldType!
configuration: ProjectV2IterationFieldConfiguration!
}
type ProjectV2IterationFieldConfiguration {
iterations: [ProjectV2IterationFieldIteration!]!
completedIterations: [ProjectV2IterationFieldIteration!]!
duration: Int!
startDay: Int!
}
type ProjectV2IterationFieldIteration {
id: String!
title: String!
startDate: Date!
duration: Int!
}ProjectV2Item:
type ProjectV2Item {
id: ID!
databaseId: Int!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
# Content (union type)
content: ProjectV2ItemContent # Issue, PullRequest, or DraftIssue
# Project
project: ProjectV2!
# Field values
fieldValues(first: Int, after: String): ProjectV2ItemFieldValueConnection!
fieldValueByName(name: String!): ProjectV2ItemFieldValue
}Common Queries:
# Get project with fields
query {
organization(login: "myorg") {
projectV2(number: 1) {
id
title
fields(first: 20) {
nodes {
... on ProjectV2Field {
id
name
}
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
... on ProjectV2IterationField {
id
name
configuration {
iterations {
id
title
startDate
}
}
}
}
}
}
}
}
# Get project items with content
query {
node(id: "PROJECT_ID") {
... on ProjectV2 {
items(first: 50) {
nodes {
id
content {
... on Issue {
number
title
repository {
nameWithOwner
}
}
... on PullRequest {
number
title
repository {
nameWithOwner
}
}
}
}
}
}
}
}Common Mutations:
# Create project
mutation ($ownerId: ID!, $title: String!) {
createProjectV2(input: { ownerId: $ownerId, title: $title }) {
projectV2 {
id
number
url
}
}
}
# Add item to project
mutation ($projectId: ID!, $contentId: ID!) {
addProjectV2ItemById(
input: { projectId: $projectId, contentId: $contentId }
) {
item {
id
}
}
}
# Update field value (text/number/date)
mutation ($projectId: ID!, $itemId: ID!, $fieldId: ID!, $value: String!) {
updateProjectV2ItemFieldValue(
input: {
projectId: $projectId
itemId: $itemId
fieldId: $fieldId
value: { text: $value }
}
) {
projectV2Item {
id
}
}
}
# Update single select field
mutation ($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
updateProjectV2ItemFieldValue(
input: {
projectId: $projectId
itemId: $itemId
fieldId: $fieldId
value: { singleSelectOptionId: $optionId }
}
) {
projectV2Item {
id
}
}
}
# Update iteration field
mutation ($projectId: ID!, $itemId: ID!, $fieldId: ID!, $iterationId: String!) {
updateProjectV2ItemFieldValue(
input: {
projectId: $projectId
itemId: $itemId
fieldId: $fieldId
value: { iterationId: $iterationId }
}
) {
projectV2Item {
id
}
}
}---
Discussion
A discussion thread.
type Discussion {
# Identifiers
id: ID!
databaseId: Int!
number: Int!
# Content
title: String!
body: String!
bodyHTML: HTML!
# Status
locked: Boolean!
closed: Boolean!
# Metadata
author: Actor
createdAt: DateTime!
updatedAt: DateTime!
closedAt: DateTime
# Category
category: DiscussionCategory!
# Repository
repository: Repository!
url: URI!
# Answer
answer: DiscussionComment
answerChosenAt: DateTime
answerChosenBy: Actor
# Connections
comments(first: Int, after: String): DiscussionCommentConnection!
labels(first: Int, after: String): LabelConnection!
reactions(first: Int, content: ReactionContent): ReactionConnection!
# Poll (if discussion is a poll)
poll: DiscussionPoll
# Access
viewerCanUpdate: Boolean!
viewerCanReact: Boolean!
viewerDidAuthor: Boolean!
}DiscussionCategory:
type DiscussionCategory {
id: ID!
name: String!
description: String
emoji: String!
emojiHTML: HTML!
# If true, only maintainers can create discussions in this category
isAnswerable: Boolean!
repository: Repository!
}DiscussionComment:
type DiscussionComment {
id: ID!
databaseId: Int!
body: String!
bodyHTML: HTML!
author: Actor
createdAt: DateTime!
updatedAt: DateTime!
discussion: Discussion!
url: URI!
# If comment is a reply
replyTo: DiscussionComment
# Nested replies
replies(first: Int, after: String): DiscussionCommentConnection!
reactions(first: Int, content: ReactionContent): ReactionConnection!
viewerCanUpdate: Boolean!
viewerCanReact: Boolean!
viewerDidAuthor: Boolean!
}Common Queries:
# Discussion with comments
query {
repository(owner: "myorg", name: "myrepo") {
discussion(number: 10) {
title
body
category {
name
emoji
}
answer {
body
author {
login
}
}
comments(first: 50) {
nodes {
author {
login
}
body
createdAt
replies(first: 10) {
nodes {
author {
login
}
body
}
}
}
}
}
}
}
# Discussion categories
query {
repository(owner: "myorg", name: "myrepo") {
discussionCategories(first: 20) {
nodes {
id
name
description
emoji
isAnswerable
}
}
}
}Common Mutations:
Note: Discussions API requires special header: -H 'GraphQL-Features: discussions_api'
# Create discussion
mutation ($repoId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
createDiscussion(
input: {
repositoryId: $repoId
categoryId: $categoryId
title: $title
body: $body
}
) {
discussion {
id
number
url
}
}
}
# Add comment
mutation ($discussionId: ID!, $body: String!) {
addDiscussionComment(input: { discussionId: $discussionId, body: $body }) {
comment {
id
url
}
}
}
# Reply to comment
mutation ($discussionId: ID!, $replyToId: ID!, $body: String!) {
addDiscussionComment(
input: { discussionId: $discussionId, replyToId: $replyToId, body: $body }
) {
comment {
id
url
}
}
}
# Mark comment as answer
mutation ($id: ID!) {
markDiscussionCommentAsAnswer(input: { id: $id }) {
discussion {
answer {
id
body
}
}
}
}---
User
A GitHub user account.
type User {
# Identifiers
id: ID!
databaseId: Int!
login: String!
# Profile
name: String
email: String!
bio: String
bioHTML: HTML!
avatarUrl(size: Int): URI!
websiteUrl: URI
location: String
company: String
# Status
isHireable: Boolean!
isCampusExpert: Boolean!
isDeveloperProgramMember: Boolean!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
# Connections
repositories(
first: Int
after: String
privacy: RepositoryPrivacy
orderBy: RepositoryOrder
): RepositoryConnection!
issues(first: Int, after: String, states: [IssueState!]): IssueConnection!
pullRequests(
first: Int
after: String
states: [PullRequestState!]
): PullRequestConnection!
followers(first: Int, after: String): FollowerConnection!
following(first: Int, after: String): FollowingConnection!
# Stats
repositoriesContributedTo(
first: Int
contributionTypes: [RepositoryContributionType!]
): RepositoryConnection!
}Common Queries:
# User profile
query {
user(login: "octocat") {
name
login
bio
avatarUrl
company
location
websiteUrl
repositories(first: 10, orderBy: { field: STARGAZERS, direction: DESC }) {
nodes {
name
stargazerCount
}
}
}
}
# Current authenticated user
query {
viewer {
login
name
email
}
}---
Organization
An organization account.
type Organization {
# Identifiers
id: ID!
databaseId: Int!
login: String!
# Profile
name: String
description: String
email: String
websiteUrl: URI
location: String
avatarUrl(size: Int): URI!
# Dates
createdAt: DateTime!
updatedAt: DateTime!
# Connections
repositories(
first: Int
after: String
privacy: RepositoryPrivacy
orderBy: RepositoryOrder
): RepositoryConnection!
members(first: Int, after: String): UserConnection!
teams(first: Int, after: String, privacy: TeamPrivacy): TeamConnection!
projectsV2(
first: Int
after: String
orderBy: ProjectV2Order
): ProjectV2Connection!
# Access
viewerCanAdminister: Boolean!
viewerCanCreateProjects: Boolean!
viewerCanCreateRepositories: Boolean!
viewerIsAMember: Boolean!
}Common Queries:
# Organization with repositories
query {
organization(login: "github") {
name
description
repositories(first: 10, orderBy: { field: STARGAZERS, direction: DESC }) {
nodes {
name
stargazerCount
}
}
}
}
# Organization projects
query {
organization(login: "myorg") {
projectsV2(first: 20) {
nodes {
id
number
title
}
}
}
}---
Common Enums
IssueState
enum IssueState {
OPEN
CLOSED
}PullRequestState
enum PullRequestState {
OPEN
CLOSED
MERGED
}PullRequestReviewState
enum PullRequestReviewState {
PENDING
COMMENTED
APPROVED
CHANGES_REQUESTED
DISMISSED
}MergeableState
enum MergeableState {
MERGEABLE
CONFLICTING
UNKNOWN
}ProjectV2FieldType
enum ProjectV2FieldType {
TEXT
NUMBER
DATE
SINGLE_SELECT
ITERATION
}ReactionContent
enum ReactionContent {
THUMBS_UP
THUMBS_DOWN
LAUGH
HOORAY
CONFUSED
HEART
ROCKET
EYES
}---
Input Types
CreateIssueInput
input CreateIssueInput {
repositoryId: ID!
title: String!
body: String
assigneeIds: [ID!]
labelIds: [ID!]
milestoneId: ID
projectIds: [ID!]
}CreatePullRequestInput
input CreatePullRequestInput {
repositoryId: ID!
baseRefName: String!
headRefName: String!
title: String!
body: String
draft: Boolean
maintainerCanModify: Boolean
}CreateProjectV2Input
input CreateProjectV2Input {
ownerId: ID!
title: String!
repositoryId: ID
teamId: ID
}AddProjectV2ItemByIdInput
input AddProjectV2ItemByIdInput {
projectId: ID!
contentId: ID!
}UpdateProjectV2ItemFieldValueInput
input UpdateProjectV2ItemFieldValueInput {
projectId: ID!
itemId: ID!
fieldId: ID!
value: ProjectV2FieldValue!
}
input ProjectV2FieldValue {
text: String
number: Float
date: Date
singleSelectOptionId: String
iterationId: String
}CreateDiscussionInput
input CreateDiscussionInput {
repositoryId: ID!
categoryId: ID!
title: String!
body: String!
}---
Connection Types
All connections follow this pattern:
type XConnection {
edges: [XEdge!]
nodes: [X!]
pageInfo: PageInfo!
totalCount: Int!
}
type XEdge {
node: X!
cursor: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}Usage:
- Use
nodesfor simple list access - Use
edgeswhen you need cursors for each item - Always include
pageInfofor pagination
---
Introspection
Query All Types
query {
__schema {
types {
name
kind
description
}
}
}Query Specific Type
query {
__type(name: "Repository") {
name
kind
fields {
name
type {
name
kind
}
description
}
}
}Query Enum Values
query {
__type(name: "IssueState") {
name
enumValues {
name
description
}
}
}---
Additional Resources
- Full schema: https://docs.github.com/en/graphql/reference
- GraphQL Explorer: https://docs.github.com/en/graphql/overview/explorer
- GraphQL changelog: https://docs.github.com/en/graphql/overview/changelog