rules.nvim · Debug & inspect · vimdoc
:help rules
A rule/checklist engine for Neovim
doc/rules.txt — rendered from the plugin's own vimdoc
*rules.txt* A rule/checklist engine for Neovim
CONTENTS
Introduction ....... |rules-introduction| Setup .............. |rules-setup| Commands ........... |rules-commands| Gates .............. |rules-gates| Waivers ............ |rules-waivers| Ruleset format ...... |rules-ruleset-format|
INTRODUCTION
rules.nvim reads a set of rules you point it at, runs whichever of them can be checked mechanically against a repo, and reports the rest as a worklist. It ships with no bundled rules of its own — see the README's "Why no bundled rules".
SETUP
require("rules").setup({
rulesets = { "~/path/to/your/checklists" },
})
rulesetsis a list of files or directories; every.mdfile reachable from each entry is scanned for fenced ```rule blocks. Each entry is expanded (~,$VAR/${VAR},%VAR%) before it is checked, so the~/...form above works as written; a path that still resolves to neither a directory nor a readable.mdfile is a load error, notified rather than silently loading zero rules.lua_predicates(boolean, defaulttrue) decides whetherlua_predicatechecks may run. A rule block body is always evaluated in an empty environment, but a predicate is arbitrary Lua that runs later; setlua_predicates = falseto run a ruleset you did not write, and each predicate then reportserror("predicate not trusted") instead of running. See docs/RULESET-FORMAT.md.
COMMANDS
*:Rules_check* :Rules check [{path}] Runs every rule whose ID prefix matches the required|--family|flag against {path} (default: the current working directory). Findings go to the quickfix list; a readable report opens in a tab, reusing a still- open report window instead of piling up a new one on every run. With --format=json, prints JSON instead and skips the quickfix list/buffer; never quits Neovim, so it is safe to run interactively. For a headless CI run with a real exit code, callrequire("rules").check_family_json(family, path)directly — see docs/BINDINGS.md in the plugin's repository for the recipe. --family={PREFIX} required, e.g. --family=DEP --format={FORMAT} optional, only "json" is recognized *:Rules_gate* :Rules gate {name} [{path}] Runs every family configured for gate {name} (see |rules-gates|) as one combined report. --diff={ref} narrows findings to files changed since that git ref (tracked + untracked); a rule left with no findings inside the diff reports "pass". --format=json behaves like :Rules check's. --diff={REF} optional, e.g. --diff=main --format={FORMAT} optional, only "json" is recognized *:Rules_show* :Rules show {id} Jumps straight to one rule's source location by its exact id (e.g.:Rules show DEP-06), without running a family check. Errors, rather than silently doing nothing, if no loaded rule has that id. *:Rules_stats* :Rules stats A structural overview of every loaded rule: total count, and per-family totals split into automated (has acheck) vs. manual, plus a severity breakdown. No check runs — this is catalog metadata, not a pass/fail report; opens in a readable buffer, or prints JSON with --format=json. --format={FORMAT} optional, only "json" is recognized
GATES
A gate is a named bundle of rule families, run together as one report — the
one place in this plugin that checks more than one family at once. No gates
are bundled; define them in setup():
require("rules").setup({
gates = {
release = { "REL" },
review = { "ERR", "LUA", "PRIN" },
},
})
See docs/BINDINGS.md in the plugin's repository for the--diffscoping semantics in detail. A configured family that matches zero loaded rules (a typo, or a family not yet migrated to fencedruleblocks) warns rather than silently running a smaller gate than configured.
WAIVERS
A .rules-waivers.json at the checked root records consciously accepted
findings so a re-run doesn't keep flagging them:
{ "DEP-04": "legacy call site, ticket JIRA-123 tracks the actual fix" }
A waived rule that would otherwise fail or error reports as "waived" instead of "fail" — visible in the buffer report with its reason, excluded from the quickfix worklist, and never counted bycheck_family_json's exit code. See docs/BINDINGS.md in the plugin's repository for detail.:checkhealth rulescross-checks the current working directory's waivers against every loaded rule and warns about an orphaned entry — a waiver whose rule id was retired or mistyped, which would otherwise sit silently protecting nothing.
RULESET FORMAT
See docs/RULESET-FORMAT.md in the plugin's repository for the full format —
this is the reference for a Lua project's own :h request, not a duplicate
of that document's detail.
A rule is a Markdown section with a fenced ```rule code block:
### `DEP-06` — `vim.tbl_flatten()` is deprecated
```rule
id = "DEP-06",
severity = "recommended",
check = { type = "grep", pattern = "vim%.tbl_flatten%(" },
```
check is optional. A rule without one is never given an automatic
pass/fail — it appears as a worklist entry instead.