Search

Search the docs, blog, and marketplace.

Getting started

Output formats

Text, JSON, SARIF, and SBOM artifacts — when to use each and how to combine them.

Last updated July 30, 2026View source (v0.21.1)

Bomly writes one primary stdout output and any number of additional outputs in the same run.

Primary output: --format

Use --json as a shortcut for --format json when you want structured output quickly.

FormatDefault forWhen to use
textLocal runs, --interactiveReading on a terminal
jsonAutomationPipelines, custom dashboards, anything consumed by code
markdownReviewsJob summaries, PR comments, and other Markdown surfaces
sarifAudit-onlyCI security panes, GitHub Security tab, IDE problem markers
spdxScan onlySPDX 2.3 JSON SBOMs
cyclonedxScan onlyCycloneDX 1.7 JSON SBOMs

Flag:

bomly scan --format text     # default
bomly scan --json
bomly explain lodash --format markdown
bomly diff --base main --head HEAD --format markdown
bomly scan --audit --format sarif
bomly scan --format spdx

Constraints:

  • --format sarif requires --audit. SARIF is a findings format; without an auditor there are no findings.
  • --format spdx and --format cyclonedx are supported by scan only.
  • --interactive forces --format text. Combining it with --json or another non-text reporting format is rejected with exit 4.

text — human-readable

The default. Groups packages by ecosystem and edge depth, summarizes finding counts by severity, and links to the explain path for any flagged package. With --enrich, it adds a short remediation summary directly below the enrichment line and points to JSON for the details. The summary counts only concrete fix suggestions; manual review, unknown fix evidence, and packages with no available fix do not inflate the count. Color and box-drawing are auto-disabled when stdout is not a TTY.

bomly scan --enrich --audit
✓ 68 packages in 1 manifest   (1 direct, 67 transitive · runtime 68, dev 0)

✓ Enriched via Grype, deps.dev License Matcher

✓ 7 fix suggestions for 7 of 7 vulnerable packages.
  Run again with --format json to see remediation details.

Top-level dependencies
  NAME      VERSION   LICENSE   SCOPE     VULNS
  express   4.19.2    MIT       runtime   1L

Findings
  [HIGH]      GHSA-37ch-88jc-xwx2  path-to-regexp@0.1.7
  [HIGH]      GHSA-9wv6-86v2-598j  path-to-regexp@0.1.7
  [HIGH]      GHSA-qwcr-r2fm-qrc7  body-parser@1.20.2
  [HIGH]      GHSA-rhx6-c78j-4q9w  path-to-regexp@0.1.7

Markdown reports include the same remediation summary and the complete suggestion table.

json — structured

The shape every Bomly subcommand emits. Each command has its own schema:

CommandSchema
bomly scanscan.md
bomly explainexplain.md
bomly diffdiff.md

bomly scan surfaces the three-collection model (see Architecture → Domain model): manifests[].dependencies are lean detection-stage nodes (identity, scopes, depends_on, package_ref); packages is the deduplicated matching-stage registry (licenses, vulnerabilities, scorecard, EOL, CPEs, digests) keyed by PURL; and findings is the reference-style audit output. Resolve a finding or a dependency to its enrichment by matching package_ref/package.purl into packages.

For remediation suggestions, affected_dependency_refs names occurrences of the vulnerable package. suggested_action_dependency_ref names the dependency or manifest anchor that the suggested action targets. These can differ for a transitive package.

Pipe into jq for common queries:

# Every package with a high-or-critical vulnerability
bomly scan --enrich --json | jq '
  .packages[]
  | select(.vulnerabilities[]? | .severity == "high" or .severity == "critical")
  | {name, version, ecosystem}
'

# All transitive paths to a specific dependency
bomly explain lodash --json | jq '.paths[] | .nodes | map(.name) | join(" -> ")'

# New findings introduced by a PR
bomly diff --base main --head HEAD --enrich --audit --json | jq '.findings.introduced[]'

The first query against a project pinning express@4.19.2 (first two of several matches shown):

{
  "name": "body-parser",
  "version": "1.20.2",
  "ecosystem": "npm"
}
{
  "name": "path-to-regexp",
  "version": "0.1.7",
  "ecosystem": "npm"
}

