--json was passed. Nothing else — not the command, not the
platform — changes the shape, so a script can rely on the mode it selected.
Human output (a TTY)
When stdout is a terminal and--json was not passed, you get the rendering
built for eyes: aligned tables, color, unicode drawing (sparklines, bars),
relative timestamps, and a progress line on stderr while the CLI waits on
the API. Two things to know about it:
- It is not a parsing surface. The human layout is allowed to improve
between versions; anything that consumes output should use
--jsonor a pipe. - Color is opt-out. Setting
NO_COLORdisables ANSI styling even on a terminal.
Piped output (TSV records)
The moment stdout is a pipe, a redirect or a CI log, list commands drop the human layout and emit plain records — the gh-style contract a shell script can address without a JSON parser:- one row per record, cells joined by a single TAB —
| cut -f2addresses a column and| wc -lcounts records, on every list; - no header row, no count trailer, no blank lines, no empty-state prose — an empty result is zero bytes on stdout;
- whitespace inside a value (TABs, newlines) collapses to a single space, so
the column count per row is constant and the data can never break
cut; - each command group’s column order is frozen — it is a compatibility
contract, like
--jsonfield names — and the mention record clips its headline column to 72 characters regardless of the producing terminal’s width (or whether there was one), so a parser sees the same bytes at any width.
FORCE_COLOR does not change
that. A truthy FORCE_COLOR only lifts the piped-color guard the CLI
applies to upstream plugin output (the autocomplete setup instructions)
— the one surface that could otherwise colorize into a pipe. Prefer --json
for
structured consumption — the TSV form is the convenience contract for quick
shell composition:
The --json document
--json is the machine contract: exactly one JSON document on stdout and
nothing else — no banner, no color, no progress frames, ever. A failing
run exits non-zero with one error envelope on stderr and — with one
exception — leaves stdout empty; the exception is the live stream
(octolens feeds watch), which cannot retract records it has already
emitted, so it keeps them on stdout and appends a terminator record instead.
The full rules, including that stream’s NDJSON form, are on
The —json contract; what each command’s
document contains is the Returns section of its command page.
stderr keeps the same discipline: in a piped or --json run nothing is
written there on success, failures carry the error report, and --verbose
adds per-request diagnostics only when you ask for them.
--json also forces non-interactive mode: a --json run never prompts,
even on a real terminal. Anything a prompt would have collected must arrive
as a flag — which is the next section.
Headless
A run is headless when no human is attached to it: stdin or stdout is not a terminal (piped, redirected, CI), or--json was passed. This is the
one definition of the word across these docs — a prompt can only open in the
opposite case, an interactive run, where stdin and stdout are both a
terminal and --json is absent.
Headless is what the Required (headless) column in every flag table
refers to. On an interactive run the CLI can prompt for missing input, so
oclif-style hard requirements would get in a human’s way; headlessly there
is no prompt to fall back on, so:
yes (headless)— the flag must be passed on a headless run;one of (headless)— at least one flag of the named group must be passed;- a destructive command (the
rmfamily) requires its confirmation flag (--yes) headlessly, because the confirm prompt is unavailable there.
2 naming the flags to pass.