Machine output coverage

Which commands speak --json, which produce machine-readable output another way, and where a real gap remains — audited per command against the shipped command grammar, and machine-checked by the offline test suite so this page cannot silently rot when a command is added or gains a flag.

If you are scripting against SBOMFlow, start with the CLI overview's integration contract; this page is the per-command census behind it.

The machine interface, in order of authority#

  1. Artifacts on disk are the API. SBOMFlow's product is deterministic, versioned JSON files. A command that writes artifacts already has a machine interface — usually a richer one than any terminal flag could carry. sbomflow schema list names the families; sbomflow schema show <family> documents the fields offline.
  2. --json where operators read terminals. Read/status commands emit one pure, versioned JSON document on stdout (schema_version on every payload), with the same exit codes as the human output. Stdout stays pure: progress, notes and warnings go to stderr.
  3. Exit codes are a machine contract of their own. Every command's exit code follows the published exit-code reference, and errors carry stable [E0xx] codes in both text and JSON.
  4. A failed --json run still answers on stdout. When a command that took --json fails, the coded error is also emitted as a versioned sbomflow-cli-error-v1 document on stdout, carrying the [E0xx] code, the title, the detail, the repair, the docs link, the exit code and the retry/state-change semantics. A consumer therefore parses exactly one stream in success and in failure, and an empty stdout never has to be read as either. The stderr text is unchanged, and a command that already emits its own document on the failure path (validate --json prints its validate-report and then fails) keeps exactly that document — stdout never carries two.

A universal "result envelope" wrapping every command's stdout is deliberately not provided: artifacts on disk are the primary machine interface, and re-wrapping every command's output for symmetry would break existing consumers without serving a named need.

The census#

In this build the CLI grammar has 147 command paths (85 top-level commands + 62 nested verbs) — re-derived from the parser by the offline suite on every run, never carried forward from a previous release. Of these, 56 take --json, 2 are machine-native without a flag, 67 produce artifacts on disk as their machine interface, and 22 are human-only by design. The three audited gaps the first pass found are now closed, so no row is left verdicted add.

VerdictCountMeaning
has-json56Takes --json; one versioned JSON document on stdout.
machine-native2Machine output is already the default: JSON with no flag, or a CI-native format.
artifact-suffices67The command's product is deterministic files on disk (or an identical sibling surface already speaks --json); a terminal flag would duplicate the real interface.
human-only-by-design22Prose, interactive or dispatch surfaces for a person at a terminal; a machine consumer has no job here (14 of the 22 are bare group names that print usage).
add0A real machine-consumer job unserved by any surface. The audit found three; all three now ship the flag.

Every verdict below was audited against the command's implementation, not its help text: what it writes, what its exit code means, and which sibling command already serves the same data.

Where schema_version sits. Every --json payload carries it. Most payloads are JSON objects and carry it as a top-level key. Two — store list and store query — are JSON arrays, and their contract name rides on each element rather than in a wrapper: wrapping the array would break every consumer already parsing it, for a key those consumers do not read. upgrade plan and gate simulate shipped their version under a schema key before this promise was written; both now carry schema_version as well, with the same value, and the original key is unchanged.

The audited matrix#

<!-- JSON-COVERAGE:BEGIN — machine-checked against the shipped CLI grammar by the offline test suite. Every command path appears exactly once as the row's first backtick token; the verdict column uses only the five values defined above; a row's has-json verdict must match the real parser. Do not add, remove, or reword rows without re-running the suite. -->

