// HACKER NEWS — CYBERSECURITY
How I Over-Engineered My Book
My book has a linter that yells at me for hyphenating “open source.”1 It runs ~5,500 automated checks, rebuilds five formats on every git push, and fails the build if I so much as imply I still work at a job I left. For a book. That one person wrote.
I didn’t set out to do this. Most people start a writing project by firing up Word or Google Docs, and I started down that same path. I even tried some purpose-built authoring tools, but every tool felt inferior to the ones I used as a developer every day. I did “the only reasonable” thing and threw all of them out, writing the whole book on Git, Markdown, and a CI build pipeline. If you’ve read how I over-engineered my home network — twice — none of this will surprise you.
I’ve been making websites for decades, so the leap was short: the same tools that build websites could build books, no last-minute magic-trick reveal required to abracadabra a standard Word doc into a full-blown book. There were missteps,2 but in the end, I would not have written Open and Async any other way. Here’s how:
Naturally, the content itself lived as Markdown files in a Git repository. After all, that’s where I spend most of my day. I used VS Code, with a handful of prose extensions (listed below). Each chapter was its own Markdown file, and a single index.yml file defined the order, making it easy to re-order chapters or add new ones.
Practically, I wrote most of this book on an iPad — Codespaces in a browser tab, a Bluetooth keyboard, often nights and weekends while away from my desk — and the Git repository kept everything in sync no matter where I opened it. I could focus on the words, and a bad idea was one git revert away from gone.
Not to mention, I had real-time feedback on my writing right in my IDE from the various prose linters, just as I would have real-time feedback on my code from ESLint or Prettier.
With content as code, the next logical step — and the point where “reasonable” quietly left the building — was to set up automated tests. Testing prose the way you test code is something I’d argued for years; this was me taking it to an absurd extreme. I did that two ways: real-time, and on push (CI).
Locally, as I typed, I ran several VS Code extensions all giving me real-time feedback. Specifically:
All six also ran in CI (Alex and Write-good folded into Vale there; more on that below). Together, they layered hundreds of curated style rules over a full grammar engine — all of it underlining my mistakes in real time, the way a red squiggle flags a type error.
In addition to running those open source linters in CI (some blocking), I built a custom test suite of my own: a standalone Node script of content validators, a Vitest suite, and Playwright specs. The validators are the fun part. Each is a few lines that read the Markdown and push an error with a file-and-line pointer. My favorite: I don’t work at GitHub anymore, so any sentence claiming I still do fails the build.