name: gh-cli description: Use the GitHub CLI (gh) to interact with GitHub. Load when working with issues, pull requests, repositories, code search, Actions, CI status, projects, releases, or gists. Triggers include "create a PR", "open a pull request", "open an issue", "check CI", "list PRs", "merge", "review", "check workflow status", "GitHub Actions", or any task involving GitHub - even if the user doesn't mention "gh" explicitly.
GitHub CLI (gh)
Use the gh CLI to interact with GitHub from the command line. Always prefer gh over
raw API calls or web browser interaction.
Important:
ghshould already be installed and authenticated. If a command fails due to missing installation or authentication, notify the user — do not attempt to install or configureghyourself.
Permissions
Commands are split into two categories based on configured permissions:
Readonly (run freely): list, view, status, checks, diff, checkout, search,
watch, download, browse — these never modify remote state and can be run without asking.
Mutating (requires user confirmation): create, edit, close, merge, comment,
review, reopen, ready, rerun, cancel, delete, upload, fork, sync, run,
enable, disable, lock, unlock, revert, update-branch, gh api — these modify
remote state and will prompt the user for approval before executing.
Always prefer running readonly commands first to gather context, then propose mutating commands and let the user confirm.
Key Patterns
- Use
--jsonand--jqfor structured data extraction (avoids fragile text parsing) - Use
--repo owner/repoto target a different repository - Use
--paginatefor large result sets - Avoid interactive commands (
-iflags, editors) — always pass arguments directly - This skill covers the most common operations. For additional subcommands not listed here,
run
gh --helporgh <command> --helpto discover available commands and flags
Pull Requests
# Readonly — run freely
gh pr list
gh pr list --state all --author @me
gh pr list --json number,title,state --jq '.[] | select(.title | contains("fix"))'
gh pr view 123
gh pr view 123 --comments
gh pr view 123 --json title,body,state,author,commits,files
gh pr checkout 123
gh pr diff 123
gh pr diff 123 --name-only
gh pr checks 123
gh pr checks 123 --watch
gh pr status
# Mutating — user will be asked to confirm
gh pr create --title "Title" --body "Description"
gh pr create --draft --base main --head feature
gh pr create --reviewer user1,user2 --labels enhancement
gh pr create --body-file body.md
gh pr edit 123 --title "New title" --add-label bug --add-reviewer user1
gh pr merge 123 --squash --delete-branch
gh pr close 123 --comment "Reason"
gh pr reopen 123
gh pr review 123 --approve --body "LGTM!"
gh pr review 123 --request-changes --body "Please fix..."
gh pr comment 123 --body "Comment text"
gh pr ready 123
PR Review Threads
GitHub has no dedicated gh pr subcommand for resolving review comment threads.
Use the GraphQL API via gh api graphql.
Confirmation rule: Only run the resolve mutation when the user has explicitly requested it (e.g. "mark the comment as resolved", "resolve that thread"). In all other cases — such as when reviewing a PR or summarising feedback — list the threads for context but ask for confirmation before resolving anything.
# Readonly — list review threads with their IDs and resolution state
gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
id
isResolved
comments(first: 1) { nodes { body } }
}
}
}
}
}
' -f owner=OWNER -f repo=REPO -F pr=NUMBER
# Mutating — resolve a single thread by its node ID (from the query above)
gh api graphql -f query='
mutation($id: ID!) {
resolveReviewThread(input: {threadId: $id}) {
thread { id isResolved }
}
}
' -f id="PRT_kwDO..."
The node ID looks like PRT_kwDO... and is returned by the reviewThreads query above.
To resolve all unresolved threads in one pass, pipe the query result through jq to
extract IDs, then loop and call the mutation for each.
Issues
# Readonly — run freely
gh issue list
gh issue list --state all --labels bug
gh issue list --assignee @me
gh issue list --search "is:open label:bug"
gh issue list --json number,title,state
gh issue view 123
gh issue view 123 --comments
gh issue view 123 --json title,body,state,labels
gh issue status
# Mutating — user will be asked to confirm
gh issue create --title "Bug: description" --body "Details..."
gh issue create --title "Bug" --labels bug,high-priority --assignee @me
gh issue edit 123 --title "New title" --add-label enhancement
gh issue close 123 --comment "Fixed in PR #456"
gh issue reopen 123
gh issue comment 123 --body "Comment text"
GitHub Actions / CI
# Readonly — run freely
gh run list
gh run list --workflow "ci.yml" --branch main --limit 10
gh run view 123456789
gh run view 123456789 --log
gh run view 123456789 --job 987654321
gh run watch 123456789
gh run download 123456789 --name build --dir ./artifacts
gh workflow list
gh workflow view ci.yml --yaml
# Mutating — user will be asked to confirm
gh run rerun 123456789
gh run cancel 123456789
gh workflow run ci.yml --ref develop
Repositories
# Readonly — run freely
gh repo view
gh repo view owner/repo --json name,description,defaultBranchRef
gh repo clone owner/repo
# Mutating — user will be asked to confirm
gh repo create my-repo --public --description "Description"
gh repo fork owner/repo --clone
gh repo sync
gh repo set-default owner/repo
Search
# All search commands are readonly — run freely
gh search code "pattern" --repo owner/repo
gh search code "import" --extension py
gh search issues "label:bug state:open"
gh search prs "is:open review:required"
gh search repos "stars:>1000 language:python" --sort stars
API Requests
For operations not covered by dedicated subcommands, use gh api directly.
All gh api calls require user confirmation since they can modify remote state.
# REST
gh api /repos/owner/repo --jq '.stargazers_count'
gh api --method POST /repos/owner/repo/issues \
--field title="Title" --field body="Body"
# GraphQL
gh api graphql -f query='{
viewer { login repositories(first: 5) { nodes { name } } }
}'
# Pagination
gh api /user/repos --paginate
Releases
# Readonly — run freely
gh release list
gh release view v1.0.0
gh release download v1.0.0 --pattern "*.tar.gz" --dir ./downloads
# Mutating — user will be asked to confirm
gh release create v1.0.0 --notes "Release notes" --target main
gh release create v1.0.0 --draft --notes-file notes.md
gh release upload v1.0.0 ./artifact.tar.gz
Variables
# Readonly — run freely
gh variable list
gh variable get MY_VAR
# Mutating — user will be asked to confirm
gh variable set MY_VAR "value"
Common Workflows
Create PR from Issue
# Mutating — each step will ask for confirmation
gh issue develop 123 --branch feature/issue-123
# Make changes, commit, push...
gh pr create --title "Fix #123" --body "Closes #123"
Bulk Operations
# List is readonly, but each close is mutating and will ask
gh issue list --search "label:stale" --json number --jq '.[].number' | \
xargs -I {} gh issue close {} --comment "Closing as stale"
Output Formatting
# JSON with jq filtering
gh pr list --json number,title --jq '.[] | select(.number > 100)'
# Go templates
gh repo view --template '{{.name}}: {{.description}}'
For full subcommand reference, run gh <command> --help.