CommandMachine output todayVerdictWhy
analyzeartifacts on diskartifact-sufficeswrites the full evidence artifact set (SBOM, findings, gaps, CRA report, gate…); the files are the API
annotateCI-native via --formatmachine-nativeits output IS a machine format: native CI annotations selected with --format (github, gitlab)
approve--jsonhas-jsonread/status surface; one versioned JSON document on stdout
audit--jsonhas-jsonread/status surface; one versioned JSON document on stdout
auditor-packartifacts on diskartifact-sufficeswrites auditor-pack.zip, a self-contained read-only package
backfill--jsonhas-jsonread/status surface; one versioned JSON document on stdout
batch-run--jsonhas-jsonone versioned batch summary on stdout; each job's own output is captured so the document stays parseable, and every row carries that job's warning count (with the line count it was taken out of) plus its declared network posture
bundleartifacts on diskartifact-sufficeswrites evidence-bundle.json / .zip, the portable reviewer handoff
caseusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
case accept-riskartifacts on diskartifact-sufficesappends the named human's bounded risk decision to the hash-chained case journal
case assignartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case communicateartifacts on diskartifact-sufficesdrafts, approves, or records delivery in the local communication journal; it never sends
case correlateartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case discloseartifacts on diskartifact-sufficesrecords a human disclosure-timeline event without publishing anything
case export-advisoryartifacts on diskartifact-sufficeswrites an unsigned, unsubmitted advisory draft
case intakeartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case openartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case propose-propagation--jsonhas-jsonemits a versioned proposal document with applied: false
case remediateartifacts on diskartifact-sufficesappends a remediation observation and its frozen-pack verification result
case show--jsonhas-jsonread/status surface; one versioned JSON document on stdout
case transitionartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case triageartifacts on diskartifact-sufficesappends JSON case records to a hash-chained journal; case show with --json is the read side
case reopenartifacts on diskartifact-sufficesappends the attributed advisory-reopen decision and transition to the hash-chained journal; no case is reopened automatically
cmake-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
compare-releasesartifacts on diskartifact-sufficeswrites release-drift.json
configusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
config show--jsonhas-jsonread/status surface; one versioned JSON document on stdout
cosign-verifyartifacts on diskartifact-sufficeswrites its verification observations JSON via --output
dashboardartifacts on diskartifact-sufficesrenders a static human dashboard from release-index.json, which is already the machine surface
decisionsusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
decisions quarantine--jsonhas-jsonmoves an unreadable decision journal under quarantine as an AUDITED event — the copy, its digest and the parse failure are appended before the original is unlinked, so an un-audited quarantine is unreachable; one versioned JSON document on stdout
decisions recover--jsonhas-jsonread/status surface; one versioned JSON document on stdout
decisions transactions--jsonhas-jsonread/status surface; one versioned JSON document on stdout
decisions verify-transactions--jsonhas-jsonread/status surface; one versioned JSON document on stdout
diffoscope-compareartifacts on diskartifact-sufficeswrites the diffoscope comparison observations JSON
doctor--jsonhas-jsonread/status surface; one versioned JSON document on stdout
elf-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
emit-user-infoartifacts on diskartifact-sufficeswrites the UNSIGNED CRA Annex II user-information draft files
esp-idf-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
examples--jsonhas-jsonread/status surface; one versioned JSON document on stdout
explaintext for humanshuman-only-by-designrenders a prose explanation composed from artifacts that are already machine-readable on disk
firmware-extractartifacts on diskartifact-sufficeswrites the bounded extraction inventory JSON
gateusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
gate simulate--jsonhas-jsonread/status surface; one versioned JSON document on stdout
help--jsonhas-jsonread/status surface; one versioned JSON document on stdout
indexusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
index query--jsonhas-jsonread/status surface; one versioned JSON document on stdout
index rebuildartifacts on diskartifact-sufficeswrites the derived SQLite index — itself a machine-queryable artifact (index query speaks --json)
index validate--jsonhas-jsonstructured errors/notes on stdout; the exit code is unchanged, so switching on --json cannot change the verdict
index-releasesartifacts on diskartifact-sufficeswrites release-index.json, the machine-readable cross-release index. A product entry also carries product_line when its releases declared one distinct from the product name; absent means no line was declared, never that grouping failed
ingest-grypeartifacts on diskartifact-sufficeswrites sourced-observation JSON artifacts
ingest-preserved-artifact--jsonhas-jsonpreserves one operator-selected artifact by identity and records what a human asserted about it; one versioned JSON document on stdout, never parsed, never a gate
ingest-sarifartifacts on diskartifact-sufficeswrites sourced-observation JSON artifacts
ingest-codex-security--jsonhas-jsonimports a sealed local Codex Security scan as external AI-assisted observations; one versioned JSON document on stdout, every record needs_review
ingest-trivyartifacts on diskartifact-sufficeswrites sourced-observation JSON artifacts
initartifacts on diskartifact-sufficesscaffolds sbomflow.yaml and inert review templates; the scaffolded files are the product
licenseusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
license inspect--jsonhas-jsonread/status surface; one versioned JSON document on stdout
license install--jsonhas-jsonverifies a delivered entitlement offline, then files it at the per-user discovery path; one versioned, non-secret JSON result on stdout (never the customer id, signature or entitlement id)
license status--jsonhas-jsonread/status surface; one versioned JSON document on stdout
license verify--jsonhas-jsonread/status surface; one versioned JSON document on stdout
linker-map-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
mcuboot-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
mcuboot-verifyartifacts on diskartifact-sufficeswrites its verification observations JSON via --output
mender-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
migrate-in--jsonhas-jsonone versioned migration manifest; every row carries claim_origin and unimported files are listed with reasons
next-actions--jsonhas-jsonone versioned next-actions document on stdout; aggregation only, never a decision
notifyartifacts on diskartifact-sufficeswrites the notification plan artifact; delivery is a separate explicit step
oci-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
passportusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
passport issueartifacts on diskartifact-sufficeswrites the signed passport files; passport verify (with --json) is the read side
passport verify--jsonhas-jsonread/status surface; one versioned JSON document on stdout
policyusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
policy diff--jsonhas-jsonread/status surface; one versioned JSON document on stdout
policy show--jsonhas-jsonread/status surface; one versioned JSON document on stdout
portfolioartifacts on diskartifact-sufficeswrites the cross-product portfolio index plus its dashboard. When the config declares products:[], the index also carries config_grouping: the operator's own group names joined to the product_ids their directories resolved to. Presentation only — it never changes identity, and a group whose outputs span two product identities is reported as spanning two rather than merged
prov-mapartifacts on diskartifact-sufficeswrites a deterministic PROV mapping JSON (file or stdout)
provenance-checkartifacts on diskartifact-sufficeswrites provenance-check observations JSON; expectations verdicts are in the artifact
quickstart--jsonhas-jsonone versioned JSON document on stdout (sbomflow-quickstart-preflight-v1, or sbomflow-quickstart-ci-preflight-v1 under --ci — two shapes, so two names). The RUN's machine interface is still the artifact set it writes; --json serves the pre-write disclosure instead — the same document the terminal form renders, so a caller reading JSON and a caller reading the terminal cannot reach different conclusions about the scan root, the bounded and labelled file count, or which of the five states the output directory is in. It emits that document and exits without writing, auditing or consenting
rauc-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
recheckartifacts on diskartifact-sufficeswrites the recheck report artifact comparing shipped evidence to newer local advisory data
release-chainusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
release-chain verify--jsonhas-jsonread/status surface; one versioned JSON document on stdout
reportusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
report freshness--jsonhas-jsonread/status surface; one versioned JSON document on stdout
reproducible-compareartifacts on diskartifact-sufficeswrites the digest-comparison JSON for two build trees
review--jsonhas-jsonread/status surface; one versioned JSON document on stdout
review-mergeartifacts on diskartifact-sufficeswrites the merged reviewer decision file plus a conflict report
review-viewartifacts on diskartifact-sufficeswrites reviewer.html, a human console composed from artifacts that are already machine-readable
schemausage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
schema list--jsonhas-jsonone versioned JSON document; exposing the flag revived a branch the parser could never reach
schema show--jsonhas-jsonread/status surface; one versioned JSON document on stdout
setuptext for humanshuman-only-by-designinteractive, TTY-gated onboarding; refuses CI and redirected IO by design
sign-bundleartifacts on diskartifact-sufficeswrites detached signature envelope files (formats: sbomflow, in-toto)
standards-view--jsonhas-jsonread/status surface; one versioned JSON document on stdout
regime-view--jsonhas-jsonread-only view of an existing verified pack through a versioned profile; one versioned JSON document on stdout
regime-profile--jsonhas-jsonlocal profile authoring kit; validate emits one versioned JSON document on stdout, and every action writes only profile files — never evidence
store reissue-plan--jsonhas-jsonread-only diagnosis of a refused export; one versioned JSON document on stdout
store reissueartifact-sufficeswrites a new release plus portable-reissue-receipt.json; human summary on stdout
storeusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
store addartifacts on diskartifact-sufficesrecords the release into the store (JSON records + index); store list / store show with --json are the read side
store empty-trash--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store export--jsonhas-jsonone versioned completeness manifest, also written to the export directory; reconciles against the store index. store_index_state records how much of that index was read, and complete can only be true when it is read
store list--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store query--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store register-rename--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store reindex--jsonhas-jsonrebuilds the deterministic index from canonical store-owned packs and reports every skipped input; prior_index_state says how much of the replaced index was read, and a prior index that will not parse is refused rather than rebuilt over
store retain--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store show--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store timeline--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store verify--jsonhas-jsonread/status surface; one versioned JSON document on stdout
store verify-replay--jsonhas-jsonreplays a stored release's recorded vulnerability inputs and reports whether each resolved to its exact recorded bytes; a recorded input it cannot find is reported as unavailable, never reproduced from whatever is current
store verify-gates--jsonhas-jsonread/status surface; one versioned JSON document on stdout
support-bundleartifacts on diskartifact-sufficeswrites the redaction-audited diagnostics zip; its contents are structured JSON
swupdate-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
syft-scanartifacts on diskartifact-sufficeswrites syft-result.json (file or stdout) as ingested observations
sync-dependencytrackartifacts on diskartifact-sufficesdry-run by default: writes the machine-readable sync plan artifact; delivery is a separate explicit step
sync-issuesartifacts on diskartifact-sufficesdry-run by default: writes the machine-readable sync plan artifact; delivery is a separate explicit step
sync-jiraartifacts on diskartifact-sufficesdry-run by default: writes the machine-readable sync plan artifact; delivery is a separate explicit step
sync-servicenowartifacts on diskartifact-sufficesdry-run by default: writes the machine-readable sync plan artifact; delivery is a separate explicit step
twister-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
update-manifest-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
upgradeusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
upgrade inspecttext for humanshuman-only-by-designpre-migration eyeball of artifact families/versions; the machine decision surface is upgrade plan with --json
upgrade migrate-copyartifacts on diskartifact-sufficeswrites migrated copies plus upgrade-manifest.json to a new directory, never in place
upgrade plan--jsonhas-jsonread/status surface; one versioned JSON document on stdout
upgrade validateartifacts on diskartifact-sufficesthe identical validation ships as top-level validate, which speaks --json with the same exit contract
uptane-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)
validate--jsonhas-jsonread/status surface; one versioned JSON document on stdout
validate-annexii-modelexit code + texthuman-only-by-designpackaged-model self-check; the machine contract is the exit code (0 pass, non-zero fail)
validate-article14-modelexit code + texthuman-only-by-designpackaged-model self-check; the machine contract is the exit code (0 pass, non-zero fail)
validate-configartifacts on diskartifact-sufficesthe same config validation surfaces machine-readably in doctor --json (config block: errors and warnings)
validate-graphexit code + texthuman-only-by-designpackaged-model self-check; the machine contract is the exit code (0 pass, non-zero fail)
validate-ssvc-modelexit code + texthuman-only-by-designpackaged-model self-check; the machine contract is the exit code (0 pass, non-zero fail)
validate-techdoc-modelexit code + texthuman-only-by-designpackaged-model self-check; the machine contract is the exit code (0 pass, non-zero fail)
verify-bundle--jsonhas-jsonverification detail, per-layer under --layered; parity with passport verify --json. Version skew stays context, changing no status and no exit code
verify-package-artifactsartifacts on diskartifact-sufficeswrites digest-verification observations JSON
vulndbusage onlyhuman-only-by-designgroup dispatcher: prints usage/guidance only; the machine surfaces are its nested verbs
vulndb change-impact--jsonhas-jsonexplains which stored releases a source-set change touches, reusing the release comparison already on disk; --store is required so the command can only emit the shape the schema registry declares
vulndb inspectJSON on stdout (no flag)machine-nativeprints its report as JSON on stdout with no flag needed
vulndb pinartifacts on diskartifact-sufficesrecords the active-snapshot pin; vulndb inspect is the JSON read side
vulndb reindexartifacts on diskartifact-sufficesrebuilds the derived index from complete snapshot manifests after index loss or corruption
vulndb retentionartifacts on diskartifact-sufficeswrites a deterministic needed-snapshots binding and conservative retention plan; deletion requires explicit --apply
vulndb sources--jsonhas-jsonread/status surface; lists the registered sources and what each one has ACTIVE locally
vulndb updateartifacts on diskartifact-sufficesrecords a pinned, hashed snapshot plus its manifest (the one explicit network step)
vulndb verify--jsonhas-jsonread/status surface; one versioned JSON document on stdout
zephyr-evidenceartifacts on diskartifact-sufficeswrites its deterministic evidence JSON (file or stdout)

