Why this session exists
Every doc you've written in this course is plain text, in the repo, versioned by git. That IS docs as code - you just haven't been collecting the benefits yet. The benefits arrive when the machinery around the text starts working for you: a linter that catches style drift while you sleep, a CI gate that refuses to merge features without their docs, and a review habit that treats a doc bug exactly like a code bug. Without the machinery, docs rot the moment the author gets busy. With it, the repo defends its own documentation.
The philosophy and the loop 8 min live
Write the Docs defines docs as code as "a philosophy that you should be writing documentation with the same tools as code": issue trackers, version control, plain-text markup, code reviews, automated tests. It is not a tool you install. It is a decision that documentation gets the same production pipeline your code already earned.
LiveThe definition and the six-step workflow3 min▶
The whole workflow, end to end - notice that every step is one you already know from shipping code:
- Docs live as plain text in the repo (Markdown, reST, AsciiDoc), next to the code they describe.
- A change is a branch and a commit - no edit button on a live page, no "who changed this?" mystery. Git remembers.
- A PR opens and the docs get peer review, at the same bar as code. A reviewer can block a misleading sentence the same way they block a misleading variable name.
- CI runs checks: the site builds, links resolve, prose passes the linter, spelling passes the dictionary.
- Merge triggers build and deploy. The published docs are always exactly what's on main.
- Doc updates ship in the SAME PR as the feature. This is the load-bearing rule: "no doc, no merge". Everything else is tooling; this one is culture.
Write the Docs names the payoff plainly: writers integrate into product teams instead of orbiting them, developers write first drafts because the doc file is right there in their editor, and doc requirements become enforceable before merge instead of negotiable after release.
LiveWhy the loop beats the wiki3 min▶
Wikis fail predictably, and each failure maps to a loop step the wiki is missing:
- No review. Wiki edits publish instantly, so the first reader of a wrong sentence is a user in trouble. In the loop, a reviewer sees it first.
- No history you can use. Git blame tells you which commit, which PR, and which discussion changed a line. Wiki history tells you a name and a date, if that.
- No dead-doc detection. When code moves, a doc in the repo shows up in the same grep, the same refactor, the same PR diff. A wiki page just quietly stops being true.
- Docs live next to the code they describe. The person editing
metrics.pyseesdocs/reference-config.mdin the same file tree. Proximity is the cheapest freshness mechanism ever invented.
The wiki nobody could delete. A data team kept a wiki with three conflicting versions of the same onboarding page - nobody knew which was current, so nobody dared remove any. After migrating docs into the repo, the duplicate problem became impossible: one file, one path, one git history. The wiki stayed up for a year as a read-only museum, then someone finally turned it off and nothing broke.
Self-studyThe tooling landscape3 min read▶
Every docs-as-code stack is the same four choices; Write the Docs' guidance on choosing tools boils down to "pick what your team already uses for code":
- Version control: git, hosted on GitHub or GitLab. The PR/MR machinery is the review system - you don't build one.
- Markup: Markdown for approachability, reStructuredText or AsciiDoc when you need cross-references and structured metadata at scale.
- Generator: Sphinx (Python-native, reST-first), MkDocs (Markdown, fast start), Docusaurus (React sites), Hugo (speed at volume). All turn plain text into a website on push.
- Checks: prose linters (Vale, next section), link checkers, spell checkers - wired into the same CI that runs your tests. The operational discipline of running docs like a production system even has a name: DocOps.
Enforcement: linting and review culture 7 min live
A philosophy without enforcement is a poster on a wall. Enforcement comes in two layers: a machine layer (Vale, catching style drift on every commit) and a human layer (Google's review-culture rules, catching everything the machine can't). You need both, and they catch different bugs.
LiveVale in 5 minutes3 min▶
Vale (vale.sh) is a prose linter: it does for your sentences what ruff does for your Python. Rules live in YAML, config lives in a .vale.ini at the repo root, and it runs anywhere - your editor, a pre-commit hook, or a GitHub Action in CI.
- It ships the famous style guides as packages. One line in
.vale.iniand you're linting against Google's or Microsoft's published style guide - the same rules their own writers follow, with zero rule-writing on day one. - It's syntax-aware. Vale knows Markdown, so it lints your prose and skips your code blocks. Your
snake_case_variablesnever get flagged as spelling errors. - Three alert levels - suggestion, warning, error - and CI can be set to fail on errors only. That's the pragmatic setting: hard rules block the merge, soft rules educate without nagging.
LiveGoogle's three review-culture rules3 min▶
Google's documentation best practices guide is short and ruthless. Three rules do most of the work:
- Docs change in the same PR as the code, and get reviewed at the same bar. Not a follow-up ticket, not "I'll circle back". The diff that changes the behavior changes the description of the behavior, and a reviewer signs off on both.
- Minimum viable documentation. "A small set of fresh and accurate docs is better than a large assembly of documentation in various states of disrepair." Write less, keep it true, and prune like a bonsai - deliberate small cuts, continuously, instead of a heroic yearly rewrite.
- Delete dead docs. Wrong docs are not neutral; they actively harm, because readers trust them and act on them. Google's default on any migration is deletion, backed by regular team doc audits ("doc fixits") to find the pages nobody wants to admit are dead.
The runbook that paged the wrong team. An on-call engineer followed a stale runbook to escalate an alert - to a team that had been dissolved eight months earlier. Forty minutes of 3am confusion later, the fix wasn't updating the runbook. It was deleting it: the alert itself had been superseded, and the doc's only remaining function was to mislead. Deletion is a documentation act.
Self-studyWhat to automate, what needs humans2 min read▶
The trap after installing Vale is believing the green check means the doc is good. Linters and reviewers catch disjoint bug classes:
- Machines catch what's checkable: spelling, passive voice, "simply" and friends, sentence length, banned words, broken links, a site that won't build. Fast, tireless, and consistent - perfect for the style layer this course built in Sessions 2 and 3.
- Only humans catch what's judgeable: the doc is written for the wrong audience, the non-scope statement is missing, the example no longer matches the code's behavior, the steps are correct but in a baffling order. Everything Sessions 1, 4, 5 and 6 taught lives above the linter's ceiling.
- Division of labor: let Vale own the mechanical comments so human reviewers never type "passive voice" again - their whole attention goes to the questions only they can answer. That is Session 8's editing pass, institutionalized.
Point Vale at Pulse's docs ★ 8 min · everyone follows
We give the Pulse repo a .vale.ini, pull in Google's packaged style, and lint the oldest prose in the doc set: docs/notes-rewrite.md from Session 2. Watching a linter grade your own writing is the fastest style lesson there is.
Create .vale.ini at the repo root with the config below. It says: rules live in .vale/styles, report everything down to suggestions, fetch the Google package, and apply Vale's core rules plus Google's to every markdown file.
Run vale sync once - it downloads the Google style package into .vale/styles.
Run vale docs/notes-rewrite.md and read the output bottom-up: the summary line first, then the errors, then the warnings.
Fix one error, rerun, watch the count drop. That tight loop - lint, fix, relint - is the whole developer experience of docs as code.
errata-ai/vale-action annotates the PR diff with Vale's findings inline. Pre-commit hook: Vale runs on staged markdown before the commit even exists. Gate setting: fail CI on errors only, so suggestions educate and errors enforce.
Review a doc like a PR ★ 8 min · build your own
Vale would pass most of the paragraph below - and it's still a bad doc. This is the human layer: review the paragraph the way you'd review code, with line comments that name the problem and propose the fix. Everything you need was taught in Sessions 1-5.
Read the flawed paragraph below once as a newcomer. Note where you'd stop, scroll back, or DM the author.
Write review comments PR-style: quote the line, name the problem, propose the concrete rewrite. Aim for four comments before you peek at ours.
Compare with the sample review. The goal isn't matching wording - it's that every comment is actionable. "This is unclear" is not a review comment; "unclear WHICH script - name it" is.
Write the team norm: DOCS.md ★ 6 min · build your own
Machinery without a written norm decays into "that check we always skip". The last artifact of milestone 3 is four lines that make the rules explicit, visible, and quotable in a PR comment. Short on purpose: a contract nobody reads is not a contract.
Create DOCS.md at the Pulse repo root with the four rules below.
Read each rule and check it's enforceable: rule 1 by reviewers, rule 2 by CI, rules 3 and 4 by reviewers with a one-line comment. A rule nobody can enforce is a hope.
Adapt the wording for your real team and open it as a PR - the contract about reviews should itself get reviewed. If anyone pushes back, that conversation IS the adoption process working.
The contract that survived its author. A data platform team wrote exactly this kind of four-line norm before their tech lead left. Two years and three team-composition changes later, PRs still get the comment "rule 1?" - from people who never met the person who wrote it. Culture you write down outlives culture you model.
Try it yourself - this week ◐ 30-45 min total
- Install Vale locally (
brew install valeor the release binary), drop the demo's.vale.iniinto your real docs repo, and run it on your three most-read docs. Count errors before fixing anything - that number is your baseline. - Run the six-step scorecard from Part 1's ★ Try it now on your team's actual doc home, and identify the single cheapest missing step to add.
- Do one doc review this week using Demo 2's format: quote, problem, concrete rewrite. On a real PR if one exists; on an old doc as a self-review if not.
- Draft your team's DOCS.md and float it with one colleague before proposing it widely. Rule 1 gets pushback everywhere - rehearse your answer to "but it slows us down" (answer: the DM you'd otherwise get later is slower).
- Read the two Self-study cards: the tooling landscape and automate-vs-humans. Optional depth: writethedocs.org's Docs as Code guide and google.github.io/styleguide/docguide are both short and free.
Official sources covered
This session teaches the working content of these sources. What stays with the originals: Vale's full rule-authoring syntax and the complete Write the Docs guide prose.
Three questions before you go 🎯 ◐ 90 seconds
1 · Vale passes a doc with zero errors. What can you now be sure of?
Linters catch the checkable: spelling, passive voice, banned words. Wrong audience, missing non-scope, and stale facts all pass Vale with flying colors - only reviewers catch those.
2 · Why do docs change in the SAME PR as the code, rather than a follow-up ticket?
The merge gate is the one point where a reviewer can actually require the doc. Once the feature ships, the doc ticket competes with the sprint and loses - that's the lane where docs go to die.
3 · Google's guidance says to DELETE dead docs rather than leave them up "just in case". Why?
A missing doc sends the reader to a colleague; a wrong doc sends them confidently in the wrong direction - like the runbook that paged a dissolved team. Deletion is a documentation act, and git remembers everything anyway.