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
--json and 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 separate jq.
- Use
--template '<go-template>' (alongside --json) when you want shaped
text output. Note that --template/-T collides with a body-template flag
on a few commands (e.g. gh pr create -T, gh issue create -T); always
check --help before 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 list do not expose aggregate totals like
totalCount via --json. If you need a true total, use gh api graphql
to query totalCount; otherwise, treat -L as the cap for the current call.
- For raw API calls use
gh api --paginate <path>. Combine with
--jq and (optionally) --slurp to 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|users uses 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:monalisa works, but
gh search issues "repo:cli/cli is:open" is treated as a single keyword (parsed as repo:"cli/cli is:open")
and fails with Invalid 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 "..." and gh 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 dependabot matches nothing. Use
--app dependabot (on pr/issue list and search prs|issues; expands
to author:app/<slug>) or --author "dependabot[bot]".
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-issue cannot be used
when editing more than one issue.
gh issue list --type <name> filters by issue type.
gh issue view and gh issue list accept these as --json fields (prefer
them over scraping the default text output): issueType, parent,
subIssues, subIssuesSummary, blockedBy, blocking. subIssues,
blockedBy, and blocking are objects shaped
{"nodes": [...], "totalCount": N} (not flat arrays), and nodes is capped
(subIssues at 100, blockedBy/blocking at 50), so compare the node count
against totalCount to detect truncation.
- GHES: issue types and sub-issues need 3.17+; blocked-by/blocking
relationships need 3.19+.
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. --state defaults to open, --sort to updated,
--order to desc. --answered is tri-state (--answered=false for
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 --comments for its comments, or pass a
comment ID/URL as the argument to list that comment's replies (no
--replies flag; --comments is rejected with a comment argument).
--order (default newest), --limit, and --after apply 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 (--body or --body-file), and
--category are 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); --edit or --delete updates or removes a comment/reply and
needs a comment ID or URL. --yes skips the --delete confirmation.
--json/--jq/--template are available on list and view only;
create and edit print the discussion URL. comment prints 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-sequences to read it anyway. --output <path> (-o) writes to
disk instead of stdout (a trailing slash writes under a directory using the
remote file name; --clobber allows overwrite); writing to disk always
includes the raw bytes regardless of escape sequences. --output and --json are
mutually exclusive. --json fields include name, path, gitSHA, size,
type, encoding, and content (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. --json fields include
name, path, type, gitType, mode, modeOctal, gitSHA, size, and
submodule. A path pointing at a file errors and points you at read-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 --comments flag on gh pr view shows 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 status prints the active host(s), user, and which env var (if
any) is being honored.
gh auth status --json is supported.
Other notes
gh pr checkout <n> switches branches. Use gh pr diff <n> or
gh pr view <n> if you only need to read.
NO_COLOR, CLICOLOR_FORCE, and GH_FORCE_TTY are honored. Set
GH_FORCE_TTY=1 if you want TTY-style output (colors, tables, the
pager, interactivity) inside an agent harness; leave it unset unless needed.
1---2name: gh3description: Patterns for invoking the GitHub CLI (gh) from agents. Covers structured output, pagination, repo targeting, search vs list, gh api fallback.4---56# Reference78## Interactivity policy910`gh` already does the right thing in non-TTY contexts: it skips the pager,11strips ANSI color, and errors out fast with a helpful message instead of12prompting (e.g. `must provide --title and --body when not running interactively`).13You don't need to defensively set `GH_PAGER` or pass `--no-pager` (no such14flag exists).1516## Parsing JSON1718Human output from `gh` is column-formatted. If you want structured data:1920- Add `--json field1,field2,...` for structured output.21- Run a command with `--json` and **no field list** to print the full set of22 available fields, then pick what you need.23- Use `--jq '<expr>'` for filtering without piping through a separate `jq`.24- Use `--template '<go-template>'` (alongside `--json`) when you want shaped25 text output. Note that `--template`/`-T` collides with a body-template flag26 on a few commands (e.g. `gh pr create -T`, `gh issue create -T`); always27 check `--help` before assuming which one you're hitting.2829## Pagination and silent truncation3031List commands cap results.3233- `gh issue list`, `gh pr list`, `gh search ...`: pass `-L N` (`--limit N`).34 The default is usually 30.35- `gh issue list` / `gh pr list` do not expose aggregate totals like36 `totalCount` via `--json`. If you need a true total, use `gh api graphql`37 to query `totalCount`; otherwise, treat `-L` as the cap for the current call.38- For raw API calls use `gh api --paginate <path>`. Combine with39 `--jq` and (optionally) `--slurp` to assemble one array.4041## Repo targeting4243`gh` infers the repo from the cwd's git remotes. 4445Pass `--repo OWNER/REPO` (`-R`) to override the resolved CWD repo.4647## Search vs list4849- `gh search issues|prs|code|repos|commits|users` uses GitHub's search50 index and accepts the full search syntax (`is:open`, `author:`,51 `label:`, `repo:owner/name`, `in:title`, ...). Pass each qualifier as52 its own bare token, not as one quoted string:53 `gh search issues repo:cli/cli is:open author:monalisa` works, but54 `gh search issues "repo:cli/cli is:open"` is treated as a single keyword (parsed as `repo:"cli/cli is:open"`)55 and fails with `Invalid search query`. Quote only multi-word free text56 (`gh search issues "broken feature"`). Most qualifiers also have a57 dedicated flag (`--repo`, `--author`, `--label`, ...). Prefer search for58 anything cross-repo or filtered by author/label.59- `gh issue list --search "..."` and `gh pr list --search "..."` take the60 query as one quoted string (it is a flag value) and are scoped to one repo.61- Bots author as GitHub Apps, so `--author dependabot` matches nothing. Use62 `--app dependabot` (on `pr`/`issue list` and `search prs|issues`; expands63 to `author:app/<slug>`) or `--author "dependabot[bot]"`.6465## Issue types, sub-issues, and relationships6667Newer `gh issue` subcommands model issue types, sub-issue hierarchy, and68blocked-by/blocking relationships.6970- `gh issue create`: `--type <name>`, `--parent <number|url>` (creates the71 new issue as a sub-issue), `--blocked-by <number|url,...>`, `--blocking <number|url,...>`.72- `gh issue edit` (edits one or more issues in the same repo, e.g.73 `gh issue edit 23 34`): `--type <name>` / `--remove-type`,74 `--parent <n|url>` / `--remove-parent`,75 `--add-sub-issue <n,n>` / `--remove-sub-issue <n,n>`,76 `--add-blocked-by <n,n>` / `--remove-blocked-by <n,n>`,77 `--add-blocking <n,n>` / `--remove-blocking <n,n>`. Relationship and parent78 refs are issue numbers or URLs; a URL may point to another repo on the same79 host, but a different host is rejected. `--add-sub-issue` cannot be used80 when editing more than one issue.81- `gh issue list --type <name>` filters by issue type.82- `gh issue view` and `gh issue list` accept these as `--json` fields (prefer83 them over scraping the default text output): `issueType`, `parent`,84 `subIssues`, `subIssuesSummary`, `blockedBy`, `blocking`. `subIssues`,85 `blockedBy`, and `blocking` are objects shaped86 `{"nodes": [...], "totalCount": N}` (not flat arrays), and `nodes` is capped87 (`subIssues` at 100, `blockedBy`/`blocking` at 50), so compare the node count88 against `totalCount` to detect truncation.89- GHES: issue types and sub-issues need 3.17+; blocked-by/blocking90 relationships need 3.19+.9192## Discussions (`gh discussion`)9394Preview command set, subject to change. Subcommands:9596- `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]`97 lists a repo's discussions. `--state` defaults to open, `--sort` to updated,98 `--order` to desc. `--answered` is tri-state (`--answered=false` for99 unanswered) for Q&A categories.100- `gh discussion view {<number>|<url>|<comment-id>|<comment-url>} [--comments] [--order oldest|newest] [--limit N] [--after <cursor>] [--json <fields>] [--web]`101 shows a discussion's body; add `--comments` for its comments, or pass a102 comment ID/URL as the argument to list that comment's replies (no103 `--replies` flag; `--comments` is rejected with a comment argument).104 `--order` (default newest), `--limit`, and `--after` apply only to comment105 and reply listings.106- `gh discussion create [--title <t>] [--body <b> | --body-file <path>] [--category <name>] [--label <name>,...]`107 creates a discussion. `--title`, a body (`--body` or `--body-file`), and108 `--category` are required non-interactively; omitting any will prompt on a109 terminal.110- `gh discussion edit {<number>|<url>} [--title <t>] [--body <b>] [--body-file <path>] [--category <name>] [--add-label <name>,...] [--remove-label <name>,...]`111 edits title, body, category, or labels.112- `gh discussion comment {<number>|<discussion-url>|<comment-id>|<comment-url>} [--body <b>] [--body-file <path>] [--edit] [--delete] [--yes]`113 adds a top-level comment (when given a discussion) or a reply (when given a114 comment); `--edit` or `--delete` updates or removes a comment/reply and115 needs a comment ID or URL. `--yes` skips the `--delete` confirmation.116- `--json`/`--jq`/`--template` are available on `list` and `view` only;117 `create` and `edit` print the discussion URL. `comment` prints the discussion comment (or reply) URL.118119## Reading files and directories (`gh repo read-file` / `read-dir`)120121Preview commands, subject to change. They read a repo's contents over the API122without cloning, and honor `--repo OWNER/REPO` (`-R`) and `--ref <branch|tag|commit>`123(default branch when omitted).124125- `gh repo read-file <path> [--ref <ref>] [--output <path> [--clobber]] [--allow-escape-sequences] [--json <fields>] [--jq <expr>]`126 prints a file's contents. In non-TTY contexts the raw bytes go straight to127 stdout (pipe-friendly); binary files are written as-is when piped but are128 refused on a TTY. By default, a file containing terminal escape sequences is129 refused; pass `--allow-escape-sequences` to read it anyway. `--output <path>` (`-o`) writes to130 disk instead of stdout (a trailing slash writes under a directory using the131 remote file name; `--clobber` allows overwrite); writing to disk always132 includes the raw bytes regardless of escape sequences. `--output` and `--json` are133 mutually exclusive. `--json` fields include `name`, `path`, `gitSHA`, `size`,134 `type`, `encoding`, and `content` (base64 encoded).135- `gh repo read-dir [<path>] [--ref <ref>] [--json <fields>] [--jq <expr>]`136 lists a directory; with no path it lists the repo root. Non-TTY output is tab137 separated as type, name, octal mode, and byte size. `--json` fields include138 `name`, `path`, `type`, `gitType`, `mode`, `modeOctal`, `gitSHA`, `size`, and139 `submodule`. A path pointing at a file errors and points you at `read-file`140 (and vice versa).141142## Fall back to `gh api` for anything `--json` doesn't expose143144Sometimes useful data isn't on the typed commands. Examples:145146- Review-thread comments on a PR: `gh api repos/{owner}/{repo}/pulls/{n}/comments`147 (the `--comments` flag on `gh pr view` shows issue-level comments only).148- Arbitrary GraphQL: `gh api graphql -f query='...' -F var=value`.149- REST shortcuts: `gh api repos/{owner}/{repo}/...` - note the150 `{owner}/{repo}` placeholder is filled in for you when run from a repo151 with detected remotes; pass them literally if you want determinism.152153## Authentication154155- `gh auth status` prints the active host(s), user, and which env var (if156 any) is being honored.157- `gh auth status --json` is supported.158159## Other notes160161- `gh pr checkout <n>` switches branches. Use `gh pr diff <n>` or162 `gh pr view <n>` if you only need to read.163- `NO_COLOR`, `CLICOLOR_FORCE`, and `GH_FORCE_TTY` are honored. Set164 `GH_FORCE_TTY=1` if you want TTY-style output (colors, tables, the165 pager, interactivity) inside an agent harness; leave it unset unless needed.