用Claude Code自动生成文档:README、API规格、ADR与验证流程
用Claude Code生成README、OpenAPI、ADR和变更日志,并用Node脚本验证,避免漂亮但错误的文档。
不要只让Claude Code写文档,要让它基于证据写
README、API规格、ADR和变更日志最容易在项目里落后。功能上线后,团队往往先修bug、发版本、处理用户反馈,文档就变成“以后再补”的任务。等到新人加入或外部用户查看API时,才发现命令已经变了,接口返回也和说明不一致。
Claude Code可以明显缩短这部分工作。官方的Claude Code overview说明,它可以读取代码库、编辑文件并运行命令。也就是说,它不仅能写一段说明,还能结合真实文件更新文档。但风险也在这里:如果没有给出清楚证据,它可能写出语气自然、结构完整、却并不存在的命令或接口。
本文把“自动生成文档”拆成一个可落地的流程:先生成仓库上下文,再用Claude Code skill更新README、OpenAPI、ADR和CHANGELOG,最后用Node脚本验证。你也可以把它和Claude Code验证收据流程一起使用,把“做了什么、怎么确认、还有什么风险”记录下来。
总体流程:先定义事实来源,再生成正文
最差的提示词是“帮我把README写好一点”。Claude Code会尽力完成,但它不知道哪些文件是事实来源,也不知道哪些信息不能公开。更稳妥的方式是先把package.json、git差异、最近提交和文件列表压缩成一份上下文,再让Claude Code在这个边界内更新文档。
flowchart LR
A["代码差异"] --> B["doc-context.mjs"]
B --> C["Claude Code skill"]
C --> D["README / OpenAPI / ADR / CHANGELOG"]
D --> E["verify-docs.mjs"]
E --> F["人工发布判断"]
ADR是Architecture Decision Record,也就是“架构决策记录”,用来解释为什么选择某个设计。OpenAPI是描述API端点、请求体和响应的机器可读格式。初学者不需要一开始就写得很完整,重点是让这些文档可以被检查,而不是只看起来专业。
第一步:生成给Claude Code看的仓库上下文
把下面的脚本保存为scripts/doc-context.mjs,在仓库根目录运行node scripts/doc-context.mjs。它会把当前脚本、未提交差异、最近提交和部分文件列表写入docs/_generated/doc-context.md。
import { execSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
function run(command) {
try {
return execSync(command, {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
}).trim();
} catch {
return "";
}
}
function readIfExists(filePath) {
return existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
}
const root = process.cwd();
const outDir = path.join(root, "docs", "_generated");
mkdirSync(outDir, { recursive: true });
const packageJson = readIfExists("package.json");
const packageSummary = packageJson
? JSON.stringify(JSON.parse(packageJson).scripts ?? {}, null, 2)
: "{}";
const fence = String.fromCharCode(96, 96, 96);
const trackedFiles = run("git ls-files")
.split(/\r?\n/)
.filter(Boolean)
.filter((file) => !file.startsWith("node_modules/"))
.filter((file) => !file.startsWith("dist/"))
.filter((file) => !file.startsWith(".git/"))
.slice(0, 400);
const changedFiles = run("git status --short") || "(no uncommitted changes)";
const recentCommits = run("git log --oneline -8") || "(no commits found)";
const content = [
"# Documentation Context",
"",
"## Package scripts",
`${fence}json`,
packageSummary,
fence,
"",
"## Changed files",
`${fence}text`,
changedFiles,
fence,
"",
"## Recent commits",
`${fence}text`,
recentCommits,
fence,
"",
"## Tracked file sample",
`${fence}text`,
trackedFiles.join("\n"),
fence,
"",
].join("\n");
const outFile = path.join(outDir, "doc-context.md");
writeFileSync(outFile, content);
console.log(`Wrote ${outFile}`);
这份文件不是给读者看的,而是给Claude Code看的工作材料。把它放在docs/_generated下面,可以避免它和正式文档混在一起。正式文档应该面向读者,生成上下文只负责给AI提供证据。
第二步:用skill固定文档更新规则
Claude Code的skill适合保存重复流程。官方skills和slash commands文档说明,SKILL.md可以创建像/docs-refresh这样的命令,旧的.claude/commands/仍然可用。文档更新每次都要检查同样的内容,所以很适合做成skill。
创建.claude/skills/docs-refresh/SKILL.md:
---
description: Refresh README, OpenAPI, ADR, and changelog from current code and generated documentation context.
---
## Inputs to inspect first
- Repository context: @docs/_generated/doc-context.md
- README: @README.md
- Existing docs: @docs
- Package metadata: @package.json
## Task
Update documentation only where the current code, package scripts, or git diff prove that the text is stale.
Required outputs:
1. README: setup steps, commands, environment notes, and troubleshooting.
2. OpenAPI: update `docs/api/openapi.yaml` when API routes changed.
3. ADR: create `docs/adr/NNNN-short-title.md` when a new architectural decision is visible.
4. CHANGELOG: add a draft entry under `Unreleased` when user-facing behavior changed.
Rules:
- Do not invent endpoints, commands, environment variables, prices, or dates.
- If evidence is missing, write a short "needs confirmation" note instead of guessing.
- Keep secret names generic. Never copy `.env` values into docs.
- After editing, run `node scripts/verify-docs.mjs` and report the result.
这里最重要的是“documentation only”。Claude Code可以修改代码,如果任务只是刷新文档,就必须明确限制范围。团队使用时,还应该参考Claude Code权限设置指南,决定哪些命令可以运行,哪些文件绝对不能读取。
实例一:把README改成新人入门手册
README不只是项目介绍。对新成员来说,它应该回答五个问题:如何安装、如何启动、如何测试、常见错误怎么处理、下一步读什么。让Claude Code更新README时,要指定读者是“刚clone仓库的人”。
# Task API
## Getting started
```bash
npm ci
npm run dev
```
## Commands
| Command | Purpose |
| --- | --- |
| `npm run dev` | Start the local server |
| `npm run test` | Run unit tests |
| `npm run docs:context` | Generate documentation context |
| `npm run docs:verify` | Verify documentation files |
## Troubleshooting
- If install fails, delete `node_modules` and run `npm ci` again.
- If API examples fail, confirm the server is running on the documented port.
- If generated docs mention unknown env vars, check `.env.example`, not `.env`.
这个例子短,但每一行都能执行或帮助排错。相比“写得更清楚”,给Claude Code一个具体读者会得到更实用的结果。
实例二:API规格用OpenAPI保存
API说明如果只写自然语言,很难验证。对于有接口的项目,让Claude Code根据路由文件、验证schema和测试更新docs/api/openapi.yaml。不要追求一次写完整,先保证已有内容真实。
openapi: 3.1.0
info:
title: Task API
version: 0.1.0
description: API for creating and listing tasks.
paths:
/api/tasks:
get:
summary: List tasks
responses:
"200":
description: Task list
content:
application/json:
schema:
type: object
properties:
tasks:
type: array
items:
type: object
required: [id, title, status]
properties:
id:
type: string
title:
type: string
status:
type: string
enum: [todo, doing, done]
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title]
properties:
title:
type: string
responses:
"201":
description: Created task
这里的陷阱是“补全过度”。如果真实接口返回open,文档却写todo,文档就会误导使用者。没有证据的字段应放进“needs confirmation”,不要硬写成确定结论。
实例三:用ADR保留设计理由
ADR的价值不是记录“我改了什么”,而是记录“为什么这样设计”。例如把生成上下文放在docs/_generated,就是一个需要说明的团队约定。
# ADR-0001: Keep generated documentation under docs/_generated
## Status
Accepted
## Context
Claude Code needs a compact summary of the repository before refreshing documentation.
Putting generated context beside hand-written docs can confuse reviewers.
## Decision
Generated context files will be written to `docs/_generated/`.
Hand-written documentation stays in `docs/api`, `docs/adr`, and root README files.
## Consequences
- Reviewers can separate generated context from authored documentation.
- The context file can be regenerated before each documentation refresh.
- The verification script must ignore unstable generated content when checking prose quality.
Claude Code可以起草ADR,但最终理由要由人确认。否则ADR会变成AI编出的解释,看似合理,却不能代表团队共识。
实例四:从差异生成CHANGELOG草稿
CHANGELOG最好在发布前就写草稿,而不是发布当天凭记忆补。让Claude Code把变化放到Unreleased下,不要让它提前确定版本号或日期。
# Changelog
## Unreleased
### Added
- Added documentation context generation for README, API specs, ADRs, and changelog updates.
### Changed
- Updated the documentation refresh workflow to verify generated files before publication.
### Needs confirmation
- Confirm the final release version and release date before moving this entry out of `Unreleased`.
这种写法保留了信息,也不会假装版本已经发布。
第三步:用脚本验证生成结果
把下面的脚本保存为scripts/verify-docs.mjs。它会检查必需文件、必需短语、ADR标题、Markdown代码围栏和明显的未完成占位符。
import { existsSync, readdirSync, readFileSync } from "node:fs";
import path from "node:path";
const requiredFiles = [
{
file: "README.md",
phrases: ["## Getting started", "## Commands"],
},
{
file: "docs/api/openapi.yaml",
phrases: ["openapi: 3.", "paths:"],
},
{
file: "CHANGELOG.md",
phrases: ["## Unreleased"],
},
];
function read(file) {
return readFileSync(file, "utf8");
}
function listMarkdownFiles(dir) {
if (!existsSync(dir)) return [];
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) return listMarkdownFiles(fullPath);
return entry.isFile() && /\.(md|mdx)$/.test(entry.name) ? [fullPath] : [];
});
}
const errors = [];
for (const item of requiredFiles) {
if (!existsSync(item.file)) {
errors.push(`${item.file}: missing file`);
continue;
}
const source = read(item.file);
for (const phrase of item.phrases) {
if (!source.includes(phrase)) {
errors.push(`${item.file}: missing phrase "${phrase}"`);
}
}
}
for (const adr of listMarkdownFiles("docs/adr")) {
const source = read(adr);
for (const heading of ["## Status", "## Context", "## Decision", "## Consequences"]) {
if (!source.includes(heading)) {
errors.push(`${adr}: missing ${heading}`);
}
}
}
for (const file of ["README.md", "CHANGELOG.md", ...listMarkdownFiles("docs")]) {
if (!existsSync(file)) continue;
const source = read(file);
const fenceMarker = String.fromCharCode(96, 96, 96);
const fenceCount = (source.match(new RegExp(fenceMarker, "g")) ?? []).length;
if (fenceCount % 2 !== 0) errors.push(`${file}: unbalanced code fence`);
if (/TODO|TBD|REPLACE_ME/.test(source)) {
errors.push(`${file}: unresolved placeholder remains`);
}
}
if (errors.length > 0) {
console.error("Documentation verification failed:");
for (const error of errors) console.error(`- ${error}`);
process.exit(1);
}
console.log("Documentation verification passed.");
在package.json里加上命令:
{
"scripts": {
"docs:context": "node scripts/doc-context.mjs",
"docs:verify": "node scripts/verify-docs.mjs"
}
}
团队使用时,可以根据官方settings documentation把项目设置和个人设置分开。下面的例子允许文档检查脚本,拒绝读取秘密文件。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(node scripts/doc-context.mjs)",
"Bash(node scripts/verify-docs.mjs)",
"Read(README.md)",
"Read(docs/**)",
"Read(src/**)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Bash(curl *)"
]
}
}
如果以后要在文件修改后自动验证,可以再阅读官方hooks reference。建议先手动运行,确认哪些失败真的应该阻止发布,再加入hooks。
常见失败和避免方法
第一种失败是写出不存在的命令。很多项目有npm run build,但你的项目可能用pnpm build或make build。README里的命令必须来自package.json、Makefile或CI配置。
第二种失败是API规格过度补全。结构漂亮不等于正确。公开前要和测试、真实响应或后端代码对照。
第三种失败是泄露秘密信息。.env、客户名、内部URL和令牌都不应该进入文档。用.env.example说明变量,用权限设置禁止读取真实秘密。
第四种失败是把内部上下文当作公开文档。docs/_generated/doc-context.md只是给AI看的材料,不应该直接面向读者。
第五种失败是把验证当作最后一分钟的形式流程。越早运行docs:context和docs:verify,越容易修复文档偏差。
模板、教材和咨询入口
个人项目可以先用本文的两个Node脚本和docs-refresh skill开始。如果想让Claude Code长期记住项目规则,可以继续阅读CLAUDE.md最佳实践,把构建命令、文档规则和审查标准写进项目说明。
如果你只是想把常用命令放在手边,可以从免费Claude Code速查表开始。每周都要重复README、调试、审查和文档提示词时,再考虑Gumroad模板包。
如果是团队导入,难点通常不是生成一篇README,而是谁负责最终确认、哪些文档会阻止发布、Gumroad和咨询CTA如何检查。这类规则适合通过导入咨询按真实仓库来设计。
我实际试用后的结果
我用这个流程先生成doc-context.md,再把README、OpenAPI、ADR和CHANGELOG拆成不同责任交给Claude Code处理。和直接说“帮我写README”相比,虚构命令明显减少,ADR也更容易保留“为什么”。不过API规格仍然需要人工和真实响应对照。最可靠的结果不是完全自动化,而是快速生成、证据清楚、验证步骤明确的文档流程。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code权限安全阶梯:逐步放开访问而不失控
从只读到有限编辑、验证命令和部署检查的 Claude Code 权限升级流程。
Claude Code 小PR证据包:让小改动真正可审查
用差异、验证命令、公开URL、CTA路径和回滚说明,把Claude Code的小PR变得可审查。
Claude Code 提交前 Review Gate:同时检查差异、测试、公开 URL 和 CTA
提交前用 Claude Code 审查差异范围、build、公开 URL、Gumroad 链接、咨询 CTA、缺少测试和无关文件。