- Onboard. A new hire runs
whyfile explain <file>instead of interrupting a senior. - Review.
whyfile changed --base mainsurfaces the intent a PR touches, so a reviewer sees the constraints a change is bound by;whyfile review-context --base mainturns that into a brief an external reviewer like Codex can act on directly. - Retain.
whyfile coverageshows which code has recorded intent and which is dark, andwhyfile digestreports what was decided since a checkpoint.
The PR check
--fail-on-constraint to turn it into a soft gate that
exits 5 when a PR touches a file bound by a constraint, so the constraint gets a reviewer’s
acknowledgement.
Coverage and digest
coverage reports the golden fraction beside the coverage numbers: the share of intent that is
trusted evidence (human-written: authored decision records, captured live decisions, and attested
commit trailers / # why: comments; the numerator grows further as the confirmed tier lands) over total
intent. It is partitioned by evidence class and never blended, so reconstructed intent is shown
separately and never inflates the trusted count. Alongside it, intent_debt reports dark files and
orphaned intent (intent that explains no code); stale decisions come from drift and disputes from
the audit phase, reported as null here rather than a misleading zero.
The attested tier is the zero-workflow capture channel: on every pipeline run (unless
--no-attest), commit trailers (Why:/Decision:) and # why: code comments are ingested
deterministically as provenance: attested intent nodes, anchored to the code they touch or
annotate. This gives any repo a non-empty trusted layer on day one, with no new workflow to adopt.
List them with whyfile list-intent --provenance attested.
The capture subcommand records a decision at the moment of choosing, the cheapest time to
capture ground truth:
# Decision: record to docs/decisions/ (idempotent by slug) and merges a
provenance: captured node into the graph, immediately queryable via why/explain/list-intent --provenance captured. The node is built through the same ingest path a committed record takes, so
re-ingesting the record reproduces the identical node. If --recommendation differs from
--chosen, the node records a resolution_delta capturing where the human overrode the agent.
--since last-run needs at least two pipeline runs: the first run has no prior snapshot to diff
against, so it writes none and digest --since last-run exits 2 with a clear message until a
second run has happened.
Drift and affirmation
Recorded decisions rot silently when the code they explain changes underneath them.affirm stamps
a decision as reviewed against the current code; drift flags any affirmed decision whose anchored
code has changed since, so staleness is visible instead of silent.
affirm records a content fingerprint of the anchored code (symbol-level where the anchor names a
function or class, file-level otherwise) into intent-affirmations.json, a small human-owned ledger
you commit. drift recomputes those fingerprints and reports four buckets: needs-reaffirmation
(affirmed, but the code moved), expired-assumptions (see below), never-affirmed (anchored, staleness
unknown), and orphaned (a ledger entry for a decision no longer in the graph). It is deterministic,
LLM-free, and informational (exit 0); re-affirming a flagged decision clears it.
Assumptions are the other decay mechanism: most stale intent is stale because an assumption quietly
expired. A record’s ## Assumptions section (see docs/adr/TEMPLATE.md) is ingested into authored
assumption intent nodes, each with an optional review-by date:
drift as an expired assumption, prompting you to
revisit the decision that rests on it. --as-of defaults to today; pass a future date to see what
will be overdue by then. Because assumptions are first-class intent nodes, explain <file> and
why "..." also answer “which assumption governs this path?” during incident triage.
Trust lifecycle
Trust is a lifecycle, not a label.trust resolves each intent node’s current state: it rises
through provisional (reconstructed, unverified), corroborated, confirmed (survived an audit),
and affirmed (a human signed off), and falls to stale (affirmed but the code drifted since),
disputed, superseded (a newer record replaced it), or orphaned (its anchored code was
deleted).
intent-trust.json), so they are stable across re-runs. Structural facts (superseded,
orphaned) win over promotions, and a human affirm outranks a panel verdict. Recording a verdict
appends to the log with the actor and timestamp; it never edits the graph. Superseded and orphaned
states are detected automatically from the graph; confirmed and disputed come from recorded
verdicts — by hand via --set, or auto-recorded by whyfile audit --record (see above).
Roadmap
Cached Pass B anchoring (to make per-PR updates truly diff-proportional) and--since pipeline
scoping are planned.
Feeding intent to external reviewers: review-context
whyfile review-context [--base <ref>] [--files ...] [--format json|markdown|focus] emits a
diff-scoped intent brief: for the changed files, the recorded decisions and constraints that
govern them, each tagged with its provenance tier (authored/reconstructed) and resolved trust
state, plus the constraints with no superseding record in the changeset. It is LLM-free — a
projection over intent-diff joined with trust state.
It exists so an external code reviewer (e.g. Codex, which auto-reads AGENTS.md) can weight its
findings by recorded intent: a diff that violates a blocking constraint (kind=constraint, trust
authored/affirmed/corroborated/confirmed) with no superseding decision record is a blocking
finding; reconstructed or disputed intent is advisory. --format focus emits a compact, budgeted
paragraph for injection as reviewer focus text; markdown (default) is the full block; json is
the structured object. This is not a gate — it exits 0/2 only, never EXIT_POLICY.