Skip to content

About the generated reference: the docs factory

The b8e command reference is not written by hand. Every command page, every flag table, the exit-code contract, the rules catalog, the output-format examples — all of it is generated from the CLI’s own structured sources and verified in CI. This document is about why a project would go to that trouble instead of just writing the docs, and what it buys in exchange for the machinery.

The problem: two copies of one fact always drift

Section titled “The problem: two copies of one fact always drift”

Hand-written reference documentation has a failure mode so common it is almost a law. Someone adds a flag, ships it, and forgets to update the docs. Someone renames an exit code and the reference now describes a contract the tool no longer honors. The docs and the code are two representations of the same fact — “here is what b8e scan accepts” — and the moment there are two copies, they begin to diverge. Nobody decides to let the docs rot; it happens by default, one missed edit at a time.

The deeper issue is that hand-written reference is unfalsifiable in the way that matters. Nothing fails when it drifts. The tests stay green, the build passes, and the only signal that the docs are wrong is a confused user weeks later. A fact that no check can prove stale is a fact that will eventually be stale.

The docs factory rejects the second copy entirely. Instead of a human transcribing the CLI’s surface into prose, each section of the reference reads the one place the fact already lives and projects it into Markdown:

  • Command pages embed the CLI’s own help output verbatim — the same source the terminal renders when you run --help, so the page cannot describe a flag the terminal doesn’t, or miss one it does.
  • The exit-code table is parsed from the exit-code definitions themselves.
  • The rules catalog is projected from the scanner’s own rule metadata.
  • The output-format examples are real renders of the actual formatters over one canonical finding, not hand-typed samples that approximate what the tool prints.

The word to hold onto is projection. The reference is a view of the source, the way a report is a view of a database. There is exactly one authoritative copy of each fact — the code — and the docs are a rendering of it. This is the same “one way to do each thing” instinct that runs through the rest of the CLI: if two things claim to be the source of truth, one of them is wrong.

Why generation alone is not enough: the drift guard

Section titled “Why generation alone is not enough: the drift guard”

Generating the docs solves half the problem. It would still be possible to generate once, commit the output, and then let the committed copy fall behind the source as the code moves — drift, just relocated. So the factory pairs generation with a drift guard that runs in CI: it regenerates the reference in memory and compares it against what is committed. If they differ, the check fails.

This is the piece that makes the whole approach trustworthy. The committed reference is not merely generated — it is continuously proven current. A pull request that changes a flag but not its generated page cannot merge, because the guard notices the committed docs no longer match what the code would produce. The failure mode of hand-written docs — silent divergence — is converted into a loud, blocking, mechanical signal. Drift stops being something a human has to remember to prevent and becomes something the machine refuses to allow.

It is worth noticing this is the same shape as the b8e gen --check drift guard that keeps a project’s generated BINCLUSIVE.md in sync with its config. The pattern — generate from a single source, then guard the committed output against regeneration — is a house convention, not a one-off.

Not everything in the reference can be projected, and the design is honest about where the line falls. The user-facing environment-variable list is a case worth dwelling on: the CLI reads dozens of BINCLUSIVE_* variables internally, but most are audit-runtime plumbing no user should ever set. Blindly projecting “every variable the code reads” would flood the docs with internal noise. So that one list is curated — a hand-picked subset of the variables a user actually sets.

But curation reopens the drift door, so it is fenced the same way everything else is: each curated entry is guarded by a test asserting the variable is still a real read in the source. The curation can choose which variables to document, but it cannot document one that no longer exists. The principle holds even where a human’s judgment is genuinely needed — human judgment picks the subset, a mechanical check keeps that subset honest.

Stepping back, the docs factory is not primarily about saving the effort of writing docs, though it does that. It is about changing the default. Under hand-written reference, the default is drift, and staying accurate takes constant vigilance. Under a generated-and-guarded reference, the default is accuracy, and drift is what takes effort — you would have to actively defeat the guard to ship stale docs.

That inversion is the whole point. The reference you read is as trustworthy as the code it describes, not because anyone was diligent, but because the structure makes “docs that match the tool” the path of least resistance and “docs that lie” the thing that fails to compile. It is the same correct-by- construction bet the rest of the CLI makes: don’t rely on remembering to do the right thing — arrange things so the wrong thing can’t quietly happen.