003 — — 6 min

The runbook nobody reads.

Essay

Every environment I have inherited came with a documentation wiki, and in every one of them the page that mattered was last edited by someone who left two years ago. The pages were not wrong exactly. They were written for a reader who has time. At three in the morning nobody has time.

Documentation optimises for the wrong reader

Most internal docs are written as if the audience is a new hire on their second week, calm, curious, reading top to bottom. The actual audience is a tired engineer who has been paged, has one hand on a terminal, and needs a single answer in under thirty seconds. Those two readers want completely different artifacts, and we keep serving the first one.

If the on-call engineer has to read a paragraph before they can type a command, the document has already failed.

Write the failure, not the system

An architecture overview does not help during an incident. What helps is a list of the ways this thing actually breaks, and for each one, the exact command that confirms it and the exact command that fixes it. Organise by symptom, because symptom is all the reader has.

markdown · runbook-template.md
## Symptom: API returns 502 for all routes

Confirm:
    systemctl status api
    journalctl -u api --since "10 min ago" | tail -50

Most likely cause:
    Worker pool exhausted. Happens under sustained
    > 200 req/s because the pool is fixed at 32.

Fix:
    systemctl restart api        # buys ~20 minutes
    Then scale: edit WORKERS in /etc/api.env, restart.

Escalate if:
    Restart does not clear it within 2 minutes.
    Page the database owner - this pattern also
    appears when Postgres connections are saturated.

Four headings. No prose. A reader can act on this while half asleep, which is the only test that counts.

Verification beats description

The most common defect in a runbook is a step that says "check that the service is healthy." Healthy according to what? Replace every subjective instruction with a command and an expected output. If you cannot write the expected output, you do not actually know what healthy means, and that is worth discovering on a Tuesday afternoon instead of during an outage.

bash · health check with an assertion
#!/usr/bin/env bash
set -euo pipefail

# Not "check the service is up" - assert it, exit non-zero if not.
code=$(curl -s -o /dev/null -w '%{http_code}' \
        --max-time 5 http://127.0.0.1:8080/healthz)

if [ "$code" != "200" ]; then
  echo "UNHEALTHY: /healthz returned $code (expected 200)" >&2
  exit 1
fi

echo "OK: /healthz 200"

The three tests

Before a runbook counts as finished I put it through three checks, and most drafts fail at least one:

  • The stranger test. Someone who did not build the system follows it end to end, alone, without asking questions. If they get stuck, the document is wrong — not the person.
  • The one-page test. If the recovery path does not fit on one screen, split it. Nobody scrolls during an incident.
  • The expiry test. Every runbook names an owner and a review date. An unowned document decays into a lie with a timestamp.

Automate the parts you wrote down twice

A runbook step that gets executed the same way every single time is not documentation, it is an unimplemented script. Once you have written the same three commands into two different pages, that is the signal to turn it into a command with a name and a rollback path.

bash · the step, promoted to a command
# Before: three lines in a wiki that everyone
# copies slightly differently.
#
# After: one verb, one rollback, in version control.

ops restart api --reason "worker pool exhausted"
ops rollback api --to previous

What remains in the document is only the part that requires judgment. That is the part worth writing well, and it is usually a lot shorter than the wiki page it replaces.

The honest version

Documentation is not a deliverable you finish. It is a running cost you either pay in small amounts continuously, or pay all at once during an incident with interest. I have paid it both ways. The second way is significantly more expensive and considerably less fun.


Joseph Ali — Director of IT & Technology. hello@josephali.com