Learning
Learning is opt-in with ward check --learn-after <n>. It tracks the problems a gate finds, not
the gate itself: each record is one tool rule, keyed gate:rule (for example
pmd:UnusedLocalVariable or checkstyle:LineLength). Ward stores compact metadata in
.ward/learning.json: the gate and rule, one example finding message of at most 200 characters,
occurrence count, state, timestamps, and whether a prompt has been issued. Full stdout and stderr are
never stored.
Only findings from failed gates whose tool reports specific rule IDs are learned: Checkstyle, PMD,
gitleaks, ESLint (for example eslint:no-unused-vars), Biome (for example
biome:lint/suspicious/noExplicitAny) and the TypeScript compiler (for example tsc:TS2322). Gates without rule-level findings (tests, coverage, SpotBugs, ArchUnit, mutation) and
catch-all findings such as Spotless formatting, javac errors or ESLint parsing errors are not
tracked, because the only lesson they offer is to run the command again.
How occurrences are counted:
- A rule is counted once per run, however many violations it has.
- An occurrence starts when the rule begins failing. It is counted again only after the rule was fixed: its gate ran and no longer reported it, even if the gate still failed on other rules.
- Skipped or unevaluated gates do not change their records.
Once a recurring rule is fixed, Ward asks the agent to add a coding rule to AGENTS.md that prevents
the problem. The prompt quotes the rule and an example message, and asks for a coding rule, not a
rule about running the gate or a command. Ward never edits that file, and issues each prompt at most
once per record.
The store carries formatVersion 2. A version 1 store, which tracked gate statuses, is discarded
without a warning and replaced on the next learning run.
To reset learning, delete .ward/learning.json (or remove the individual record). Decide
whether to commit the file with your project or ignore .ward/ according to your team’s
workflow; Ward does not modify .gitignore.