Harper: an offline grammar checker that runs in milliseconds
Offline, privacy-first grammar checker. Fast, open-source, Rust-powered.
At a glance
- What is it?
- Automattic's Harper is a Rust grammar checker that lints locally, ships as a language server for VS Code, Neovim, Helix, Emacs and Zed, and also compiles to WebAssembly. Here is what it does, how to install it, and where it stops being the right tool.
- Who is it for?
- Adopt Harper if you write English prose in an editor that speaks LSP and you want suggestions computed on your own machine, with no document leaving the process. Skip it if you need languages other than English, or if you want grammar checking wired into a CI job, since the repository exposes no documented non-editor lint command.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Harper targets: grammar checking without a network round trip
Harper is aimed at people who write English prose all day and do not want a cloud service reading it. The README frames the motivation as a reaction to two existing options. Grammarly is described as expensive and overbearing, with suggestions that lack context, and the README objects that everything written with it is sent to their servers. LanguageTool is described as capable but heavy: the README says it needs gigabytes of RAM and a roughly 16GB n-gram dataset, and that linting even a moderate-size document took several seconds.
The audience follows from that. If you write Markdown, LaTeX, code comments or commit messages in a terminal-friendly editor, and you care that the text never leaves the process, Harper is built for you. It is not a writing assistant with tone rewriting or a plagiarism service. It checks English grammar and spelling, locally. The README is explicit that only English is supported today, though it says the core is extensible and welcomes contributions for other languages.
One claim in the README is worth reading carefully rather than repeating: it says Harper takes milliseconds to lint a document and uses less than a fiftieth of LanguageTool's memory footprint. That is the author's own comparison, stated without a published benchmark in the README. Treat it as a design goal, not a measured result you can rely on for capacity planning.
How Harper is built: a Rust workspace with per-format crates and an LSP front end
The architecture is visible in the repository layout. Cargo.toml declares a workspace whose members include harper-core, harper-ls, harper-cli, harper-wasm, harper-comments, harper-html, harper-literate-haskell, harper-typst, harper-tex, harper-asciidoc, harper-python, harper-git-commit, harper-jjdescription, harper-thesaurus and harper-stats. That list is the design statement: instead of stripping markup with a generic regex pass, Harper has a separate crate per document format, so a LaTeX file, a Typst file, a literate Haskell file and an HTML file each get parsed on their own terms before the grammar rules see the prose.
harper-core holds the linting engine and is the crate that other front ends depend on. harper-ls wraps it as a Language Server Protocol implementation, which is how the editor integrations work. harper-wasm compiles the same core to WebAssembly, which is what makes the browser build at writewithharper.com possible and what the Dockerfile builds with wasm-pack. harper-cli exists in the workspace, but the README does not document a command-line linting workflow, so anyone who wants a terminal pipeline should read the crate's own source before assuming a stable interface.
There is also harper-pos-utils and harper-brill, which suggest part-of-speech tagging derived from the Brill tagger lineage, plus harper-dictionary-wordlist for the dictionary. The README does not describe the rule format or how a new rule is added; that detail lives in the contribution guidelines it links to, not in the README itself.
Installing Harper and linting your first document
The README does not give a single install command for the whole project. It points at per-editor documentation pages, and the crates.io badge links to harper-ls, which is the crate most users will end up installing. The safest route is to follow the page for your editor: the README lists Visual Studio Code, Neovim, Helix, Emacs and Zed, plus an Obsidian integration.
For a Rust user who wants the language server without an editor extension, the crate name is the entry point:
cargo install harper-lsAfter that, the binary is what your editor launches. The exact arguments and configuration keys are documented on the harper-ls page rather than in the README, so check that page before wiring it into an LSP client config; do not guess flags.
If you want to work on Harper itself rather than use it, the workspace is a normal Cargo workspace, and the repository also carries a justfile and a flake.nix for task running and Nix environments. The website and web services have their own Docker setup, and the Dockerfile opens with a note that it is not needed to use Harper:
docker compose upThat compose file builds the site on port 3000 with a MariaDB service on 3306, and its first line says plainly that it is for development of the Harper website and web services. Running it will not give you a grammar checker to point at your notes.
The browser option needs no install at all. The README says Harper is small enough to load via WebAssembly and links to writewithharper.com, where the same core runs in the page.
Where Harper is the wrong choice
English only is the first boundary, and the README states it without hedging: Harper currently only supports English. If your team writes in German, Japanese or Portuguese, the extension mechanism is an invitation to contribute, not a feature you can adopt today.
The second boundary is the shape of the product. Harper is distributed as a language server and editor integrations. The repository contains harper-cli, but the README never documents a supported command for linting a directory from a shell, and it does not describe a CI recipe. If you want grammar checks enforced on every pull request as a blocking gate, you are not looking at a documented workflow here; you would be building on an undocumented crate or waiting for one.
The README also makes a commitment that cuts both ways: it says long lint times are considered bugs and asks users to file an issue when they hit one. That is a healthy stance for a young engine, and it also tells you the performance envelope is still being defended rather than settled.
Finally, the desktop story is thin. There is a harper-desktop directory and a fastlane directory in the repository root, but the README's link list covers editors, Obsidian, harper.js and the language server, not a downloadable desktop application. Do not plan around a packaged app you cannot confirm from the README.
Harper compared with LanguageTool and Grammarly
The README does the comparison itself, so the honest summary is the author's own framing. Against Grammarly, the difference is where the computation happens. Grammarly processes text on remote servers; Harper runs locally, which removes the network round trip and the question of what happens to your draft. That is the whole privacy argument, and it is a structural difference rather than a feature toggle.
Against LanguageTool, the difference is resource shape. LanguageTool's approach in the README's telling depends on a large n-gram dataset, roughly 16GB, and gigabytes of RAM, with linting that took several seconds on a moderate document. Harper's approach is a Rust core with a dictionary and rule set small enough to ship as WebAssembly. The trade-off is coverage: LanguageTool supports many languages and Harper supports one, so the smaller footprint is partly bought by doing less.
Harper.js is the third surface. The README links a harper.js documentation page, and the repository has a packages directory alongside harper-wasm, which means the same engine can be embedded in a JavaScript application rather than only spoken to over LSP. For a web app that wants inline suggestions without a backend, that is the relevant comparison point, not Grammarly's API.
Licence, maintenance and what upgrading costs you
Harper is licensed under Apache-2.0, which permits commercial and private use, modification and redistribution, and includes an explicit patent grant. It also requires that you keep the licence and notice files and state significant changes when you redistribute. That is a permissive arrangement, not a copyleft one, so embedding harper-core or harper-wasm in a product does not by itself oblige you to publish your own source. This is a description of the licence text, not legal advice; if you are shipping it inside a commercial product, have counsel read the NOTICE and attribution requirements.
The project is not archived, and the last push was on 2026-08-29, the same day as the v2.9.1 release. Releases have been landing roughly every two to three weeks across v2.7.0 on 2026-07-28, v2.8.0 on 2026-08-13 and v2.9.1 on 2026-08-29. If you install the language server through cargo, upgrading is a rebuild of the same crate, and the practical cost is re-reading the release notes for rule changes that may surface new diagnostics in documents you had already cleaned up.
The repository is a Cargo workspace with a pnpm monorepo on top of it, and package.json pins Node at >=22 and pnpm at ^10.6.3. Building the full stack, including the WebAssembly packages and the web app, therefore means maintaining both a Rust toolchain and a Node toolchain. Using only the editor integration avoids most of that.
Editorial conclusion
Adopt Harper if you write English prose in an editor that speaks LSP and you want suggestions computed on your own machine, with no document leaving the process. Skip it if you need languages other than English, or if you want grammar checking wired into a CI job, since the repository exposes no documented non-editor lint command. Before committing, verify two things yourself: that your editor is on the supported list (VS Code, Neovim, Helix, Emacs, Zed, or Obsidian), and that your machine can build the Rust workspace, because the crates.io badge points at harper-ls rather than a packaged desktop binary.
Frequently asked questions
How do I install the Harper grammar checker?
The README does not give a single install command. It links per-editor documentation pages for Visual Studio Code, Neovim, Helix, Emacs, Zed and Obsidian, and the crates.io badge points at the harper-ls crate, so follow the page for your editor or install that crate with cargo.
How do I use Harper in Obsidian?
The README lists a dedicated Obsidian integration page under its documentation links, so the setup steps live there rather than in the README. The README itself only confirms that the integration exists.
How do I use the Harper extension?
Harper reaches editors through harper-ls, its Language Server Protocol implementation, and the README links separate documentation for VS Code, Neovim, Helix, Emacs and Zed. Each of those pages describes the extension setup for that editor.
How do I use the Harper grammar checker?
Harper runs inside your editor through the harper-ls language server, or in the browser via the WebAssembly build at writewithharper.com. The README documents editor integrations for VS Code, Neovim, Helix, Emacs, Zed and Obsidian.
How do I install Harper?
The README does not document a single install path. It points to per-editor documentation pages and its crates.io badge links to the harper-ls crate, which is the component that editor integrations launch.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/automattic-harper)