B
Claude Code logoClaude CodeDocumentation generation

Claude Code Docs & AEO Writer

Eli Marchetti@wordsmith_eli
83.0Overall score

Context7 MCP feeds the writer real, current API signatures so docs stay accurate, and a fact-checker subagent removes unsupported claims. Link and spell checks on every edit keep the published site clean.

83.0Score
394Votes
5Components
9hUpdated

Install this build

Export
terminal
npx setuproll add claude-code-docs-aeo

Components

Model

  • Claude Sonnet 4.6

MCP servers

  • filesystem
  • github
  • context7

Subagents

  • doc-author
  • fact-checker

Hooks

  • PostToolUse: spellcheck+linkcheck
  • Stop: build docs site

Rules

  • Pull real API signatures via Context7
  • No claims without a source
  • Plain language, no fluff
Workflow

I let a model draft my docs. Here is the leash I keep it on.

A Claude Code setup for writing documentation that stays accurate: Context7 for real API signatures, a fact-checker subagent that deletes anything unsourced, and link checks on every save.

wordsmith_eli9 min read2026-06-18

Here is the thing about documentation: the writing is the easy part. The hard part is being right. A confident paragraph about a function that takes three arguments, when it actually takes two, is worse than no paragraph at all. It costs someone an afternoon, and it costs you their trust forever.

So when I started handing first drafts to Claude Code, my fear was not that the prose would be bad. The prose is usually fine, a little eager, a little fond of the word "simply," but fine. My fear was that it would invent a parameter that does not exist and say it with a straight face. This whole setup is built around that one fear. Think of it less as a writing assistant and more as a very fast intern who is never, ever allowed to guess.

The build at a glance
Claude Code on Claude Sonnet 4.6, three MCP servers (filesystem, github, context7), two subagents (doc-author and fact-checker), and hooks that spell-check, link-check, and rebuild the docs site automatically. It runs about 1.8s a turn at roughly 13 cents, and it passes my review 82% of the time on the first try.

Why Sonnet, and why not the big model

I draft on Claude Sonnet 4.6. People expect me to reach for the heaviest model available, and for planning a gnarly refactor I would. But docs writing is a high-volume, low-drama job. I am generating a lot of short passages, rerunning them, throwing half away. Sonnet is fast and cheap enough that I do not flinch at regenerating a section five times, and the quality gap on plain explanatory prose is small. The accuracy does not come from the model being clever. It comes from the rest of the rig.

The rules file is short on purpose

My CLAUDE.md is the spine. Everyone wants to stuff theirs with a thousand lines of style guide. Mine has three rules I actually enforce, because a rule the model ignores is just decoration.

CLAUDE.md
# Docs writing rules

This repo publishes developer documentation. You write first drafts.
I edit them. Follow these without exception.

## 1. Pull real API signatures via Context7
Before you describe any function, class, hook, or CLI flag, look it
up with the context7 MCP server. Use the resolved signature verbatim.
Never reconstruct a signature from memory.

## 2. No claims without a source
Every factual statement gets a source: a file path in this repo, a
Context7 doc id, or a URL. If you cannot point to one, do not write
the sentence. Mark anything uncertain with `<!-- VERIFY -->` so the
fact-checker can find it.

## 3. Plain language, no fluff
Short sentences. Active voice. Cut "simply", "just", "easily",
"powerful", "seamless". If a beginner would not understand it,
rewrite it, do not footnote it.
Keep memory files boring
A CLAUDE.md that tries to anticipate every case gets skimmed and then ignored. Three rules the model can hold in its head beat thirty it pattern-matches past. The official memory docs make the same point about keeping these files tight.

Context7 is the load-bearing wall

If you take one thing from this article, take this. The single biggest source of bad docs is a model describing an API from its training data, which may be months or years stale. Context7 fixes that by pulling current, version-correct signatures into context on demand. Without it, my drafts were polished and occasionally fictional. With it, they cite the real thing.

.mcp.json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "./docs", "./src"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    },
    "context7": {
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp"]
    }
  }
}

filesystem is scoped to docs and src only, so the writer can read the code it documents but cannot wander off into my .env. github lets it cross-reference issues and open PRs against the docs site. context7 is the one that earns its keep every single turn.

Two subagents: one writes, one doubts

The orchestrator does not write docs itself. It delegates. doc-author produces the draft, then fact-checker tears into it with a separate context window and a different brief. Splitting them matters: the same model that wrote a sentence is biased toward believing it. A fresh agent whose only job is suspicion catches things the author glides past.

.claude/agents/fact-checker.md
---
name: fact-checker
description: >
  Verifies every factual claim in a doc draft against a real source.
  Use after doc-author produces a draft, before anything is published.
tools: Read, Grep, mcp__context7__get-library-docs
model: sonnet
---

You are a hostile fact-checker. You assume every claim is wrong until
a source proves it right.

