Using GitHub CLI
Overview
Manage GitHub resources using the gh CLI instead of REST API calls or MCP servers. Assumes CLI is authenticated (gh auth status). Focus on checking existing state before creating or modifying anything.
Core principle: Always check what exists before creating. Duplicate PRs, redundant issues, and orphaned branches waste everyone's time.
When to Use
- •Creating, reviewing, or merging pull requests
- •Managing issues (create, search, close, triage)
- •Working with GitHub project boards
- •Querying repo metadata, releases, or workflow runs
- •Any GitHub operation where you'd otherwise reach for
curlor the REST API
Workflow
1. Context Check
Before any operation, confirm you're in the right repo and authenticated:
# Confirm repo identity and default branch gh repo view --json nameWithOwner,defaultBranchRef --jq '.nameWithOwner + " (default: " + .defaultBranchRef.name + ")"' # Verify auth (especially after long sessions) gh auth status
If you're not in a git repo, or need to target a different one, pass --repo OWNER/REPO on every command.
2. Discovery
Before creating any resource, check what already exists. This is the most important step agents skip.
Before creating a PR:
# Check if current branch already has a PR gh pr list --head $(git branch --show-current) --json number,title,state,url
If this returns results, do not create a new PR. View the existing one instead.
Before creating an issue:
# Search for existing issues with similar content gh issue list --search "the problem description" --state all --json number,title,state --limit 10
Before working on a project board:
# List available projects gh project list --owner ORG --format json
3. Execution
Output defaults:
- •Always use
--json fieldswith--jq 'expr'when you need to process the result - •Use
--limit Non all list commands (default is usually 30, but be explicit) - •Use
--state open|closed|allto filter lists meaningfully
Creating resources:
- •PRs: Always include
--titleand--body. Write the body using a heredoc for multi-line content - •Issues: Always include
--titleand--body. Add--labeland--assigneewhen known - •Use
--assignee @mefor self-assignment
PR creation pattern:
# First confirm no PR exists for this branch gh pr list --head $(git branch --show-current) --json number --jq 'length' # If 0, create the PR gh pr create --title "Short descriptive title" --body "$(cat <<'EOF' ## Summary - What changed and why ## Test Plan - How to verify EOF )"
Mutations via gh api:
When gh subcommands don't cover an operation, use gh api as the escape hatch rather than raw curl:
gh api repos/OWNER/REPO/issues/123/comments -f body="Automated comment"
4. Output Handling
| Approach | When to Use |
|---|---|
--json fields --jq 'expr' | Default for agents. Structured, filtered to exactly what you need |
--json fields (no jq) | When you need the full JSON object for multi-step processing |
| No flags (default text) | Only for simple confirmations or when showing output to a human |
--web | When the user needs to interact in the browser (review UIs, settings) |
Counting results:
gh issue list --state open --json number --jq 'length'
Existence checks:
# Check if a PR exists for a branch (0 = no PR, >0 = PR exists) gh pr list --head my-branch --json number --jq 'length'
Extracting specific fields:
gh pr view 123 --json title,state,mergeable --jq '{title, state, mergeable}'
CLI Reference
| Platform | CLI | Reference |
|---|---|---|
| GitHub | gh | See references/gh-cli.md |
For any flag or subcommand not covered here, use gh <command> --help.
Common Mistakes
Creating duplicate PRs: Opening a new PR without checking if one already exists for the branch. This is the single most common agent mistake with the gh CLI.
Fix: Always run gh pr list --head BRANCH --json number before gh pr create. If results come back, view/update the existing PR instead.
Parsing unstructured output: Using the default text output and then trying to extract data from it with string manipulation.
Fix: Use --json fields --jq 'expr' for any output you need to process programmatically. The text format is for humans reading terminals.
Missing repo context: Running gh commands outside a git repo or against the wrong remote, getting confusing errors.
Fix: Start every session with gh repo view --json nameWithOwner to confirm the target repo. Use --repo OWNER/REPO when operating outside a repo directory.
Unbounded list output: Running gh pr list or gh issue list with no filters, dumping dozens of results into context.
Fix: Always use --limit N, --state, --search, and --json to narrow and structure results. Ask for only the fields you need.
Using curl instead of gh: Writing raw REST API calls with curl and manual auth headers when gh subcommands or gh api handle it natively.
Fix: Check gh <resource> --help first. If no subcommand exists, use gh api which handles auth and pagination automatically.