Fix the version claim (v12, not 0.x; the 0.0.0-semantically-released placeholder was the source), reframe the eval section around cost measurement, trim the README for scannability (Diátaxis link buckets, tighter reconciliation + proofs), reorganize the docs index into Guides/Reference/Explanation and add six missing docs, and consolidate overlapping docs (related-tools→comparison, inline-mode→markdown-mode, agent-setup+agent-workflows). Relocate the eval-architecture design-of-record ADR from docs/ to research/ per the doc-tiers rule, and fix the library entry points (vigiles/linting is the compiler surface) plus the Codex setup path.
11 KiB
Markdown mode
The README has the pitch; this is the full guide to verifying rules in plain markdown — no TypeScript, no build step.
vigiles meets you in the markdown you already have. You don't need a
TypeScript build step, and you don't need to port your CLAUDE.md into a
.spec.ts to get verified rules. Declare enforce rules in the instruction
file itself and vigiles lint verifies them against your real linter config
— existence check, closest-match typo suggestions, disabled-rule detection,
and GitHub Actions annotations, exactly like a typed spec.
Two on-ramps, one tool
There are two ways to author rules, and each adds value without requiring the other:
| On-ramp | Where rules live | Build step | When |
|---|---|---|---|
| Plain markdown | <!-- vigiles:enforce ... --> in the prose |
none | Try a rule on any CLAUDE.md, zero ceremony |
| Typed spec | CLAUDE.md.spec.ts → compiled markdown |
vigiles compile |
You want compiler-grade guarantees + enforcement |
Plain markdown is the on-ramp; the typed spec is the source
of truth when you want full type checking, programmatic rule composition, and
generate types. Your agent writes the spec, and vigiles eject hands it back
to plain markdown anytime — so graduating to a spec is never a one-way door.
Inline enforce comments
The minimum-commitment path: add a single HTML comment per rule, anywhere in
your existing markdown. It's the vigiles equivalent of
// eslint-disable-next-line — maximum incrementalism, zero new files.
<!-- vigiles:enforce eslint/no-console "Route output through logger.ts" -->
Three pieces, all required:
vigiles:enforce— onlyenforceis supported inline. The prose around the comment is the guidance, so aguidancecomment would be a tautology.<linter>/<rule>— the same reference format asenforce()in spec mode. All seven catalogs (ESLint, Stylelint, Ruff, Clippy, Pylint, RuboCop, Cedar), scoped plugin names (eslint/@typescript-eslint/...), and the vigiles-internal namespace (vigiles/orphan-docs) work here."<why>"— a double-quoted string shown to the agent as context. No newlines or embedded quotes; if you need either, move to a spec.
A fuller example:
# My Project
<!-- vigiles:enforce eslint/no-console "Route output through logger.ts" -->
<!-- vigiles:enforce eslint/@typescript-eslint/no-floating-promises "Await or explicitly void" -->
<!-- vigiles:enforce ruff/F401 "No unused imports" -->
## Logging
All application output must go through the shared logger module.
What vigiles lint catches
- Verifies each rule reference against your real linter config.
- Emits closest-match suggestions on typos:
"no-consol"→did you mean "eslint/no-console"? - Flags rules that exist but are disabled in your linter config.
- Emits
::errorannotations under GitHub Actions; exits code 2 on any failed rule, so CI fails fast.
What it does not do (vs a typed spec)
- No edit-time type safety. A
.spec.tsgets editor squiggles because rules are a type union; inline strings surface typos only atvigiles linttime (still before CI). - No programmatic composition — each comment stands alone.
- No NCD duplicate detection — that runs on spec-mode files.
That's all fine for the adoption on-ramp. When you outgrow it, graduate to a spec.
Mixing with a spec — don't
A file is checked for inline rules only when it isn't managed by a spec (no sibling <file>.spec.ts, no vigiles:sha256 … compiled from … header). If both exist, the compiler overwrites the markdown on the next compile and your inline comments vanish. Pick one per file.
Graduating to a spec
When a dozen inline rules start crowding the prose:
npx vigiles init --target=CLAUDE.md
That scaffolds a CLAUDE.md.spec.ts beside your CLAUDE.md. Copy the enforce rules into the rules: block, delete the inline comments, and run vigiles compile — the markdown is rebuilt with a sha256 header, and future edits flow through the spec. vigiles eject reverses it anytime.
require-instructions-spec
The built-in require-instructions-spec rule asks for a .spec.ts sibling
for every CLAUDE.md / AGENTS.md. It is narrow: only a .spec.ts
satisfies it. Inline <!-- vigiles:enforce --> comments and vigiles:
frontmatter are still valid plain-markdown on-ramps, but they do not
satisfy require-instructions-spec — so a markdown-mode user simply keeps
the rule off (it is off by default; turning it on is a workflow-tier opt-in
for teams that want to require a typed spec). No vigiles-disable require-instructions-spec comment needed unless you have enabled the rule.
A file is checked for inline rules only when it is not managed by a spec —
i.e. it has no sibling <file>.spec.ts and no vigiles:sha256 … compiled from … header. The typed spec is the source of truth; it overwrites the markdown on
the next compile, so don't mix a spec with hand-authored markers in the same
file.
See also
spec-format.md— the typed.spec.tssource of truth.verifying-instruction-files.md— the lint guide.