Files
holocron/plugins/lint/.apm/skills/vale-config/references/configuration-reference.md
Defame1297 ca744d5d6c fix(vale-config): correct the missing-style failure mode
Gotcha 1 said a style in BasedOnStyles that is not built-in and not
already under StylesPath "finds nothing until vale sync fetches it — a
clean run is not proof anything linted". Reproduced against vale 3.15.2:
that case is a hard `E100 [loadStyles] style '<name>' does not exist on
StylesPath`, exit 2. Nothing is linted and nothing is silent.

Worse, the same commit deleted the Gotcha that was the actual diagnostic —
that Packages and BasedOnStyles are separate keys and a style lints only
once it is in both. So the surviving rule sent a reader staring at E100 to
run `vale sync`, which fetches only what Packages declares and reports
"Synced 0 package(s)" against a BasedOnStyles-only name. The remediation
loop did not terminate. Reproduced end to end.

The genuinely silent case is the reverse — declared in Packages and
synced, but absent from BasedOnStyles — and it is now the one labelled as
such. Testing also turned up that StylesPath must exist as a directory
even when Vale is the only style (E201, exit 2), which was documented
nowhere.

references/configuration-reference.md gains a seven-row resolution matrix,
each row backed by a fixture. Its Frontmatter Scopes section claimed
provenance from the vale.sh research corpus, which contains no frontmatter
material at all; it is house-verified and now says so under its own slug.

Issue #99's wave-3 comment recorded this defect as found and repaired. It
was not — the file was byte-identical to the commit that introduced it, so
nothing here was treated as already correct.

Refs #99
2026-08-30 20:51:32 +00:00

5.2 KiB

topic, source_keys
topic source_keys
configuration-reference
context7-websites-vale-sh
house-vale-3-15-2-repro

Core Settings

Key Type Purpose
StylesPath string Path to all Vale-related resources (styles, dictionaries, vocab).
Packages string[] Packages to download and install via vale sync.
Vocab string[] Vocabularies to load.
MinAlertLevel enum Minimum severity to report: suggestion, warning, or error.
IgnoredScopes enum Inline-level HTML tags to ignore.
SkippedScopes enum Block-level HTML tags to ignore entirely.

Format Associations

Map an unrecognized extension onto a supported one so Vale lints it with the right parser — an extension-level substitution only, it does not add new file-type support:

[formats]
mdx = md

Vocabularies

Reference a named vocabulary (a folder of accept/reject word lists under StylesPath) via Vocab, then apply styles per glob:

StylesPath = styles

Vocab = Blog

[*]
BasedOnStyles = Vale, MyStyle

Local Overrides

A project can layer a local .vale.ini that overrides StylesPath, adds packages, and changes BasedOnStyles for a subset of files — local settings merge with or override the global ones:

StylesPath = localpath

Packages = write-good

[*.md]
BasedOnStyles = write-good

Rule Header Fields

Individual rule YAML files (under a style's directory) support these header fields:

Field Required Default Purpose
extends yes — Check this rule extends (e.g. existence).
message yes — Message shown when triggered; supports %s formatting per check type.
level no suggestion Severity: suggestion, warning, or error.
scope no text Scope the rule applies to (e.g. heading).
link no — URL with more info about the rule.
limit no — Max number of triggers per file.
vocab no true Set false to disable active vocabularies for this rule.

Checks

The underlying functions a rule's extends field can reference: existence, substitution, occurrence, repetition, consistency, conditional, capitalization, metric, spelling, sequence, script.

Style Resolution

Only package styles need fetching. A style whose YAML rule files are already committed under StylesPath lints immediately, with no Packages entry and no vale sync; the same is true of the built-in Vale style, which ships with the binary and contains four rules:

  • Vale.Spelling — spell-checks against Hunspell-compatible dictionaries in <StylesPath>/config/dictionaries.
  • Vale.Terms — enforces the project's accepted vocabulary terms.
  • Vale.Avoid — enforces the project's rejected vocabulary terms.
  • Vale.Repetition — flags repeated words (e.g. "the the").

Packages (top-level, what vale sync downloads) and BasedOnStyles (per-glob, what activates) are separate keys: a style lints a file only once it is in both. Every row below reproduced against Vale 3.15.2 (slug house-vale-3-15-2-repro):

Configuration Result
BasedOnStyles names a style with no directory under StylesPath, not built-in E100 [loadStyles] Runtime error — style 'X' does not exist on StylesPath, exit 2
StylesPath directory itself absent, even with only Vale active E201 Invalid value — The path '...' does not exist, exit 2
vale sync with a name in BasedOnStyles but not Packages SUCCESS Synced 0 package(s), exit 0, nothing downloaded — the next lint repeats the E100
vale sync with the name added to Packages package lands under StylesPath, exit 0; lint then loads it
Style in Packages and synced, but in no glob's BasedOnStyles 0 findings, exit 0 — downloads, never lints, indistinguishable from a clean run
BasedOnStyles names an empty directory under StylesPath 0 findings, exit 0 — loads and lints nothing; vale sync never produces this state
Built-in Vale, or a style's YAML committed under StylesPath lints immediately, no Packages entry, no sync

Frontmatter Scopes

House-verified behaviour, not documented on vale.sh — reproduced locally against Vale 3.15.2 (slug house-vale-3-15-2-repro).

A rule scoped to text.frontmatter.<key> (e.g. text.frontmatter.description) matches reliably when that field's value is a single physical line, and breaks on most — not all — multi-line forms. Multi-line forms spanning 2+ lines:

Frontmatter value form Result
Single physical line (control) Lints, exits 1
| literal block scalar Lints, exits 1
> folded block scalar 0 findings, exits 0
Plain (unquoted) continuation lines 0 findings, exits 0
Single- or double-quoted multi-line scalar 0 findings, exits 0

The silent cases produce no error of any kind, so a passing run is indistinguishable from a clean one. Do not assume a literal block scalar and a folded one behave alike — reproduce both against your own config before trusting a frontmatter-scoped rule in production. If the field is commonly authored in one of the broken forms, flatten it to one physical line ahead of the vale call rather than relying on the scope alone.