<!-- JSON-COVERAGE:END -->

The three audited gaps — CLOSED#

Only three of the 123 non-dispatch paths audited in that pass were verdicted a real gap, all of them read-only verifiers or listings whose sibling commands already speak --json. All three now ship the flag, additively:

  • schema list — the machine-readable listing already existed internally, behind a flag the parser never declared, so the branch could not be reached. Declaring --json exposes the document and revives that dead branch.
  • index validate — integrity notes and errors are now a structured document. The exit code is unchanged, so a caller that switches on --json cannot get a different verdict from the one the text reported.
  • verify-bundle — verification detail, per-layer under --layered, at parity with passport verify --json. Version skew stays context: it appears in the document but changes no layer status and no exit code.

Human text, exit codes, and artifacts are byte-identical to before on every one of the three.

verify-bundle --layered: what a zero exit proves#

Every layered document carries exit_code_scope, and the human output prints the same sentence, because a consumer reading only one of the two must not have to find that boundary in prose somewhere else. Exit 0 proves that no layer failed and that every layer named by --require-layers reached a trusted status. It does not prove the bundle is trusted (read verdict / trusted_use), that an unrequired layer verified, that the evidence inside the bundle is correct, or anything at all about conformity.

--require-layers content,envelope,semantics,authority adds an expectation block — required, met, unmet, and a per-layer row carrying the observed status alongside the accepted_statuses that would have satisfied the requirement — and exits 7 when a well-formed report does not meet it. The full layer report is still emitted: an expectation narrows what the exit code means, never what the run reports. Without the flag the block is absent and every exit code is exactly what it was; a genuine verification failure stays 3 and outranks 7; an unknown layer name is refused as an input error (2) before verification runs, because a stricter check that silently did not happen is worse than no check. Nothing else on this page is a commitment to add flags; the remaining non---json rows are deliberate.

Doctor facts added by the same audit#

The same audit reviewed two outstanding doctor requests, and both shipped alongside it as facts-only additions — doctor reports local facts, fabricates nothing, and never decides:

  • offline docs availability — whether sbomflow help error and sbomflow help exit render from this install, with their code counts, and which web docs URLs error messages will print (recorded, never fetched).
  • path length — the absolute target path's length in characters and bytes next to the filesystem's own reported PATH_MAX / NAME_MAX limits, or an honest "not reported" where the platform has no answer.

See Troubleshooting for what doctor reports and why each row is context, never a verdict.