A fast, extensible grammar and style checker for Markdown, HTML, LaTeX, Typst, and more. Ships as a VS Code / VSCodium extension and Neovim plugin, backed by a Rust core binary with LSP and Protobuf server modes.
[!NOTE] Language Check is in early development. Core checking works and is usable day-to-day, but expect rough edges — if you hit a bug, please open an issue and it will be addressed promptly. The configuration format may evolve between minor versions; backwards compatibility is a goal but not yet guaranteed.
Features
- Multi-engine checking — local Harper engine for instant feedback, optional LanguageTool for deep grammar analysis, optional Vale for style linting with its rich plugin ecosystem, optional Hunspell for spelling in the languages the others do not read, external binaries, and WASM plugins via Extism
- Tree-sitter parsing — extracts prose from Markdown, HTML, LaTeX, Typst, and more while skipping code blocks, math, and markup
- SpeedFix panel — keyboard-driven batch review: press
1–9for suggestions,ato add to dictionary,ito ignore,Spaceto skip - Inline suggestions — inlay hints, ghost text completions, and quickfix code actions
- Standalone CLI —
language-check check,fix,list-rules,config, andpackssubcommands - Workspace indexing — background indexing with redb-backed caching
- Rule normalization — unified rule IDs across providers for consistent severity overrides
- Prose insights — word count, sentence count, and Automated Readability Index in the status bar
- Inspector — debug webview showing AST structure, prose extraction ranges, and check latency
- i18n — extension UI localized in English, German, French, and Spanish
Quick Start
VS Code Extension
- Install the extension (publisher:
KaiErikNiermann) — from the VS Code Marketplace, or from Open VSX on VSCodium and other non-Microsoft builds - Open a Markdown, HTML, LaTeX, or Typst file — checking starts automatically on save
- Press
Alt+Fto open the SpeedFix panel
Neovim
-- lazy.nvim
-- Or with Neovim 0.11+ native LSP config:
vim..
See editors/nvim/README.md for full setup instructions.
CLI
# Build from source
# Check a file
# Auto-fix high-confidence issues
# List available rules
Project Structure
lang-check/
├── rust-core/ Rust core binary (server + CLI)
│ ├── src/
│ │ ├── engines/ Harper, LanguageTool, External, WASM engines
│ │ ├── orchestrator.rs Multi-engine coordinator
│ │ ├── prose/ Tree-sitter prose extraction, one module per language
│ │ │ ├── gap.rs What a language puts between two prose words
│ │ │ └── shared.rs Range merging and scanning helpers
│ │ ├── grammars.rs Bindings to the vendored tree-sitter grammars
│ │ ├── rules.rs Rule normalization
│ │ ├── config.rs YAML/JSON configuration loader
│ │ ├── workspace.rs redb-backed workspace indexing
│ │ └── ...
│ └── src/bin/
│ ├── language-check-server.rs LSP + Protobuf stdio server
│ └── language-check.rs Standalone CLI
├── editors/nvim/ Neovim plugin (lang-check.nvim)
│ ├── lua/lang_check/ Plugin core (config, binary, health)
│ ├── lsp/ Neovim 0.11+ native LSP config
│ └── doc/ Vim help file
├── extension/ VS Code extension (TypeScript)
│ ├── src/
│ │ ├── extension.ts Activation, commands, providers
│ │ ├── client.ts Protobuf IPC client
│ │ ├── api.ts Public API for other extensions
│ │ ├── downloader.ts Core binary auto-download
│ │ └── trace.ts Protobuf message tracing
│ ├── webview/ SpeedFix + Inspector UIs (Svelte 5 + Tailwind)
│ ├── l10n/ Runtime localization bundles
│ └── package.nls.*.json Command/setting translations
├── examples/ A worked document per format, with its config
├── proto/ Protobuf schema (checker.proto)
├── docs/ Sphinx documentation
├── scripts/ Build utilities
└── docker-compose.yml Local LanguageTool server
Configuration
examples/ has a working setup per format — a document, the
.languagecheck.yaml it is written against, and a note on what a check reports
and what it deliberately does not.
Create a .languagecheck.yaml in your workspace root:
engines:
harper: true
languagetool:
enabled: true
url: "http://localhost:8010" # your LanguageTool server
external:
- name: vale
command: /usr/bin/vale
args:
extensions:
wasm_plugins:
- name: custom-checker
path: .languagecheck/plugins/checker.wasm
rules:
spelling.typo:
severity: warning
grammar.article:
severity: off
performance:
high_performance_mode: false
debounce_ms: 500
max_file_size: 1048576
auto_fix:
- find: "teh"
replace: "the"
See language-check config init to generate a default configuration.
Development
Prerequisites
- Rust 2024 edition (1.85+)
- Node.js 18+ and pnpm
- Protobuf compiler (
protoc)
Building
# Rust core
# Extension
Testing
# Rust — unit tests + snapshot tests (insta)
# Extension — vitest
Linting
# Rust
# TypeScript
Local LanguageTool
# LanguageTool API available at http://localhost:8010
Git Hooks
The project uses Lefthook for pre-push checks (cargo check, clippy, fmt, test, and tsc).
Plugin System
Language Check supports three extension mechanisms:
| Type | Sandboxed | Config key | Protocol |
|---|---|---|---|
| External binary | No | engines.external |
JSON over stdin/stdout |
| WASM plugin | Yes (Extism) | engines.wasm_plugins |
check(input) -> output export |
| VS Code API | N/A | — | LanguageCheckAPI interface |
See docs/advanced/plugins.md for the WASM plugin development guide.
Documentation
Full documentation is built with Sphinx:
# Open _build/html/index.html