buildwiththis home

Test script: Check grammar and spelling for free

The script we wrote before testing, with every amendment and its timestamp. The verdict it produced: Best free grammar checker you can run yourself: LanguageTool vs Harper.

Published as written, with private emails and internal file paths removed. Times are Eastern. How we score: the rubric.

  • Job slug: check-grammar-and-spelling
  • Version / status: v1 · frozen 2026-10-16 15:45 ET, before the first run. Changes after freeze go under “Amendments”, dated, with the reason.
  • Rubric version: v1 (rubric)
  • Author / date: Lando (CEO), 2026-10-16

1. The job

You write landing pages, docs, emails and posts, and want typos and grammar mistakes caught before you publish, without paying for a subscription or sending your drafts to someone else’s server. You’re done when the tool flags most real mistakes, suggests the right fix, and doesn’t bury you in false alarms on correct text (including the tech words builders use every day).

2. Candidates

ToolVersionHow you get itTerms check (2026-10-16)Run mode
LanguageTool (open-source server)6.6 (latest release zip), English, default rules, no n-gram dataDownload the zip from languagetool.org, run its HTTP server locally (needs Java 17+)LGPL-2.1. Local server, no account. No benchmark clause.Agent-driven
Harperharper.js (latest on npm), American English, default rulesnpm install harper.js, runs in NodeApache-2.0. No account. No benchmark clause.Agent-driven

3. Fixed inputs

  • Test set (published with the results, SHA-256 5fbacaff26bfe00d5efca12e968484ef4aeb86272192a794e0a7efaa76e5e2d0): 60 sentences written for this test.
    • 40 sentences with exactly one seeded mistake each: 10 spelling, 8 subject-verb agreement, 8 wrong word (its/it’s, their/they’re, effect/affect, then/than, should of, loose/lose), 6 a/an, 8 repeated word, punctuation or capitals.
    • 20 correct sentences, 5 of them full of everyday builder words (npm, API, Supabase, Next.js, Tailwind, Postgres, GitHub, Cloudflare Pages, webhook).
  • Each sentence is checked on its own, in American English.

4. Fixed task

Using only <tool>'s official docs: install it, start it locally, and check each of the 60 sentences with its default rules. Save every flag: position, message and suggestions.

5. Follow-up rules

  • Time cap: 60 active minutes per tool to get from nothing to the first full set of results. Downloads are logged but excluded, up to 15 minutes.
  • Allowed: official README, docs and error messages. Manual interventions (C2): any step the docs don’t cover.

6. Steps

  1. Record the start time; install following the docs; log each docs page used.
  2. Run all 60 sentences, network switched off for the run; record time per sentence and peak memory (/usr/bin/time -v on the server or Node process).
  3. Run the check script; save its JSON.

7. Pass/fail checks

A seeded mistake counts as caught if any flag overlaps its exact position. It counts as fixed if applying the flag’s first suggestion gives exactly the corrected sentence. A false alarm is a correct sentence with any flag.

IDCheckPass if
G1 [core]Runs locally and returns results for all 60 sentencesYes
G2 [core]Catches mistakes≥ 70% of the 40 caught
G3Suggests the right fixFirst suggestion fixes ≥ 60% of the 40
G4Spelling≥ 9 of 10 spelling mistakes caught
G5Few false alarms≤ 3 of the 20 correct sentences flagged
G6FastMedian time per sentence ≤ 200 ms (after startup)
G7Fits a normal laptopPeak memory ≤ 2 GB

8. Quality checklist (C5)

IDItemPass if
Q1Works where you writeOfficial integrations for at least 2 of: VS Code, a browser, Obsidian, Google Docs/Word
Q2Custom dictionaryDocumented way to add your own words
Q3Turn rules offDocumented way to disable a rule
Q4Quickstart works as writtenThe docs’ install-and-check example runs unchanged
Q5Explains each flagEvery flag in the run has a human-readable message

9. Privacy checklist (C7)

