Harper

Elixir bindings to Harper — a fast, offline, privacy-first English grammar and spell checker written in Rust by Automattic. Harper runs entirely in-process: no server, no network, no LLM, no model download. It's the engine behind writewithharper.com.

This package wraps harper-core as a Rustler NIF and ships precompiled binaries for common targets, so most consumers don't need a Rust toolchain.

Installation

def deps do
[{:harper, "~> 0.1"}]
end

Precompiled artifacts are provided for macOS (aarch64/x86_64) and Linux (aarch64/x86_64, gnu). Other targets — including FreeBSD — build from source via rustler, which needs a Rust toolchain (≥ 1.85, for edition 2024). To force a source build on a supported target:

RUSTLER_PRECOMPILATION_FORCE_BUILD=1 mix deps.compile harper

Usage

Harper.lint/1,2,3 returns a list of Harper.Lint structs. It's a pure, stateless function and runs on a dirty CPU scheduler, so linting a large document won't block the BEAM's normal schedulers.

iex> Harper.lint("Ths is a testt.")
[
%Harper.Lint{
start: 0, end: 3, kind: "Spelling", priority: 63,
message: "Did you mean to spell `Ths` this way?",
suggestions: [%Harper.Suggestion{kind: "replace", text: "This"}, ...]
},
...
]
iex> Harper.lint("This is a clean sentence.")
[]

Dialects

English spelling is dialect-sensitive. lint/2 takes one of Harper.dialects/0 (:american — the default — :british, :canadian, :australian, :indian):

iex> Harper.lint("I love the colour blue.", :american) |> Enum.any?(& &1.kind == "Spelling")
true
iex> Harper.lint("I love the colour blue.", :british) |> Enum.any?(& &1.kind == "Spelling")
false

Custom dictionary

Pass words (proper nouns, brand terms, handles) that should never be flagged as misspellings — the server-side equivalent of "add to dictionary":

iex> Harper.lint("I write for acme daily.", :american, ["acme"]) |> Enum.any?(& &1.kind == "Spelling")
false

Offsets

Harper.Lint:start/:end are UTF-16 code-unit offsets into the linted string, end-exclusive — chosen so they drop straight into JavaScript string indexing and editor APIs (Quill, contenteditable ranges) without conversion.

Notes

Releasing (maintainers)

Precompiled tarballs are built locally on macOS and hosted on the sr.ht release ref. See scripts/:

License

Apache-2.0. Bundles the Apache-2.0 harper-core (statically linked into the NIF); each precompiled tarball ships LICENSE, LICENSE-APACHE, and a THIRD-PARTY-NOTICES file generated from the full dependency tree.