Config Files
Overview
Wavemill configuration has two file layers plus environment variables:
.wavemill-config.json: shared repository defaults, usually committed..wavemill-config.local.json: developer-specific overrides, should stay gitignored.- Environment variables: best for secrets and ephemeral environment-specific overrides.
sync-config writes .wavemill-config.json only. It never modifies .wavemill-config.local.json.
Precedence at Runtime
At runtime, Wavemill loads config in this order:
.wavemill-config.json(base).wavemill-config.local.json(deep-merged override when present)- Environment variables (where a code path supports env overrides)
Merge behavior for local overrides:
- Nested objects are deep-merged.
- Arrays replace the base array.
- Primitive values in local override win.
Cross-PR Revert Checker
tools/check-cross-pr-reverts.ts resolves the integration branch in this order:
--integration-ref <ref>when the CLI argument is non-empty..wavemill-config.json/.wavemill-config.local.jsonintegration.integrationBranch.- Default
auto/integration.
If the resolved integration ref does not exist in the repo, the checker skips gracefully instead of blocking ready on a config lookup failure.
Recommended Placement by Category
Use .wavemill-config.json for:
- Team-wide defaults that should be consistent for everyone.
- Shared relative repo paths that apply across developers.
- Canonical router/model defaults when the whole repo should use them.
Use .wavemill-config.local.json for:
- Personal model experiments and temporary model preferences.
- Developer-specific challenge rate or local routing preferences.
- Consent/data-submission preferences when they are personal opt-in choices.
- Machine-specific values that should not be committed.
Use environment variables for:
- API keys, credentials, and tokens.
- CI-specific runtime values.
- Temporary shell-session overrides.
Never store secrets in either config file when an environment variable or secret manager is available.
Model and Router Defaults
When new model/router config fields are added in future versions:
- Put them in
.wavemill-config.jsonwhen the repository should share the same default behavior. - Keep personal model trials and developer-specific provider preferences in
.wavemill-config.local.json. - Keep provider credentials in environment variables, not config files.
Native Read-Only Opt-In
Use .wavemill-config.json for the shared nativeAgent.enabled, nativeAgent.allowedPhases, nativeAgent.patchCoding.enabled, and provider model allow-list values that define whether a repo opts into native read-only expansion, planning, review, or patch-coding alpha.
Keep native provider secrets such as OPENAI_API_KEY and OPENROUTER_API_KEY in environment variables only.
nativeAgent.patchCoding.enabled is fail-closed and defaults to false. Setting it to true does not enable native patch coding by itself; Wavemill also requires a current certification artifact at .wavemill/native-agent/patch-coding-certification.json.
Coder routing has a third gate after repo opt-in and the smoke artifact: the chosen provider/model pair must also have a current phase certification artifact at .wavemill/native-agent-certifications/<provider>/<model>/<suite-version>.json whose phase satisfies patch.
See Native Read-Only Runtime for the exact config shape and phase examples.
Router Exploration Sampling
router.exploration converts deterministic argmax model selection (stage-aware
KNN routing and the Layer 3 policy resolver) into stochastic sampling so newer
or undersampled models keep receiving routing traffic:
{
"router": {
"exploration": {
"enabled": true,
"mode": "epsilon",
"rate": 0.15,
"temperature": 0.7,
"topK": 3,
"ucbConstant": 0.05,
"priors": {
"enabled": true,
"blendSamples": 10
}
}
}
}
enabled(defaultfalse): when off, sampling is byte-identical to argmax.mode:epsilonpicks a non-argmax candidate from the top-K window with probabilityrate;softmaxsamples the top-K window weighted byexp(score / temperature).topK: candidates eligible for sampling per stage (minimum 2, default 3).ucbConstant(default0= off): adds a UCB-style uncertainty bonusc * sqrt(ln(totalObservations + 1) / max(support, 1))to each candidate’s ranking key, so undersampled models get a temporary boost that decays as eval records accumulate. The bonus affects selection order only — reported expected success stays bonus-free.priors(default disabled): seeds every eligible stage model into the stage-aware candidate set even with zero eval records, scored by its registry quality prior. Empirical KNN scores blend in as evidence accumulates: weightmin(support / blendSamples, 1)— zero records means pure prior,blendSamplesrecords means pure empirical. This is how a brand-new registry model (e.g. a freshly released frontier model) becomes routable before any challenge runs produce eval data for it.newModelBoost(default off,multiplier: 1): models whose registryreleasedAtfalls withinwindowDays(default 45) get their exploration sampling weight multiplied bymultiplier, decaying linearly to 1.0 at the window edge — a temporary thumb on the scale while a new model accumulates data, never a permanent one. The same window also makes the challenge scheduler prioritize recently released under-covered models over older deliberately-unused ones. SetreleasedAtper model in the registry defaults or viamodelRegistry.models.<id>.releasedAtconfig overrides. Boosted picks are marked[recency-boosted]in decision reasoning.
Sampling, the UCB bonus, and prior seeding all operate inside the
already-filtered candidate set (allowlists, capability constraints, disabled
models, DeepSeek opt-in), and a sampled stage-aware combination that would
exceed maxCostUsd reverts to the exploit selection. Decisions record
explore-vs-exploit attribution in reasoning and an exploration field that
is persisted to route artifacts. Zero-record candidates get cost estimates
from the pricing table instead of reporting zero cost.
Router Coverage Targets and Diversity Report
router.coverage configures the diversity report
(npx tsx tools/router-diversity-report.ts):
{
"router": {
"coverage": {
"minRecordsPerModelStage": 15,
"maxStageShare": 0.7,
"window": 50
}
}
}
minRecordsPerModelStage: eval records each model should accumulate per workflow stage; cells below the target are starred in the report.maxStageShare: dominance threshold — the report warns when one model exceeds this share of any stage over the window.window: most recent eval records used for stage-share and routing-mode breakdowns (coverage counts are cumulative).
The challenge scheduler also consumes per-model-per-stage counts: new-model
recommendations target the least-covered (model, stage) cell, and
low-data-stage recommendations pick the least-tested model for the starved
stage specifically.
Local Paths Guidance
- Relative paths shared by the team can live in
.wavemill-config.json. - Absolute machine paths (for example
/Users/...orC:\\Users\\...) should stay local-only or env-backed.
Ready Stage Settings
ready.watchdog controls how mill reacts to stale or failing ready states:
thresholdMinutes: stale-local-state threshold before the watchdog intervenes.autoRecover: allows local stale-state cleanup when GitHub is clean and green.timeoutSeconds: watchdog subprocess timeout per monitor tick.stableFailureConsecutivePolls: identical safe failures required before queueing remediation.stableFailureEscalateAfterPolls: identical unsafe failures required before escalating to operator attention.safeRemediationCategories: allowlist for watchdog-driven remediation, defaulting tolint,type,test,build,migration-chain, andalembic.
ready.migrationChecks controls automatic migration validation:
enabled: master switch for automatic migration integrity checks.autoDetectAlembic: auto-enablesmigration-chain-integritywhenalembic/versions/exists andready.checksis otherwise empty.baseRefresh.enabled: fetches the PR base branch before local migration validation.baseRefresh.timeoutSeconds: timeout for that fetch.
These settings are additive and optional. Repositories that do nothing keep the defaults.
How sync-config Interacts with Config Files
npx tsx tools/sync-config.ts syncs canonical fields into .wavemill-config.json.
- It may add missing canonical fields with canonical default values.
- It does not copy values from
.wavemill-config.local.jsoninto shared config. - In
--dry-run, it reports local-only missing fields to help you decide if a shared default should be added manually. - If a local-only missing path appears secret-like or host-specific and overlaps a pending canonical addition, write mode aborts so you can make an explicit decision.