Output formats & exit codes

Shipmoor Team
June 11, 2026
3 min read

Every scan produces the same evidence; you choose how it’s rendered. Human output is for you, deterministic JSON is for scripts and agents, SARIF is for code scanning — and a stable four-code exit contract makes all three safe to gate a build on.

Human output (default)

shipmoor scan --changed

The default renderer leads with a one-line verdict, groups findings by file with blockers first, and ends by naming the exact command to run next (shipmoor explain <id> for the first blocker, plus the rerun command). Color is suppressed automatically when stdout is not a TTY, when NO_COLOR is set, or with --no-color.

JSON — shipmoor.scan.v1

shipmoor scan --changed --json --output shipmoor.json

The JSON report is a stable, versioned contract (shipmoor.scan.v1) — the same document the Agent Harness, the IDE extension (preview), and your own CI scripts consume. Key fields per finding:

FieldWhat it holds
idStable finding ID (SHM-…) — usable with shipmoor explain <id> --from <report>
rule_idThe rule, e.g. python.phantom_import
severitycritical / high / medium / low
path, start_lineWhere
message, recommendation, evidenceThe what, the fix, and the proof
subtypeFiner classification, e.g. hallucinated_package
change_statusintroduced / modified / preexisting / unknown for diff and patch scans
fingerprintStable hash for deduplication across runs

When --json writes to stdout (no --output), stdout contains only the JSON document; diagnostics go to stderr. That discipline is what lets agents and pipelines parse the output without scraping.

SARIF — for code scanning

shipmoor scan --changed --sarif --output shipmoor.sarif

SARIF 2.1.0, ready for GitHub code scanning upload. The same stdout/stderr discipline applies. See SARIF & code scanning for the workflow.

Markdown summary

For CI job pages, --markdown-summary <path> writes a human-readable digest alongside whichever main format you chose:

shipmoor scan --diff origin/main...HEAD \
  --sarif --output shipmoor.sarif \
  --markdown-summary "$GITHUB_STEP_SUMMARY"

The exit-code contract

Four codes, stable across versions — this is the contract the Agent Harness and CI integrations are built on:

CodeClassMeaning
0cleanNo gate fired. The report is present.
1thresholdFindings met the gate. Not an error — the JSON/SARIF is still written and complete.
2usageBad arguments or config. Error on stderr, no report.
3scan failedThe scan itself crashed. Error on stderr, no report.

Two rules of thumb for anything consuming these codes:

  • Treat 1 as a signal, not a failure. It means the gate worked. Parse the report and act on the findings; don’t route it to your “tooling broke” path.
  • Reserve error handling for 2 and 3. Those are the only codes where no report exists.

On an IC plan with the Claim Check gate enabled, exit code 1 unifies both gates: the scan exits non-zero if either the finding threshold or the claim-check gate fires. See Turning on the gate.

Note: shipmoor upgrade has its own, separate exit codes for install plumbing (20 network, 21 checksum, …) — see Installation. The 0/1/2/3 contract above is specifically the scan surface.

Next

Last updated on June 11, 2026

Was this article helpful?

Your response is saved on this device.