Project layout & configuration¶
Summarizes SPEC.md §3; SPEC.md is authoritative.
Layout¶
vouch.toml # configuration (committed)
vouch_values.py # derive / claim / table / expect definitions (committed, optional)
.vouch/
runs/<run-id>.json # run records: one file per run id (committed)
derived.json # evaluated derived values, claims and tables, with their hashes (committed)
acknowledged.json # change-notification baseline (committed)
accepted.toml # reviewed-staleness ledger (committed)
history.jsonl # append-only log of detected changes and acks (committed)
CATALOG.md # LLM- and human-readable catalog of every value (committed, generated)
cache/ # hash cache, derive cache, notification state (gitignored)
paper/
main.tex
vouch.sty # copied in by `vouch init`, so Overleaf and arXiv need no install (committed)
vouch-values.tex # generated (committed)
vouch-tables/<key>.tex # generated table bodies (committed)
vouch-provenance.csv # only if [[paper]] provenance_csv is set; else `vouch export --csv`
.claude/skills/vouch/SKILL.md # optional, from `vouch init --agents`
Everything except .vouch/cache/ is committed. Committing is what lets co-authors,
Overleaf, CI and fresh clones check the paper without the artifacts or a GPU.
Project root discovery¶
The CLI walks up from the current directory to the nearest vouch.toml. The
Python API walks up from the entry script's directory; VOUCH_ROOT overrides
both.
If no vouch.toml exists, the API falls back to the git top level, warns once
(no vouch.toml found; recording into <root>/.vouch — run 'vouch init'), and
records anyway. Adopting vouch should never break an experiment run.
vouch.toml reference¶
[[paper]] # one table per paper; several are allowed
main = "paper/main.tex" # entry point; \input, \include, \subfile and \import are followed
values_file = "paper/vouch-values.tex" # default: next to main
tables_dir = "paper/vouch-tables"
provenance_csv = "paper/vouch-provenance.csv" # optional: also write the CSV on every build
[python]
values_modules = ["vouch_values.py"] # modules defining derive / claim / table / expect
first_party = [] # extra roots counted as first-party code (default: the project root)
exclude = [".venv", "venv", "build", "dist", "node_modules"]
[freshness]
granularity = "function" # "function" (needs Python >= 3.12) | "module"
env_drift = "warn" # "ignore" | "warn" | "error"
input_hashing = "content" # "content" | "stat" (size + mtime, for huge datasets)
[inputs]
external = ["data/raw/"] # source data a derive may read without a producing run
[[track]] # functions whose results are recorded, no decorator
function = "experiments/train.py::evaluate"
over = "seed"
[tables.main] # presentation overrides for a recorded or derived table
highlight = { acc = "max" }
midrules = [2]
[metrics] # project-wide defaults by key glob
"*.acc" = { fmt = ".1pct", better = "higher", desc = "top-1 test accuracy, {1} on {0}" }
"*.loss" = { fmt = ".3f", better = "lower", desc = "test loss, {1} on {0}" }
[format]
rounding = "half_up" # "half_up" | "half_even"
default_float = ".3g"
siunitx = false # render with \num / \qty
named = { pct1 = ".1pct", sci2 = ".2e" }
[latex]
tooltip = "full" # "off" | "key" | "value" | "full"
highlight = "changed" # "off" | "changed"
annotate = false # managed "% vouch: ..." trailing comments
[changes]
rel_threshold = 0.10 # relative change that makes a change "suspicious"
claim_margin = 0.01 # a claim that holds by less than this relative margin is "fragile"
on_change = [] # argv of a command that receives new changes as JSON on stdin
[lint]
level = "warn" # "warn" | "error" (--strict forces "error")
allow_years = true # don't flag 19xx/20xx in prose
skip_envs = ["verbatim", "lstlisting", "minted", "comment"]
allow = [
{ pattern = 'GF\(2\)', why = "the field GF(2), notation not a measurement" },
]
[check] # per-check severity overrides
severity = { "figure-untracked" = "info" }
[hook]
strict = false # pre-commit runs `vouch check` (errors block); true adds --strict
Every setting has a working default. vouch init writes only [[paper]] main
plus commented-out examples.