The bug that ships in your docs
A model will hand you a --dry-run flag that never existed. It will tell you the default timeout is 30 seconds when it is 10. It will reference an endpoint called /v2/users/bulk with total confidence, and there is no bulk endpoint. None of this looks wrong. That is the whole trouble. A hallucinated parameter reads exactly like a real one, so a human reviewer skims past it, and now your quickstart tells people to pass an option that throws on the first call.
We hit this early when we started generating and updating documentation with an LLM. The prose was clean. The code samples ran in maybe four cases out of five. The fifth had a plausible ghost in it. And the failure was the expensive kind, because a reader trusts docs more than they trust a random blog, so a wrong default in the docs costs someone an afternoon.
The fix that worked for us is boring and small. We keep a registry of facts that are allowed to appear in generated content, and we run a check that flags anything outside it.
What goes in the registry
The registry is a flat list of the concrete, checkable things a model tends to get wrong. Not prose. Just the atoms.
For an API that means:
- endpoint paths (
/v1/messages,/v1/files) - parameter names and their exact spelling (
max_tokens, notmaxTokens) - defaults and limits (default page size 25, max 100)
- enum values (
roleis one ofuser,assistant,system) - type signatures for the SDK functions you document
- product numbers you cite (prices, counts, tiers)
We keep ours as YAML in the same repo as the docs, so a pull request that changes the API changes the registry in the same diff. That colocation matters more than the format. If the registry lives somewhere else, it rots, and a stale registry is worse than none because it fails you quietly.
A trimmed slice looks like this:
endpoints:
- path: /v1/messages
methods: [POST]
params:
max_tokens:
type: integer
required: true
temperature:
type: number
default: 1.0
range: [0.0, 1.0]
Every one of these is a fact you can check against the source of truth, which is your OpenAPI spec, your type definitions, or the running service itself. Many teams already generate half of this. If you have an OpenAPI document, you can pull paths, params, and enums straight out of it and skip the hand maintenance.
The check step
Generation is the easy half. The check is what earns the trust.
After the model writes a draft, we extract every candidate fact from it and compare against the registry. Concretely:
- Pull tokens that look like API surface out of the draft: things in backticks, things that match a path shape, flags starting with
--, numeric claims near words like "default" or "max". - For each one, ask: is this in the registry?
- Anything that is not gets flagged for a human, with the surrounding sentence attached.
That is it. You are not asking the model to grade itself. You are diffing its output against a list you control. A regex plus a set membership test covers most of the value. You can get fancier later, matching a claimed default against the registered default and flagging mismatches, not just unknown names, but even the crude version catches the ghost endpoint.
One design choice saved us pain: flag, do not autodelete. When the check finds something outside the registry, it does not silently strip it. Sometimes the model wrote about a real new feature and the registry is the thing that is behind. So the check produces a list of unverified claims and a person spends two minutes on that list instead of rereading the whole page. The output of the pipeline is a draft plus a short worry list, and the worry list is usually empty or three lines long.
This is genuinely how we keep AGINE Academy material accurate. The course text refers to real flags and real signatures, so the same registry-and-check idea runs over our own lessons before they publish. It is not a detector arms race. It is a list of true things and a diff.
Where it helps and where it does not
Be honest with yourself about the boundary. A registry catches invented names, wrong defaults, and misspelled params. It does not catch a sample that is syntactically fine, uses only real parameters, and still does the wrong thing. Logic errors sail right through, because every atom in them is real. For those you still need runnable examples and tests.
So we treat the registry as one layer. Real code samples get executed in CI. Conceptual claims still get a human read. The registry just removes the single most embarrassing failure mode, the confident nonexistent flag, and it removes it cheaply.
If you want to start today, do the smallest version. Take your OpenAPI file, dump the paths and param names into a set, write twenty lines that scan a markdown file for backticked tokens and print the ones not in the set. Run it on your existing docs first. You will almost certainly find a ghost already shipped. Then wire it after your generation step and let it grow only when a real miss teaches you what the next atom should be.
AGINE Academy is an independent product by AGINE AI (not affiliated with Anthropic). We teach building with Claude by doing the work, not watching lectures.
Top comments (0)