JSON output includes Bomly-specific metadata that standard SBOM formats don't carry: reachability tier/status/confidence, audit reasons, and per-finding source.

bomly explain returns every deterministic root-to-target path, not only a shortest or representative path. Paths are ordered by their stable package-ID sequence, and cyclic paths are explicitly marked. This preserves alternate workspace and duplicate-version routes that can require different investigation.

bomly diff classifies an audit finding by its stable advisory/package identity, independent of a package version bump. A finding present on both sides is persisted; it is not reported as one resolved finding plus one introduced finding merely because the affected package version changed.

Dependency changes are split into separate kinds. A version change says that the package release changed. A detail change says that the same package occurrence changed in one of these ways:

  • its relationship changed between direct, transitive, and unknown;
  • its source changed, such as registry to Git or workspace;
  • its eligibility for registry matching changed.

A dependency can have both a version change and a detail change in the same diff. Structured output calls each detail-change record a transition. JSON keeps the before and after evidence under results.dependencies.transitions and under the matching manifest. Text, Markdown, the interactive view, and MCP show the same classification.

Human-readable output asks for extra review when a known source changes to Git or a URL, or when vulnerability checks covered the dependency before the change but no longer do. Other detail changes remain informational. These labels help reviewers find important changes; by themselves, they do not change the command's exit status.

sarif — CI security tools

SARIF 2.1.0. Findings only. One result per (rule × package) pair. Includes:

  • Finding ID as the rule ID (CVE / GHSA / OSV identifier).
  • Severity mapped to SARIF level (error for critical/high, warning for medium, note for low/unknown).
  • Locations populated with manifest file paths when known.
  • Bomly-specific reachability and policy metadata in the properties bag.
bomly scan --enrich --audit --fail-on high --format sarif > bomly.sarif
Sample result object (one finding, properties trimmed)
{
  "ruleId": "GHSA-m6fv-jmcg-4jfg",
  "level": "error",
  "message": {
    "text": "send vulnerable to template injection that can lead to XSS in pkg:npm/send@0.18.0"
  },
  "locations": [
    {
      "physicalLocation": {
        "artifactLocation": { "uri": "package-lock.json" },
        "region": { "startLine": 636 }
      }
    }
  ],
  "properties": {
    "package_ref": "pkg:npm/send@0.18.0",
    "fixed_in": "0.19.0",
    "fix_state": "fixed"
  }
}

Locations point at the lockfile line that pins the vulnerable version, so code-scanning annotations land somewhere actionable.

GitHub Code Scanning, Azure DevOps, and most IDE extensions ingest SARIF directly. See CI integration for upload recipes.

Additional output: -o

-o uses the same format names as --format, plus an optional file path. Use <format>=<path> to write to a file, or just <format> to write that additional output to stdout. When every -o names a file and --format is not set, a successful run writes the files silently — pass --format text (or any primary format) if you also want stdout output.

bomly scan --json \
  -o text=summary.txt \
  -o markdown=summary.md \
  -o sarif=bomly.sarif \
  -o spdx=sbom.spdx.json \
  -o cyclonedx=sbom.cdx.json

Supported targets:

-o valueFormat
textHuman-readable terminal report
jsonStructured Bomly JSON report
markdownGitHub-flavored Markdown report
sarifSARIF 2.1.0 report; requires --audit
spdxSPDX 2.3 JSON
cyclonedxCycloneDX 1.7 JSON

spdx and cyclonedx are supported by scan. Report formats (text, json, markdown, sarif) are supported by report-producing commands. See SBOM formats for the SBOM comparison and writing rules.

Combining outputs

A single scan can produce:

  • A human report on stdout.
  • A JSON document written to a file.
  • A SARIF document for a CI panel.
  • One or more SBOM artifacts.

Example:

bomly scan --enrich --audit --fail-on high \
  --format text \
  -o json=bomly.json \
  -o sarif=bomly.sarif \
  -o spdx=sbom.spdx.json \
  -o cyclonedx=sbom.cdx.json

--format text keeps the terminal report on stdout. Without it (and with every -o naming a file), a successful run writes the files and prints nothing.

Detector and matcher work runs once. All outputs derive from the same in-memory graph.

See also