Skip to main content

Configuring whyfile: the whyfile.config.json file

Every repo has a Makefile, a Dockerfile, a lockfile. This tool adds the missing one: a checked-in whyfile.config.json at repo root holds this repo’s own contract — where intent lives, and how strict the audit panel is — as a small hand-edited JSON file instead of a code change. Missing entirely is a no-op: every field falls back to today’s hardcoded default, byte-for-byte.
  • intent_sources.docs / intent_sources.records — the reconstruct pass’s --docs default and the decision-record ingest directories, honored by both the reconstruct run and whyfile sync, so a whole team shares one source of truth without repeating --docs/--records on every invocation. Precedence everywhere: explicit CLI flag > whyfile.config.json > built-in default.
  • convergence — the audit panel’s dispute thresholds (Audit in Gates): structural refutations auto-dispute, sharpen and note stay advisory. Tune this once you’ve measured the panel (see Panel evaluation) — never hand-picked without evidence.
  • intent_models (#82) — a per-pass model map, keyed by pass letter (A/B/C/D, any subset). Lets a team commit its own tiering decision instead of relying on whyfile’s built-in defaults or per-invocation env vars — useful on any backend, since #77 only gave non-claude backends ONE model id for every pass. Four-layer precedence, per pass:
    1. Explicit env override (GRAPHIFY_CLAUDE_CLI_MODEL / ANTHROPIC_MODEL / the backend’s own GRAPHIFY_<BACKEND>_MODEL) — always wins, and applies to every pass at once.
    2. intent_models[pass] from whyfile.config.json.
    3. whyfile’s built-in per-pass tier default (claude-cli/claude only — see Per-pass models in the CLI reference).
    4. The backend’s own registry default (non-claude backends only); nothing resolved at all lets the pass thread model=None and fall back to the backend name.
    An unlisted pass falls through to the next layer, so a partial map (e.g. just B) only overrides that one pass. An unknown pass key or an empty model string fails loud (EXIT_INPUT) rather than being silently ignored. Note: a config-mapped Pass A model changes Pass A’s cache key for that pass, so switching intent_models.A triggers one re-extract, same as any other Pass A model change (#55/#77).
A malformed contract (unknown key, wrong type, or thresholds that violate `structural >= sharpen
= note >= 1) fails loud rather than being silently ignored — a committed contract nobody reads is the exact dishonesty this tool exists to catch elsewhere. whyfile —doctor reports whether a whyfile.config.json is present and what it resolves to. This repo's own [whyfile.config.json`](https://github.com/whyfile/whyfile/blob/main/whyfile.config.json) is the worked example. See ADR-0029.

Seeing what this actually captures

docs/decisions/ holds this repo’s everyday decision records (see its own README.md for the full open → resolved → promoted lifecycle). For a real, concrete example of a human overriding an agent’s recommendation, read keep-the-active-wrapper-deferred-the-passive-channel-is-suff.md. For the artifact rename this file itself just went through, see rename-whyfile-artifact-to-whyfile-config-json.md.