IDItemPass if
S1Text stays on your computerWorks with the network switched off
S2No telemetryNothing in the docs or the network-off run shows usage data being sent
S3Official sourceDownloaded from the project’s official location over HTTPS
S4Licence allows commercial useYes, and stated clearly

10. Weights and tie-breaker

  • Weights: C1 35 · C2 15 · C3 10 · C4 10 · C5 10 · C6 10 · C7 10. C1: rubric anchor on the share of G1–G7 passed.
  • C2 (manual interventions): 5 = 0–1 · 4 = 2–3 · 3 = 4–5 · 2 = 6–8 · 1 = more. C3 (T = 60 active min): 5 = ≤15 · 4 = ≤30 · 3 = ≤45 · 2 = ≤60 · 1 = cap hit.
  • C4: 5 = $0 with no usage limits (runs locally). C5 and C7: checklist-count anchor.
  • C6: 5 = open-source licence that allows commercial use with no conditions for using it as a local tool or server (MIT, Apache, LGPL), runs offline, documented API · 4 = strong copyleft (GPL/AGPL) · 1 = hosted only.
  • Tie-breaker: C1, then fewer false alarms (G5), then more mistakes caught (G2).

11. Cleanup

  • Delete the downloaded server, packages and Java runtime files used only for the test. Keep results, logs and check JSON.

Amendments

  • v1.1 (2026-10-16, during the runs; none changes how a tool is scored):
    1. Java: the test machine runs Debian 13, which has no Java 17 package; we installed OpenJDK 21 (LanguageTool’s README asks for Java 17 or later). Not counted as an intervention: it’s the documented prerequisite.
    2. Memory log (15:46 ET, lt-r1): our run script’s shutdown command also stopped the time process, so the first run’s memory figure wasn’t written. We fixed our script and reran at once; the 60 results were identical to the first attempt.
    3. Network off: every run ran in a network namespace with only the loopback interface up (unshare -rn), which is how S1 and S2 were checked.
    4. Second runs: the first runs tied at 100, so both tools ran again. Results were identical, so the tie-breaker decided (see scoring notes).

Scoring notes (2026-10-16)

  • LanguageTool 6.6 (lt-r1, lt-r2), 100 both runs: 7 of 7. Caught 36 of 40 seeded mistakes and its first suggestion fixed all 36. Missed: “The results of the test shows”, “Their going to”, “Your welcome to”, and ”!!”. Spelling 10 of 10. False alarms on 3 of 20 correct sentences: “npm” (twice in one sentence), “Supabase”, and “the deploy” (it suggests “deployment”). Median 16–17 ms per sentence; 678 MB peak (Java server). C2 = 5, C3 = 5 (results 2 min after the download finished). C5 5 of 5: browser add-on can use the local server; spelling_custom.txt for your own words; disabledRules; the docs’ server command ran unchanged; every flag has a message. C6 = 5 (LGPL-2.1, used as a local server). C7 4 of 4.
  • Harper (harper.js 2.13.0) (harper-r1, harper-r2), 100 both runs: 7 of 7. Caught 29 of 40 (fixed 28). Missed 6 of 8 agreement mistakes (e.g. “Our servers was”, “There is three steps”), and “Its important”, “Your welcome”, “will not effect”, “could loose”, ”!!”. Spelling 10 of 10. False alarms on 3 of 20: “Supabase”, “js” in “Next.js”, and “Every one of the tests” (suggests “everyone”). Median 3 ms per sentence; about 500 MB peak (Node). C2 = 5, C3 = 5. C5 5 of 5 (VS Code, Chrome, Firefox, Obsidian; dictionary; rule config; the docs’ Node example ran unchanged; messages). C6 = 5 (Apache-2.0). C7 4 of 4.
  • Tie-breaker: C1 tied (7 of 7), false alarms tied (3 and 3), then mistakes caught: LanguageTool 36, Harper 29. LanguageTool is the pick.