Configuration¶
Tip
The configuration format is still evolving. Backwards compatibility is maintained where possible, but some keys may change between minor versions. Check the release notes when upgrading.
Language Check is configured via a .languagecheck.yaml file in your workspace root. YAML is preferred; .languagecheck.yml and .languagecheck.json are also supported.
Where the config is read from¶
Language Check reads one config per workspace, from the root of the workspace folder. It does not search up or down from the file being checked, so the closest config to a file is not necessarily the one that applies to it.
Only the root counts. A
.languagecheck.yamlin a subfolder is not read, not even for the files inside that subfolder, and nothing from it is merged into the root config. To treat part of a project differently, useexclude, the per-language settings andrulesin the root config.One file wins, with no merging. If more than one config sits at the root,
.languagecheck.yamlis used, then.languagecheck.yml, then.languagecheck.json. The others are ignored completely.Multi-root workspaces use the config of the first folder, for every folder.
The command line reads the config from the directory it runs in.
language-check check docs/from the repository root uses the root config; running the same check from insidedocs/uses the config there, if there is one.
This is the model pyright and mypy use (one config per run), not the nearest-config-wins model of Prettier or ESLint’s flat config.
The editor says so when you open a config that is not in effect: a nested one, or one shadowed by a higher-precedence name at the root. It shows a single information note naming the file that is read, and none of the gutter status marks the config in effect gets.
Engines¶
Control which checking engines are active:
engines:
# Bool shorthand — just enable/disable:
harper: true
languagetool: false
# Nested config — engine-specific settings:
harper:
enabled: true
dialect: "American" # American | British | Canadian | Australian | Indian
linters:
LongSentences: false # Disable specific Harper rules
languagetool:
enabled: true
url: "http://localhost:8010"
level: "picky" # "default" or "picky" (stricter rules)
mother_tongue: "de-DE" # For false-friends detection
disabled_rules:
- WHITESPACE_RULE
enabled_rules: []
disabled_categories: []
enabled_categories: []
max_concurrent_requests: 8 # In-flight /v2/check requests; 1 = serial
vale:
enabled: true
config: ".vale.ini" # Path to Vale config (auto-detected if omitted)
proselint:
enabled: false
config: "proselint.json" # Path to proselint config (auto-detected if omitted)
spell_language: "en-US" # BCP-47 tag for checking language
Both bool shorthand (harper: true) and nested config (harper: { enabled: true, dialect: "British" }) are supported. Use the shorthand when you only need to toggle an engine; use the nested form when you need engine-specific settings.
Note
Harper is built in and requires no external installation. LanguageTool, Vale, and Proselint are external tools that must be installed separately and available on your $PATH. See the dedicated setup guides:
The inspector health tab in VS Code shows whether each engine’s binary was detected and provides install instructions when missing.
Enabled engines run one after another and their diagnostics overlay. (Each engine may work concurrently inside its own turn — LanguageTool overlaps its requests — but the engines themselves are sequential.)
An engine is skipped when it does not handle the language being checked, or
the markup the document is written in. Harper is English-only; an external
provider or WASM plugin declares both through languages and extensions, and
declaring neither means it takes everything. spell_language is the document
default — a passage that declares its own language is checked in that one
instead, and each language group goes only to the engines that claim it.
When two engines report the same rule over the same byte range, the reports are merged into one: the highest severity wins, and the suggestions are taken round-robin, one from each engine in turn, so the top of the list is every engine’s best guess before any engine’s tail. Spans that differ even by a byte are left as separate diagnostics.
Rule Overrides¶
Change severity or disable individual rules:
rules:
spelling.typo:
severity: warning # error | warning | info | hint | off
grammar.article:
severity: "off" # Disable this rule entirely
Exclude Patterns¶
Glob patterns to skip during workspace checking:
exclude:
- "node_modules/**"
- ".git/**"
- "vendor/**"
- "*.min.js"
Auto-Fix Rules¶
Define custom find-and-replace rules applied automatically:
auto_fix:
- find: "teh"
replace: "the"
description: "Fix common typo"
- find: "colour"
replace: "color"
context: "American" # Only apply when "American" appears in the text
Performance¶
Tune performance for large workspaces:
performance:
high_performance_mode: false # Only use Harper (skip LT and externals)
debounce_ms: 300 # LSP debounce delay
max_file_size: 1048576 # Skip files larger than 1MB (0 = unlimited)
Dictionaries¶
Five domain wordlists ship with the checker — software-terms, typescript,
companies, jargon and mathematics — and all of them load by default. Turn
off the ones you do not want by name:
dictionaries:
disabled: [companies] # keep the rest
paths:
- .languagecheck/project-terms.txt
Set bundled: false to switch all five off at once. See
Configuration Schema for the full
field reference and how hyphenated words are matched.
Morphology¶
One dictionary entry covers the words built on it, so you do not have to add
algebra, algebras, subalgebra and algebraicity separately. This is on by
default:
morphology:
enabled: true # accept prefixed and derived forms
inflections: true # accept plurals and regular verb forms
Prefixed and derived forms are recognized by taking the flagged word apart and
requiring what is left to be a real word — subalgebra yes, subxyzzy no.
Inflections are generated instead, because the spelling rules only work
forwards: occur plus -ed is occurred, and a checker that stripped -ed
from occured would quietly accept a typo.
Misspellings stay visible because the engine’s own correction overrides the analysis: if it can suggest something one edit away from what you typed, you still get a squiggle. See Configuration Schema.
Full Example¶
Here’s a .languagecheck.yaml putting it all together:
engines:
harper:
enabled: true
dialect: "American"
languagetool:
enabled: true
url: "http://localhost:8010"
level: "default"
vale:
enabled: true
config: ".vale.ini"
proselint: false
spell_language: "en-US"
external:
- name: custom-checker
command: ./my-checker
extensions: [md, rst]
rules:
spelling.typo:
severity: warning
grammar.article:
severity: "off"
exclude:
- "node_modules/**"
- ".git/**"
auto_fix:
- find: "teh"
replace: "the"
performance:
high_performance_mode: false
debounce_ms: 300
dictionaries:
disabled: [companies]
paths:
- .languagecheck/project-terms.txt