Validators

July 28, 2026 · View on GitHub

Every rule is declared as an attribute on a <block> tag inside a comment. One block can carry several attributes at once.

Which validator do I want?

I want to...Use
Force docs or config to be updated whenever some code changesaffects
Assert two places still hold the same valuesame-as
Keep a list alphabetized or numerically orderedkeep-sorted
Prevent duplicate entries in a listkeep-unique
Require every line to match a formatline-pattern
Cap or fix the number of lines in a blockline-count
Enforce a rule stated in plain Englishcheck-ai
Run arbitrary validation logiccheck-lua

Prefer the deterministic validators — affects, same-as, keep-sorted, keep-unique, line-pattern, line-count. They are fast, offline, and need no API key. Reserve check-ai for rules the others genuinely cannot express.

Universal attributes

These apply to any block regardless of which validator it uses.

name

Names the block so other blocks can point at it with affects or same-as. Names also show up in blockwatch list.

# <block name="allowed-colors">
"red",
"green",
# </block>

severity

Controls how a violation is reported. Mirrors LSP diagnostic severities.

ValueReportedExit code
error (default)yes1
warningyes0
infoyes0
hintyes0

Only error fails the run. This makes severity the way to introduce a rule without breaking CI on day one — land the block as a warning, clean up the existing violations, then promote it:

# <block keep-sorted severity="warning">
"cherry",
"apple",
# </block>

When a block is checked

With a diff on stdin, a block is validated only if the diff touched its content or its start tag. Without a diff, every block in scope is validated.

affects is the exception in the other direction: it is inert without a diff, since it asks "was this edited without its counterpart?" — a question a full-tree run cannot answer. Every other validator runs in both modes.


README