Output schema

prcompass analyze writes one JSON document to stdout. The top-level keys are versioned by version (== ANALYSIS_SCHEMA_VERSION from @prcompass/core) — pin to the major when you integrate.

interface CliAnalysisOutput {
  version: string;          // e.g. "0.1.0"
  head: { sha: string; baseSha: string };
  pr: PrMetadata | null;    // null in --local mode
  diff: { fileCount: number; files: DiffFile[] };
  mining: MineStats;
  hotspots: HotspotsReport;
  churn: ChurnReport;
  cochange: CochangeReport;
  risk: RiskReport;
  triage: { verdicts: FileVerdict[] };
  adapter: { name: string };  // "local" | "github"
}

Every numeric claim in risk is grounded by real commit SHAs in groundedIn — or it is null. The CLI never fabricates a 0 to mean "no signal".

Top-level keys

version

The ANALYSIS_SCHEMA_VERSION constant from @prcompass/core. Independent of the package's npm version, so you can pin parsers without pinning the binary.

"version": "0.1.0"

head

The resolved SHAs at the endpoints of --diff. Useful for caching and for cross-referencing tools that work in SHA space.

"head": {
  "sha":     "def567812345678123456781234567812345678",
  "baseSha": "abc123412345678123456781234567812345678"
}

pr

PR metadata — present only when a GitHubAdapter was used; otherwise null. Local-mode runs never produce a non-null pr.

"pr": {
  "number": 42,
  "title": "Migrate session middleware to JWE",
  "author": "alice",
  "createdAt": "2026-04-01T12:00:00Z"
}

diff

The set of files touched in --diff. fileCount is files.length — duplicated for cheap header-style summaries that don't want to traverse the array.

"diff": {
  "fileCount": 8,
  "files": [
    {
      "path": "src/billing/checkout.ts",
      "previousPath": null,
      "status": "modified",
      "additions": 30,
      "deletions": 5,
      "patch": "@@ -10,3 +10,4 @@\n ..."
    }
  ]
}

status is one of added | modified | removed | renamed | copied. The triage pass below maps removed → deleted and copied → renamed to match @prcompass/pr-triage-filter's vocabulary.

mining

Bug-fix vs total commit stats over the walked history.

"mining": {
  "totalCommits": 5000,
  "bugFixCommits": 904,
  "bugFixRate": 0.1808
}

hotspots

Bayesian-smoothed bug-fix density per file. The report is a map from path → {score, totalCommits, bugFixCommits, groundedIn}.

"hotspots": {
  "byFile": {
    "src/billing/checkout.ts": {
      "score": 0.74,
      "totalCommits": 38,
      "bugFixCommits": 12,
      "groundedIn": ["abc1234", "def5678", "..."]
    }
  }
}

churn

Per-file commit count, bug-fix count, defect density, first/last touch.

"churn": {
  "byFile": {
    "src/billing/checkout.ts": {
      "commitCount": 38,
      "bugFixCount": 12,
      "defectDensity": 0.316,
      "firstTouched": "2025-09-12T09:14:00Z",
      "lastTouched": "2026-04-22T17:03:00Z"
    }
  }
}

cochange

File × file co-modification graph. Edges carry both raw counts and a Jaccard-style weight.

"cochange": {
  "edges": [
    {
      "a": "src/billing/checkout.ts",
      "b": "src/billing/invoice.ts",
      "count": 18,
      "jaccard": 0.82
    }
  ]
}

risk

Per-file combined risk score with groundedIn SHA pointers and caveats.

"risk": {
  "byFile": {
    "src/billing/checkout.ts": {
      "score": 0.78,
      "tier": "high",
      "groundedIn": ["abc1234", "def5678"],
      "caveats": ["short history (38 commits)"]
    }
  }
}

score is in [0, 1]. tier is one of low | medium | high. score === null means "no signal" — never confuse with 0.

triage

The Tier 1 file-priority verdicts from @prcompass/pr-triage-filter.

"triage": {
  "verdicts": [
    {
      "path": "pnpm-lock.yaml",
      "verdict": "skip",
      "ruleId": "lockfile",
      "reason": "Package lockfile — content is auto-generated"
    },
    {
      "path": "src/billing/checkout.ts",
      "verdict": "review-candidate",
      "ruleId": "default",
      "reason": "Production source code outside tests, docs, and config paths."
    }
  ]
}

ruleId is part of the public contract — safe to pattern-match.

adapter

Identifies which adapter produced the context. Useful in logs and replay scenarios.

"adapter": { "name": "local" }

Stability

  • The set of top-level keys is stable within a major version of version.
  • New top-level keys may be added in minor versions.
  • Removing or renaming a key is a major-version break.
  • Numeric ranges (score ∈ [0, 1], verdict ∈ skip|skim|review-candidate) are part of the contract.

The schema is engineered to be JSON-clean — no Map, no Date, no functions. JSON.parse(formatJson(output)) always round-trips losslessly.

@prcompass/cli Deterministic git-diff analysis on the command line