Configuration
Every threshold in this doc has a sensible default — you don't need a config file at all to get useful output. wattage.yaml exists for the cases where the defaults don't fit: a noisier detector you want to quiet down, a different convergence sensitivity, a stricter CI gate.
Where it's read from
- With no
--configflag, every command (report,score,badge,ci) looks for./wattage.yamlin the current working directory. If it's not there, you get plain defaults — a config file is optional, not required. --config path/to/file.yamlloads a specific file instead, on any command.- An explicit
--configpath that doesn't exist, isn't valid YAML, or doesn't match the schema below is a hard error (exit code 2) — asking for a specific file and having it silently ignored would hide a real mistake. A missing file with no explicit--configis not an error; that's the normal unconfigured case.
You only need to specify the fields you want to override — anything you leave out keeps its default.
Example
# wattage.yaml
detectors:
verbosity:
expected_output_ceiling: 2000 # this codebase's steps genuinely run long
redundant_tool_calls:
enabled: false # too noisy for this agent's polling pattern
quality:
target: 0.85
ci:
fail_on:
score_below: 75
cost_delta_pct_above: 10
Reference
detectors.*
Each detector has its own enabled: bool (default true) plus whatever thresholds it uses — see each detector's own page under Detectors for what each threshold means and why its default was chosen. The keys match the detector IDs shown in a report's findings table:
| Key | Notable fields (defaults) |
|---|---|
prefix_churn |
high_severity_ratio: 0.30 |
cache_gap |
(no tunable thresholds) |
verbosity |
expected_output_ceiling: 1000, high_severity_multiplier: 3.0 |
redundant_tool_calls |
window: 5, fuzzy: true, exempt_tools: [poll_status, wait, healthcheck] |
nonconvergence |
min_iterations: 3, theta_prog: 0.25, consecutive_k: 3, oscillation_threshold: 0.6, stall_evidence_threshold: 0.15, stall_state_threshold: 0.15, stall_growth_threshold: 0.5, osc_window: 6, max_period: 4, weights: {E: 0.40, S: 0.20, P: 0.20, O: 0.15, G: 0.05}, exempt_tools, embed: local, judge: off |
retrieval_thrash |
relevance_threshold: 0.35, max_iterations_soft: 4 |
model_mismatch |
downgrade_candidates: {anthropic: claude-haiku-4-5, openai: gpt-5.6-luna}, simple_output_ceiling: 150, require_quality_map: true, min_downgrade_pass_rate: 0.90 |
reasoning_overspend |
expected_reasoning_ceiling: 500, simple_output_ceiling: 150 |
See The Convergence Engine for what nonconvergence's E/S/P/O/G weights and thresholds actually mean.
quality
| Field | Default | Meaning |
|---|---|---|
target |
0.90 |
The eval score --quality's tasks.*.eval_score values are compared against when computing the quality factor that scales your Token Efficiency grade. |
ci
| Field | Default | Meaning |
|---|---|---|
baseline_path |
.wattage/baseline.json |
Default baseline location if --baseline isn't passed. |
rolling_window_days |
7 |
How long the baseline's trend history is kept. |
fail_on.score_below |
80 |
Fail if the Token Efficiency score drops below this. |
fail_on.cost_delta_pct_above |
5.0 |
Fail if total cost increased more than this percent vs. the baseline's last passing run. |
fail_on.any_critical |
true |
Fail on any single critical-severity finding, regardless of the aggregate score. |
badge_out / sarif_out / pr_comment_out |
null |
Default output paths, if you don't want to pass --badge-out/--sarif-out/--pr-comment-out on every invocation. |
Any of these can also be overridden per-invocation with the matching CLI flag (e.g. --fail-on "score_below:75") — an explicit flag always wins over both the config file and the built-in default.