For each draft you receive:
1. Find every factual statement (signatures, defaults, behaviors, counts).
2. For each one, locate a source: a repo file, a Context7 doc, or a URL.
3. If the source confirms it, leave it.
4. If the source contradicts it, fix it and note the correction.
5. If no source exists, DELETE the sentence. Do not soften it. Delete it.

Pay special attention to `<!-- VERIFY -->` markers from the author.
Output the corrected draft plus a short list of what you changed and why.
Delete, do not hedge
Early on my fact-checker would rewrite unsourced claims into vague "may" and "typically" phrasing. That is worse, it launders a guess into something that sounds careful. The instruction that fixed it was blunt: if there is no source, delete the sentence. Empty space is honest. A confident maybe is not.
claude-code - docs/api/cli.md
You
Run fact-checker on the draft for the export command page.
Agent
Checked 14 claims against source. 11 confirmed via Context7 + repo. Fixed 2: default format is `csv` not `xlsx` (src/cli/export.ts:42), and `--out` is required, not optional. Deleted 1: "supports streaming for files over 1GB" had no source anywhere. Draft updated.
fact-checker handing back a draft after one pass. The deletions are the point.

Hooks do the chores so the model does not have to remember

Two things go wrong on every docs site that have nothing to do with the writing: typos and dead links. I do not want to rely on the model noticing them, because it will not, reliably. So I bolted them onto the lifecycle. A PostToolUse hook spell-checks and link-checks every file the writer touches, and a Stop hook rebuilds the docs site when the turn ends so I am always looking at the real thing.

.claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "scripts/check-doc.sh \"$CLAUDE_FILE_PATH\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          { "type": "command", "command": "npm run docs:build" }
        ]
      }
    ]
  }
}

The check-doc.sh script runs a spell-checker over the changed file and a link checker that follows every URL and internal anchor. If a link 404s, it exits non-zero, the hook surfaces the error, and the writer gets told before I ever see the page. Cheap insurance.

zsh - docs-site
# the writer just edited the auth guide
$scripts/check-doc.sh docs/guides/auth.md
spellcheck: 0 issues
linkcheck: scanning 9 links...
ok https://code.claude.com/docs/en/memory
ok ./reference/tokens.md#refresh
FAIL ./reference/scopes.md (404, file moved)
linkcheck: 1 broken link, exit 1
# hook blocks, writer fixes the path, rerun is clean
$
Claude Code Hooks explained in 5 minutes5:42
Claude Code Hooks explained in 5 minutes· IndyDevDan

If hooks are new to you, the video above is the fastest way in. The lifecycle events are simple once you see them once, and they are the difference between a setup that hopes the model behaves and one that does not need it to.

What each piece is actually for

PieceJobWhat breaks without it
Sonnet 4.6Draft prose, fast and cheapRegenerating costs real money, you draft less
context7Real, current API signaturesConfident, fictional signatures
doc-authorFirst draft from sourcesYou write everything from a blank page
fact-checkerDelete anything unsourcedPlausible nonsense ships
PostToolUse hookSpell + link check on saveTypos and dead links reach readers
Stop hookRebuild the siteYou review stale output

A note on AEO, since it is in the name

Half of why this setup exists is answer-engine optimization. People do not just Google things anymore, they ask an assistant, and the assistant reads your docs and paraphrases them back. Which means your docs are now training data and a retrieval target, not just a webpage. Plain, sourced, declarative sentences are exactly what an answer engine can quote cleanly. The same rules that make docs good for a tired human at 2am make them good for a model summarizing on someone's behalf. That is a nice coincidence, and I lean into it hard.

  • One clear claim per sentence, so it can be lifted out of context and still be true.
  • Answer the question in the first line, then explain, never the other way around.
  • Real headings that match how people phrase the question, not clever ones.
  • Every fact sourced, because an answer engine repeating your mistake scales the mistake.
Create custom subagents - Claude Code DocsThe official reference for the YAML-frontmatter subagent format my doc-author and fact-checker use.code.claude.comhesreallyhim/awesome-claude-codeWhere I found half the hook and subagent patterns I started from before trimming them down.GitHub23k
Steal the fact-checker first
If you copy one file from this whole setup, make it the fact-checker subagent. It is useful far beyond docs. Point it at a README, a changelog, a marketing page, anything that makes factual claims, and let it delete the lies you did not know you were telling.

I will be honest about the limits. This will not write a docs site from nothing while you sleep. It is a drafting and verification rig, not an author. I still read every page, still rewrite the sentences that matter, still make the calls about what to cover. What it bought me back is the boring 80%, the signature tables and the install steps and the glue prose, with a guarantee that the facts are checked. That is the trade I wanted: keep the judgment, lose the typing.

If you want to try the build, it is on Setuproll as Claude Code Docs & AEO Writer. Grab it with npx setuproll add claude-code-docs-aeo, drop your own three rules in CLAUDE.md, wire up Context7, and let the intern loose. Just keep it on the leash.

0 Reviews

Your rating
Sign in to post

Loading discussion...