ADR-0012: Settings as a seam (Context, build_context, dedicated config file)¶
- Status: Accepted
- Date: 2026-08-16
- Source tickets: #154 (and #157-#160)
- Supersedes: the
docs_dir-only precedence chain,config show, anddoctorcontracts from ADR-0007. ADR-0007’sinitdecision stands unchanged.
Context¶
ADR-0007 resolved a single setting, docs_dir, through a four-tier chain (flag, env, pyproject.toml, default).
Three more settings needed the same treatment: repo_root
(already computed ad hoc in several commands),
and branch_prefix/batch_byte_cap/batch_file_cap
(previously hardcoded constants in write_gate.py and the batching module).
A non-Python host repo also had no config file that didn’t compete for space in a pyproject.toml table meant
for Python tooling.
Decision¶
wiki_toolkit/settings.pygains aContextmodel (docs_dir,repo_root,branch_prefix,batch_byte_cap,batch_file_cap) and abuild_context()entry point that resolves all five fields at once, in precedence order: CLI flag (onlydocs_dir/repo_roothave one) >WIKI_TOOLKIT_<UPPER_SNAKE>env var >.wiki-toolkit.tomldedicated file, found by walking upward from cwd >[tool.wiki_toolkit]table in the nearestpyproject.toml> built-in default.- The dedicated file wins over the
pyproject.tomltable even when both are present, so a non-Python host repo has a config file that never has to compete with one meant for Python tooling.doctorwarns when both exist, since only the dedicated file’s values take effect. - Resolution never raises.
A malformed dedicated file, a malformed
pyproject.tomltable, or an individually invalid field value (emptybranch_prefix, non-positive batch cap) is dropped and that field falls through to the next tier, rather than failing the whole field or the command. build_context()returns theContextalongside a per-field source map (flag/env/dedicated_file/pyproject/default). The CLI group callback calls it once per invocation and assigns the result toctx.obj; every subcommand reads settings off that shared object via@click.pass_objinstead of re-declaring--docs-dirand re-resolving it per command.config showprints every field’s resolved value and source, replacing the single-fielddocs_dir-only output.doctorprints the resolved configuration and source for every field (not justdocs_dir), plus three new non-fatal warnings, never exit-1 failures: both a dedicated file and apyproject.tomltable present,repo_rootfalling back tocwdbecause no.gitwas found, and any field that fell back todefaultbecause an upstream tier’s value for it was invalid.
Consequences¶
write_gate.pyand the batching module readbranch_prefix/batch_byte_cap/batch_file_capoffContextinstead of module-level constants; both remain internal defaults, now overridable.- Every CLI subcommand’s default-resolution line collapses to reading
ctx.obj; only the group callback performs resolution. resolve_docs_dir()(ADR-0007’s four-tier,docs_dir-only function) stays insettings.pyunused by the CLI; nothing currently calls it outside tests. It is not removed by this decision, since removing it is out of scope for the settings-seam work. (Removed later by issue #166.)