@cli/gh
@cli/gh — AI coding skill
| name | gh |
| description | Patterns for invoking the GitHub CLI (gh) from agents. Covers structured output, pagination, repo targeting, search vs list, gh api fallback. |
Reference
Interactivity policy
gh already does the right thing in non-TTY contexts: it skips the pager,
strips ANSI color, and errors out fast with a helpful message instead of
prompting (e.g. must provide --title and --body when not running interactively).
You don't need to defensively set GH_PAGER or pass --no-pager (no such
flag exists).
Parsing JSON
Human output from gh is column-formatted. If you want structured data:
- Add
--json field1,field2,...for structured output. - Run a command with
--jsonand no field list to print the full set of available fields, then pick what you need. - Use
--jq '<expr>'for filtering without piping through a separatejq. - Use
--template '<go-template>'(alongside--json) when you want shaped text output. Note that--template/-Tcollides with a body-template flag on a few commands (e.g.gh pr create -T,gh issue create -T); always check--helpbefore assuming which one you're hitting.
Pagination and silent truncation
List commands cap results.
gh issue list,gh pr list,gh search ...: pass-L N(--limit N). The default is usually 30.gh issue list/gh pr listdo not expose aggregate totals liketotalCountvia--json. If you need a true total, usegh api graphqlto querytotalCount; otherwise, treat-Las the cap for the current call.- For raw API calls use
gh api --paginate <path>. Combine with--jqand (optionally)--slurpto assemble one array.
Repo targeting
gh infers the repo from the cwd's git remotes.
Pass --repo OWNER/REPO (-R) to override the resolved CWD repo.
Search vs list
gh search issues|prs|code|repos|commits|usersuses GitHub's search index and accepts the full search syntax (is:open,author:,label:,repo:owner/name,in:title, ...). Pass each qualifier as its own bare token, not as one quoted string:gh search issues repo:cli/cli is:open author:monalisaworks, butgh search issues "repo:cli/cli is:open"is treated as a single keyword (parsed asrepo:"cli/cli is:open") and fails withInvalid search query. Quote only multi-word free text (gh search issues "broken feature"). Most qualifiers also have a dedicated flag (--repo,--author,--label, ...). Prefer search for anything cross-repo or filtered by author/label.gh issue list --search "..."andgh pr list --search "..."take the query as one quoted string (it is a flag value) and are scoped to one repo.- Bots author as GitHub Apps, so
--author dependabotmatches nothing. Use--app dependabot(onpr/issue listandsearch prs|issues; expands toauthor:app/<slug>) or--author "dependabot[bot]". gh search issuesalso takes--search-type <lexical|semantic|hybrid>(github.com/GHEC only, issues only): usesemanticwhen the user describes a problem in natural language rather than exact terms, andhybridto blend keyword and semantic ranking;lexical(default) is exact matching.
Issue types, sub-issues, and relationships
Newer gh issue subcommands model issue types, sub-issue hierarchy, and
blocked-by/blocking relationships.
gh issue create:--type <name>,--parent <number|url>(creates the new issue as a sub-issue),--blocked-by <number|url,...>,--blocking <number|url,...>.gh issue edit(edits one or more issues in the same repo, e.g.gh issue edit 23 34):--type <name>/--remove-type,--parent <n|url>/--remove-parent,--add-sub-issue <n,n>/--remove-sub-issue <n,n>,--add-blocked-by <n,n>/--remove-blocked-by <n,n>,--add-blocking <n,n>/--remove-blocking <n,n>. Relationship and parent refs are issue numbers or URLs; a URL may point to another repo on the same host, but a different host is rejected.--add-sub-issuecannot be used when editing more than one issue.gh issue list --type <name>filters by issue type.gh issue viewandgh issue listaccept these as--jsonfields (prefer them over scraping the default text output):issueType,parent,subIssues,subIssuesSummary,blockedBy,blocking.subIssues,blockedBy, andblockingare objects shaped{"nodes": [...], "totalCount": N}(not flat arrays), andnodesis capped (subIssuesat 100,blockedBy/blockingat 50), so compare the node count againsttotalCountto detect truncation.- GHES: issue types and sub-issues need 3.17+; blocked-by/blocking relationships need 3.19+.
Attaching images and videos
--attach <path> is available on gh issue create, gh issue edit,
gh issue comment, gh pr create, gh pr edit, and gh pr comment.
- Repeat
--attachto upload multiple files:gh issue comment 12 --attach ./before.png --attach ./after.png. - Each command invocation accepts at most 50
--attachvalues total across images and videos. - Supported files are
png,jpg,jpeg,gif,webp,svg,mp4,mov, andwebm. - For an image, append alt text to the path after
#. Quote the value so the shell does not treat#as a comment:gh pr create --attach './login.png#The login error state'. Without alt text, the filename is used. --attachpaths and local Markdown destinations may be absolute or relative to the directory whereghruns.- If the body references an attached path,
ghrewrites that Markdown reference to the uploaded URL. The reference keeps its existing alt text. Otherwise,ghappends the attachment to the body. For example:gh pr edit 23 --body '' --attach ./login.png. - Videos cannot take alt text. A standalone
becomes a bare player URL, while an inline video image becomes a link. A reference-style video image such as![recording][clip]with[clip]: ./repro.mp4is rejected; use a reference-style link instead. gh issue createandgh pr create:--attachcannot be used with--web.gh pr create --attachalso cannot be used with--dry-run.gh issue edit:--attachcan edit only one issue at a time.gh issue commentandgh pr comment:--attachcannot be used with--webor--delete-last. It works alone, with--edit-last, or with one of--body,--body-file, or--editor.- Uploads require GitHub.com or a GHE.com tenant, an OAuth token, classic PAT,
or fine-grained PAT, and
WRITE,MAINTAIN, orADMINrepository permission. GitHub Enterprise Server and GitHub App tokens are unsupported. - Uploads stop at the first failure. If earlier files uploaded,
ghstill writes those attachments and exits non-zero. Create and edit commands also print the issue or pull request URL.
Discussions (gh discussion)
Preview command set, subject to change. Subcommands:
gh discussion list [--state open|closed|all] [--category <name>] [--author <handle>] [--label <name>,...] [--answered] [--search <query>] [--sort created|updated] [--order asc|desc] [--limit N] [--after <cursor>] [--json <fields>] [--web]lists a repo's discussions.--statedefaults to open,--sortto updated,--orderto desc.--answeredis tri-state (--answered=falsefor unanswered) for Q&A categories.gh discussion view {<number>|<url>|<comment-id>|<comment-url>} [--comments] [--order oldest|newest] [--limit N] [--after <cursor>] [--json <fields>] [--web]shows a discussion's body; add--commentsfor its comments, or pass a comment ID/URL as the argument to list that comment's replies (no--repliesflag;--commentsis rejected with a comment argument).--order(default newest),--limit, and--afterapply only to comment and reply listings.gh discussion create [--title <t>] [--body <b> | --body-file <path>] [--category <name>] [--label <name>,...]creates a discussion.--title, a body (--bodyor--body-file), and--categoryare required non-interactively; omitting any will prompt on a terminal.gh discussion edit {<number>|<url>} [--title <t>] [--body <b>] [--body-file <path>] [--category <name>] [--add-label <name>,...] [--remove-label <name>,...]edits title, body, category, or labels.gh discussion comment {<number>|<discussion-url>|<comment-id>|<comment-url>} [--body <b>] [--body-file <path>] [--edit] [--delete] [--yes]adds a top-level comment (when given a discussion) or a reply (when given a comment);--editor--deleteupdates or removes a comment/reply and needs a comment ID or URL.--yesskips the--deleteconfirmation.--json/--jq/--templateare available onlistandviewonly;createandeditprint the discussion URL.commentprints the discussion comment (or reply) URL.
Reading files and directories (gh repo read-file / read-dir)
Preview commands, subject to change. They read a repo's contents over the API
without cloning, and honor --repo OWNER/REPO (-R) and --ref <branch|tag|commit>
(default branch when omitted).
gh repo read-file <path> [--ref <ref>] [--output <path> [--clobber]] [--allow-escape-sequences] [--json <fields>] [--jq <expr>]prints a file's contents. In non-TTY contexts the raw bytes go straight to stdout (pipe-friendly); binary files are written as-is when piped but are refused on a TTY. By default, a file containing terminal escape sequences is refused; pass--allow-escape-sequencesto read it anyway.--output <path>(-o) writes to disk instead of stdout (a trailing slash writes under a directory using the remote file name;--clobberallows overwrite); writing to disk always includes the raw bytes regardless of escape sequences.--outputand--jsonare mutually exclusive.--jsonfields includename,path,gitSHA,size,type,encoding, andcontent(base64 encoded).gh repo read-dir [<path>] [--ref <ref>] [--json <fields>] [--jq <expr>]lists a directory; with no path it lists the repo root. Non-TTY output is tab separated as type, name, octal mode, and byte size.--jsonfields includename,path,type,gitType,mode,modeOctal,gitSHA,size, andsubmodule. A path pointing at a file errors and points you atread-file(and vice versa).
Fall back to gh api for anything --json doesn't expose
Sometimes useful data isn't on the typed commands. Examples:
- Review-thread comments on a PR:
gh api repos/{owner}/{repo}/pulls/{n}/comments(the--commentsflag ongh pr viewshows issue-level comments only). - Arbitrary GraphQL:
gh api graphql -f query='...' -F var=value. - REST shortcuts:
gh api repos/{owner}/{repo}/...- note the{owner}/{repo}placeholder is filled in for you when run from a repo with detected remotes; pass them literally if you want determinism.
Authentication
gh auth statusprints the active host(s), user, and which env var (if any) is being honored.gh auth status --jsonis supported.
Other notes
gh pr checkout <n>switches branches. Usegh pr diff <n>orgh pr view <n>if you only need to read.gh pr checkout <n> --worktree <path>checks the PR out into a git worktree at<path>instead of switching the current branch.gh issue develop <n> --checkoutcreates a linked branch for the issue and checks it out. Add--worktree <path>to check that branch out into a git worktree at<path>instead of switching the current branch;--worktreerequires--checkout, cannot be blank, and cannot be combined with--list.NO_COLOR,CLICOLOR_FORCE, andGH_FORCE_TTYare honored. SetGH_FORCE_TTY=1if you want TTY-style output (colors, tables, the pager, interactivity) inside an agent harness; leave it unset unless needed.
Loading...
Select a file to preview
Analyzing security...
Checking scan reports and verification data.
Bill of Materials
Everything this skill can do — files, network, commands, and more.