paranoid_
Report

The JSON report, its schema, and SARIF

Four output formats, one underlying result. Pick text for a terminal, md for a PR comment or job summary, json for scripting, or sarif for code scanning tools.

Formats

FormatUse it for
text (default)Reading in a terminal. Uses color on a real terminal and respects NO_COLOR.
mdPR comments, job summaries, anywhere Markdown renders.
jsonScripting and storage. Byte-identical across reruns of the same input.
sarifGitHub code scanning and other SARIF-reading tools.

Pick with --format on verify. All four renderers describe the same underlying finding.Result, so the same run produces the same findings in every format; only the shape differs.

The JSON report, schema version 7

The JSON report follows a versioned schema, checked in at docs/schema/report-v1.schema.json. A test in the repository checks every rendered report against this file; it accepts nothing the schema does not describe (additionalProperties: false everywhere). The current version is 7. Whenever a change adds a field, a category, or a report section, this number goes up; a field never changes shape under the same number.

Top-level fieldTypeMeaning
schema_versionintegerAlways 7 today
scoreinteger 0-100The trust score
verdict"pass" | "warn" | "fail"Derived from the score
findingsarray of findingEverything that fired, minus baseline and policy suppressions
checks_runarray of stringNames of checks that actually ran
checks_skippedarray of {name, reason}Checks that could not run, and why
coverageobjectTotal test coverage, best-effort; see Sandbox & coverage
suppressedobject {count, entries}Findings a baseline entry or a policy [[disable]] entry matched, see Baseline & suppressions and Team policy file
metaobjectrepo, base, head, tool version, generated_at

Each item in findings:

FieldType
rule_idstring, e.g. "TI001"
severity"info" | "low" | "medium" | "high" | "critical"
category"test-integrity" | "dependencies" | "sandbox" | "claims" | "error-handling" | "api-surface" | "safety"
filestring
lineinteger, 0 when unknown
evidencestring, truncated to about 200 characters
messagestring
suggestionstring

Findings are sorted by rule ID, then file, then line, so JSON output is byte-identical across reruns. Nil slices render as empty arrays, never null.

Each item in suppressed.entries:

FieldType
rule_idstring
severity"info" | "low" | "medium" | "high" | "critical"
filestring
lineinteger, 0 when unknown
messagestring
reasonstring, empty for a bulk-generated baseline entry
expiresstring, empty when the entry never expires
expiredboolean
source"baseline" | "policy" (schema version 7)
{
  "schema_version": 7,
  "score": 40,
  "verdict": "fail",
  "findings": [
    {
      "rule_id": "DEP001",
      "severity": "critical",
      "category": "dependencies",
      "file": "requirements.txt",
      "line": 2,
      "evidence": "requests-toolkit-pro",
      "message": "The new dependency requests-toolkit-pro does not exist in PyPI.",
      "suggestion": "Remove the dependency or fix the typo."
    }
  ],
  "checks_run": ["test-integrity", "dependencies", "sandbox"],
  "checks_skipped": [{"name": "claims", "reason": "no --claims, --session, or commit messages given"}],
  "coverage": {"available": false, "reason": "no coverage tool detected", "head_percent": 0, "has_base": false, "base_percent": 0, "delta_percent": 0},
  "suppressed": {"count": 1, "entries": [
    {"rule_id": "TI012", "severity": "medium", "file": "flaky_test.go", "line": 12,
     "message": "A retry was added to an existing test.", "reason": "flaky under load, tracked in issue #142",
     "expires": "2026-12-01", "expired": false, "source": "policy"}
  ]},
  "meta": {"repo": "/home/you/project", "base": "7db5cfb", "head": "worktree", "version": "v0.1.0", "generated_at": "2026-08-26T12:00:00Z"}
}

SARIF (--format sarif)

SARIF 2.1.0, so findings can upload straight into GitHub code scanning or any other SARIF-reading tool. One run, one tool driver named paranoid, one reportingDescriptor per registered rule (id, short and full description, a helpUri pointing at that rule's anchor in docs/rules.md on the main branch), and one result per finding.

paranoid severitySARIF level
critical, higherror
mediumwarning
low, infonote

The original severity is preserved in properties.severity on the result even after it is mapped to a SARIF level. Score, verdict, checks run, checks skipped, and the suppressed block all ride along in runs[0].properties, since SARIF has no first-class concept that matches paranoid's own report shape. Coverage is not included in SARIF properties.

SARIF is versioned by the SARIF spec itself, not by schema_version: a JSON report schema bump never forces a SARIF shape change, and the reverse is true too. See Exit codes & CI for the upload-sarif workflow example.

fix-prompt's own JSON schema

paranoid fix-prompt --format json emits a completely separate artifact with its own versioned schema at docs/schema/fix-prompt-v1.schema.json, currently version 1, independent of the verify report's schema version. See fix-prompt.

{
  "schema_version": 1,
  "instructions": [
    {
      "rule_id": "TI001",
      "severity": "critical",
      "file": "internal/calc/calc_test.go",
      "line": 0,
      "instruction": "Restore the deleted test file at internal/calc/calc_test.go; do not delete a test to make the suite pass."
    }
  ],
  "notes": []
}

The history envelope, version 1

verify --save writes each report to .paranoid/history/, wrapped in a small envelope with its own history_version (currently 1), independent of both the verify schema and the fix-prompt schema: {history_version, report}, where report is the exact same object --format json would print for that run. paranoid history --format json emits a third, derived shape, a per-run series for scripting, also carrying its own history_version. See History for both shapes in full, an example of each, and how the HTML trend view is built from them.

Both schema files are checked in and both are tested: a rendered report that does not match its schema fails the build. If your own tooling parses these formats, pin to a schema version and treat an unexpected schema_version as an error, the same way fix-prompt --report does.