Architecture
augur is a deterministic change-risk engine: it reads a git diff and emits a
verdict (proceed, review, or block) from structural signals only. No API
key, no LLM in the core.
Two targets
| Target | Role | Dependencies |
|---|---|---|
AugurKit (library) | The pure engine: probes, signals, scoring, calibration, coverage parsing, glob/CODEOWNERS matching, SARIF projection. | Foundation only, zero third-party deps. |
augur (CLI) | Argument parsing, config loading, file discovery, output formatting, optional AI delegation. | swift-argument-parser, TOMLDecoder (CLI layer only). |
The split is deliberate and enforced:
AugurKitstays AI-free and dependency-free. Never add a hosted-LLM, local model, or third-party package to it. Optional AI lives only inaugur explain, which shells out tofledge.- Config (
.augur.toml) is parsed entirely in the CLI. The CLI decodes the file withTOMLDecoder, then constructsRiskEngine(weights:rules:thresholds:)and injects it into the pure engine. The engine never sees TOML. - Scoring is deterministic. No
Date()or randomness inside the engine;nowis injected at the CLI boundary so tests are reproducible and assessments are byte-identical for identical inputs.
The signal pipeline
git repo ──probe──▶ ChangedFile[] + Commit[]
│
HistorySnapshot (churn, recency, ownership, coupling, incidents)
│
optional: CoverageReport, PathFilter, CodeOwners
│
RiskEngine.assess
│
per-file Signal[] ──weighted blend──▶ FileAssessment.riskScore
│
aggregate (max + mean + breadth)
│
Assessment { riskScore, verdict, calibration, files, ... }
- A
RepositoryProbe(theGitRepositoryimplementation, or an in-memory fixture in tests) supplies the change surface (ChangedFile[]) and recent commits (Commit[]). HistorySnapshotderives query-friendly facts from the commits once: churn, recency, distinct authors, co-change partners, and incident-prone files.RiskEngine.assessFilecomputes a list ofSignals per file (each ariskin0...1, aweight, and a human-readabledetail).- The per-file score is the weight-normalized blend of its signals
(
Σ risk·weight / Σ weight × 100). - The overall score aggregates the files:
0.65 × max + 0.35 × mean + breadth, wherebreadthadds a small penalty for touching many files. A single file scoring≥ 80forces the overall verdict to at leastblock.
See signals.md for every signal and its weight.
Two-layer scoring + calibration
Scoring has two layers:
- A transparent heuristic prior with documented weights (see
RiskEngine.Weights). This always applies, even on a brand-new repo with no history. - A history calibration that scales the
incidentsignal by how much the repository’s own revert/hotfix record backs it. On a history-free repo the incident contribution is0; asaugurwatches a repo accumulate commits and incidents, the calibration confidence grows.
Every Assessment reports a Calibration (confidence, totalCommits,
incidentCommits, and a band: prior-only → weak → history-backed) so a
consumer knows whether a score is “guessing” or “grounded”.
calibrationConfidence = min(1, commits/300) × (0.4 + 0.6 × min(1, incidents/25))
augur calibrate walks history once and caches a CalibrationCache (a lossless
projection of the snapshot facts the engine queries) to .augur/cache.json,
pinned to HEAD. A later augur check --cached rebuilds an equivalent snapshot
without re-walking git log, and warns when HEAD has moved.
The zero-dependency invariant
AugurKit is Foundation-only by design. This is what makes augur trivially
embeddable, fast to build, and free of supply-chain surface in the part that
decides whether your change is safe. Concretely:
- Coverage parsing (LCOV / Cobertura / JaCoCo / Go) uses
XMLParserand line parsing. See coverage.md. - Glob matching (
GlobPattern) lowers globs toNSRegularExpression. - CODEOWNERS (
CodeOwners) reusesGlobPatternfor path matching. - SARIF output is a Foundation
Codablemodel.
If a feature seems to need a dependency in AugurKit, it belongs in the CLI
layer instead (as TOML parsing does).