Output formats
Cards, JSON, markdown, --copy, --compact, --verbose — every way CommitBrief renders review findings.
CommitBrief renders review findings in three primary forms. The choice is driven by global output flags; if none are set and the destination is a TTY, the colored cards renderer is the default.
Cards (default TTY)
Lipgloss-styled header / status / footer with one panel per finding. Each panel is severity-coded (color of the left border) and includes the finding’s title, location, description, suggestion, and a code snippet when present.
Triggered when: TTY stdout AND no --json / --markdown flag
AND --color resolves to ON.
This is the format you see in your terminal during a normal
commitbrief --staged session. The output is not designed to be
parsed; it is designed to be read.
Markdown
Plain markdown — no ANSI escapes, no lipgloss boxes. The same finding content rendered through the OUTPUT.md template (or its embedded default).
Triggered by --markdown, by --color=never, or by a non-TTY
stdout. The bare commitbrief --staged > review.md path also
produces markdown.
The template has access to .Findings (typed
[]Finding{Severity, File, Line, LineEnd, Title, Description, Suggestion, Language, Snippet}) plus helpers like
groupBySeverity, upper, countFiles. See
OUTPUT.md for the template
reference.
JSON (schema v1)
Strict machine-readable form. Top-level shape:
{
"schema": 1,
"content": "",
"findings": [
{
"severity": "high",
"file": "internal/handlers/auth.go",
"line": 42,
"line_end": 56,
"title": "Missing authorization check on admin route",
"description": "...",
"suggestion": "...",
"language": "go",
"snippet": "..."
}
],
"summary": {},
"meta": {
"provider": "anthropic",
"model": "claude-opus-5-5",
"lang": "en",
"usage": { "input_tokens": 2105, "output_tokens": 526, "cached_input_tokens": 0 },
"cost_usd": 0.0237,
"latency_ms": 4123,
"cached": false,
"timestamp": "2026-07-26T12:00:00Z"
}
}
Triggered by --json. Bypasses cards / markdown renderers
entirely. schema is the integer 1 — not the string "v1" —
and follows strict semver: additive changes (new optional fields)
are allowed within the same schema major version; renames,
removals, or type changes require a schema major bump. summary
is a reserved placeholder and is always {} in v1; there is no
per-severity count anywhere in the document except by counting
findings[] yourself.
Field reference
Every top-level and required field in schema v1. The five
additive-optional meta fields below this table are covered in
Optional meta fields — they’re all
omitempty and only appear when they have something to report.
Top-level document
| Field | Type | Required? | Meaning |
|---|---|---|---|
schema | integer | required | Always 1 in schema v1.x. Parse this field first; refuse a document reporting a version you don’t understand. |
content | string | required | Empty on the happy path. Populated with the raw model response only when the review gracefully degrades (unparseable structured output). Vestigial — slated for removal in schema v2. |
findings | array of Finding | required | [], never null, on a clean or degraded review. Unfiltered: --min-severity never touches this array. |
summary | object | required | Always {} in v1. Reserved for a future model-authored prose summary. |
meta | object | required | Provider, cost, and timing metadata — see below. |
findings[] item (Finding)
| Field | Type | Required? | Meaning |
|---|---|---|---|
severity | string | required | One of critical, high, medium, low, info. |
file | string | required | Repo-relative path. |
line | integer | required | 1-based start line. |
line_end | integer | optional | Present only when the finding spans more than one line. |
title | string | required | One sentence. |
description | string | required | 1–3 sentences: the issue and its impact. |
suggestion | string | required | 2–3 sentence concrete fix. An empty suggestion triggers the retry-then-degrade path rather than shipping. |
language | string | optional | Present when the finding’s language is known. |
snippet | string | optional | Verbatim diff excerpt, ≤6 lines, diff-prefixed. Always omitted for a leaks credential finding — populating it would echo the secret. |
meta — base fields
| Field | Type | Required? | Meaning |
|---|---|---|---|
provider | string | required | e.g. anthropic. builtin for a leaks --json report — no model was called. |
model | string | required | e.g. claude-opus-5-5. secret-scan for leaks. |
lang | string | required | Output language code. |
usage.input_tokens | integer | required | 0, never omitted, on a cache hit or when the provider doesn’t report usage. |
usage.output_tokens | integer | required | Same 0-not-null rule as input_tokens. |
usage.cached_input_tokens | integer | required | Same 0-not-null rule. |
cost_usd | number | required | 0 on a cache hit, for Ollama, and for any CLI-tool-backed provider. |
latency_ms | integer | required | Call latency in milliseconds. |
cached | boolean | required | Whether this document is a cache replay rather than a live call. |
timestamp | string | required | RFC 3339. |
Optional meta fields
Every field below is omitempty: it is absent unless it has
something to report, so a clean review’s JSON is byte-for-byte
what it was before these shipped, and the schema stays 1.
| Field | Requires | Meaning |
|---|---|---|
meta.baselined | Requires v1.8.0 or later | Findings removed by the baseline. |
meta.suppressed | Requires v1.8.0 or later | Findings removed by an inline commitbrief-ignore. |
meta.retry_count | Requires v1.13.0 or later | How many structured-output repair retries the call needed. Live calls only — a cache replay reports neither this nor degrade_reason. |
meta.degrade_reason | Requires v1.13.0 or later | Why the pipeline fell back to plain markdown, when it did (e.g. malformed-json). |
meta.filtered_commits | Requires v1.15.0 or later | How many commits’ patches make up the reviewed diff, when a commit filter walked history. |
--verbose surfaces retry_count and degrade_reason as two
footer lines as well, which is what makes retries and degrades
comparable across models.
A leaks --json report uses this same document
with meta.provider: "builtin" and cost_usd: 0 — there was no
model call — which is why guard --from-json consumes it without
any new plumbing.
CLI-tool-backed providers — plain text passthrough
claude-cli, gemini-cli, and codex-cli emit pre-formatted plain
text from the host CLI, not structured findings. The cards renderer is
skipped; the host CLI’s output is streamed verbatim to stdout (or
to --output <file>). --json and --markdown are rejected
upfront when paired with a CLI provider — cobra error before any
work runs. See CLI providers.
Output destinations
| Flag | Effect |
|---|---|
--output <path> (-o) | Write the rendered output to a file. Applies to cards, markdown, JSON, AND plain-text emit (CLI providers). |
--copy | Copy a finding summary to the system clipboard via OSC 52 (works over SSH) plus native tools (pbcopy / wl-copy / xclip / xsel / clip.exe). Payload format per finding: [<icon> <SEVERITY>] <path>:<line>\n<title>\n\n<description>\n\n→ <suggestion>, joined with \n---\n\n. Description and suggestion are flattened to single paragraphs and the diff snippet is left out. |
--compact | Dense one-line-per-finding output: [icon] SEVERITY • file:line — title. Works in cards and markdown modes. |
--min-severity <level> | Display-only filter: hide findings below <level> in the rendered output (cards, markdown, --copy). --json stays complete and --fail-on still evaluates the full set. See Severity. |
--verbose (-v) | Append a footer with provider / model / tokens / cost / latency. |
--quiet (-q) | Suppress stderr info messages (progress, rule-source hints). |
--json is a renderer choice, not a destination choice;
the JSON still goes to stdout (or --output <file>). Combine
flags freely:
commitbrief --staged --json --output review.json --quiet
Color resolution
Default --color=auto:
- TTY stdout + no
NO_COLORenv + noCOMMITBRIEF_NO_COLORenv +TERMnot set todumb→ color ON. - Otherwise → color OFF.
--color=always forces ON, except that NO_COLOR /
COMMITBRIEF_NO_COLOR still turn color off (TERM=dumb does not
override it); --color=never forces OFF
unconditionally. Color OFF in cards mode falls back to markdown.
Suggesting a commit message
--suggest-commit adds a second step after the review: a free-form
provider call that prints one Conventional Commit message for
the staged diff to stdout.
commitbrief --staged --suggest-commit
- Read-only. It suggests; you commit. CommitBrief never writes to git or the working tree.
- Staged scope only. Works with
--stagedor the default run; rejected with--unstaged, thediffsubcommand, and with--json/--markdown/--output(the suggestion is plain stdout, not part of the structured or file output). - Any provider. API providers return the message via a free-form path (no JSON contract for this one call); CLI-tool providers emit it directly.
- The message follows Conventional Commits (
type(scope): subjectplus an optional body). YourCOMMITBRIEF.mdrules govern the critique, not the message wording. - The suggestion is a fresh call each run (not cached); the review itself still uses the cache.
Splash logo
The colored splash logo prints to stderr at the start of every
invocation, gated on a TTY-capable stderr. It is NOT part of
stdout — commitbrief --json | jq and commitbrief > out stay
clean. To suppress it entirely, set NO_COLOR=1 in the
environment.
See also
- Severity and CI gating — what severity
values can appear and how
--fail-onmaps them to exit codes. - Review rules — how OUTPUT.md shapes the markdown form.
- Providers — which providers support which formats.