惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
量子位
腾讯CDC
A
About on SuperTechFans
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
T
Tailwind CSS Blog
V
V2EX
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
罗磊的独立博客
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
V
Visual Studio Blog
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
有赞技术团队
有赞技术团队

Oskar Wickström

How Antithesis Found and Explained a Bombadil Race Condition Coding on Paper The Bombadil Terminal Experiment There and Back Again: From Quickstrom to Bombadil Computer Says No: Error Reporting for LTL A Year with the Daylight Computer Finding Bugs in a Coding Agent with Lightweight DST Machine: Learning; Human: Unlearning; How I Built “The Monospace Web” A Flexible Minimalist Neovim for 2024 Statically Typed Functional Programming with Python 3.12 Specifying State Machines with Temporal Logic Clearing Weeds and Planting Trees Introducing Quickstrom: High-confidence browser testing The TodoMVC Showdown: Testing with WebCheck Time Travelling and Fixing Bugs with Property-Based Testing Property-Based Testing in a Screencast Editor, Case Study 3: Integration Testing Property-Based Testing in a Screencast Editor, Case Study 2: Video Scene Classification Property-Based Testing in a Screencast Editor, Case Study 1: Timeline Flattening Property-Based Testing in a Screencast Editor: Introduction Why I’m No Longer Taking Donations Writing a Screencast Video Editor in Haskell Declarative GTK+ Programming with Haskell Finite-State Machines, Part 2: Explicit Typed State Transitions Modeling with Haskell Data Types Motor: Finite-State Machines in Haskell Automating the Build of your Technical Presentation Tagless Final Encoding of a Test Language Hyper: Elegant Weapons for a More Civilized Page Taking a Step Back from Oden
Catching Typos on My Website with Browser Testing
Oskar Wickström · 2026-05-13 · via Oskar Wickström

One neat thing about Bombadil’s specification language is that it’s plain TypeScript, with access to external NPM packages. I’ve written a specification that spell-checks my website — what you’re reading now — and I want to share how that turned out.

The inner loop (spell-checking):

Bombadil randomly walks the website and collects misspelled words as property violations. The specification uses nspell with American and British English dictionaries and a personal word list in the repository. This is fast and strict.

The outer loop (triage):

I’m running Claude Code with a spell-checking skill, a triage loop that goes something like this:

  1. Run Bombadil against the local development server for 5 minutes and capture the output. If no words flagged, we’re done.
  2. Collect each flagged word and the URL it appeared on.
  3. Triage each word into one of these buckets:
    • Real typo: fix the markdown source
    • Legitimate common word: add to the custom dictionary
    • Legitimate uncommon or very technical word: mark inline with spellcheck="false"
    • Extraction noise: add a unit test and fix the word extractor
  4. Run Bombadil against each failing URL to confirm the corrections.
  5. Go to step 1.

This is slow and loose.

The hybrid model seems to work well; it has flagged words in almost every blog post. It has fixed 13 real typos and added 130+ words to my personal dictionary. Example typos include “forseeable”, “similiar”, “perculiar”, “occured”. Some of these were 10 years old.

Claude doesn’t have to waste tokens spell-checking everything over and over. Right now I’m just running this locally, but you could imagine a more elaborate setup for large websites where the “inner loop” runs as a nightly job, invoking the “outer loop” only on violations. You could involve a human where needed, and build up a domain-specific dictionary over time.

Note that using an LLM is entirely optional. It just saves me some time. You can do triage on your own.

Why not spell-check the sources directly? Yes, that is often preferable, and I use spell in Neovim all the time. But it’s not always practical. At least in my experience, the tooling trips up on syntax and templating in more complicated setups. Maybe your editor handles this better than mine does, or maybe you’re fine with tools like typos and codespell, but I like the fact that this approach is external and checks the rendered output. Given that Bombadil interacts with web applications, you could even run this against dynamic applications to spell-check states deep in the UI.

Speaking of source-level checking: since the custom dictionary is a plain word list, I point Neovim’s spellfile at it and use zg to add words while I edit. A single source of truth that both tools write to.

vim.opt.spellfile = "/path/to/custom.utf-8.add"
vim.opt.spelllang = "en"

Being able to use NPM packages in specifications has turned out to be more useful than I expected. In addition to nspell, I’m using tlds to identify URLs. Bombadil is built for property-based testing of web applications, but with a specification language and package ecosystem at hand, its uses might be broader than my original vision.

If you’re interested in setting up something like this on your own, you’ll find the sources in my Bombadil playground.

Disclosure: I’m the original author and lead for the Bombadil project at Antithesis.