Gerar documentação com Claude Code: README, API, ADR e verificação
Gere README, OpenAPI, ADR e changelog com Claude Code e valide tudo com scripts Node práticos.
Documentação gerada precisa de evidência
README, especificação de API, ADR e changelog costumam ficar desatualizados porque a equipe prioriza implementar, testar e publicar. Quando uma pessoa nova clona o repositório, descobre que os comandos mudaram. Quando alguém consome a API, percebe que o retorno real não bate com o texto.
Claude Code reduz esse trabalho porque consegue ler o código, editar arquivos e executar comandos. A página oficial Claude Code overview descreve exatamente essa atuação dentro do fluxo de desenvolvimento. Mas a mesma capacidade também exige cuidado: sem evidência, Claude Code pode escrever uma documentação bonita para um comando inexistente ou um endpoint que nunca foi implementado.
O fluxo seguro é simples: gerar um contexto verificável, pedir mudanças de documentação com escopo limitado, rodar uma verificação automática e só então publicar. Para registrar a revisão, combine este artigo com o workflow de recibo de verificação do Claude Code.
Fluxo: contexto, geração, verificação e decisão humana
Pedir “melhore o README” é amplo demais. Claude Code precisa saber qual é a fonte da verdade: scripts do package.json, diff do git, commits recentes, documentação existente e arquivos relevantes.
flowchart LR
A["Diff do código"] --> B["doc-context.mjs"]
B --> C["Skill do Claude Code"]
C --> D["README / OpenAPI / ADR / CHANGELOG"]
D --> E["verify-docs.mjs"]
E --> F["Decisão humana"]
ADR significa Architecture Decision Record, ou registro de decisão de arquitetura. É uma nota curta que explica por que uma escolha técnica foi feita. OpenAPI é um formato para descrever rotas, requisições e respostas de API. O ponto não é criar burocracia, mas deixar a documentação verificável.
Gerar o contexto do repositório
Salve o script abaixo como scripts/doc-context.mjs e execute node scripts/doc-context.mjs na raiz. Ele cria docs/_generated/doc-context.md, um resumo para Claude Code usar como base.
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}`);
Esse arquivo não é documentação pública. Ele é contexto de trabalho para o agente. Mantê-lo em docs/_generated ajuda a separar evidência temporária de documentação escrita para leitores.
Criar um skill para atualizar documentação
Claude Code usa skills para procedimentos repetíveis. A documentação oficial de skills e slash commands explica que um SKILL.md pode criar comandos como /docs-refresh; arquivos antigos em .claude/commands/ continuam funcionando.
Crie .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.
O trecho “documentation only” evita que uma tarefa de docs vire mudança de implementação. Em equipe, vale revisar também o guia de permissões do Claude Code para definir comandos permitidos e arquivos sensíveis.
Caso 1: README como guia de onboarding
Um README bom ajuda quem acabou de clonar o repositório. Ele deve mostrar instalação, execução, testes, erros comuns e próximos documentos.
# 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`.
Ao pedir para Claude Code atualizar o README, diga quem é o leitor. “Pessoa nova depois de clonar o projeto” gera respostas mais úteis do que “deixe mais claro”.
Caso 2: API com OpenAPI
Documentação de API em texto livre é difícil de validar. Peça para Claude Code ler rotas, schemas de validação e testes antes de atualizar 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
O risco é completar demais. Se a resposta real usa open e a especificação diz todo, o documento está errado mesmo parecendo profissional.
Caso 3: ADR para registrar decisões
ADR não é log de tarefas. Ele registra contexto, decisão e consequências.
# 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 pode escrever o rascunho, mas a decisão final precisa ser humana. O ADR representa o acordo da equipe.
Caso 4: CHANGELOG como rascunho em Unreleased
Changelog é melhor quando começa antes do release. Peça para Claude Code escrever sob Unreleased e não definir versão nem data sem confirmação.
# 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`.
Assim você guarda informação sem fingir que o release já aconteceu.
Verificar os documentos gerados
Salve como scripts/verify-docs.mjs. O script confere arquivos obrigatórios, frases esperadas, estrutura de ADR, code fences e placeholders evidentes.
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.");
Adicione ao package.json:
{
"scripts": {
"docs:context": "node scripts/doc-context.mjs",
"docs:verify": "node scripts/verify-docs.mjs"
}
}
A documentação oficial de settings mostra como separar configurações de projeto e locais. Um começo seguro é permitir scripts de docs e negar segredos.
{
"$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 *)"
]
}
}
Se quiser automação após edição de arquivos, leia a referência oficial de hooks. Comece manualmente e só automatize o que realmente deve bloquear.
Falhas comuns
A primeira falha é documentar comando inexistente. Comandos de README devem vir de package.json, Makefile ou CI.
A segunda é inventar comportamento de API. OpenAPI bonita, mas falsa, piora suporte e integração.
A terceira é vazar segredo. .env, tokens, nomes de clientes e URLs internas não devem entrar em docs.
A quarta é publicar contexto interno. docs/_generated/doc-context.md é entrada para Claude Code, não manual de usuário.
A quinta é verificar tarde demais. Rode docs:context e docs:verify enquanto o diff ainda é pequeno.
Templates, produtos e consultoria
Para projeto individual, os dois scripts Node e o skill docs-refresh bastam. Para regras persistentes, combine com o guia de boas práticas de CLAUDE.md.
Se quiser um próximo passo leve, use a cola gratuita de Claude Code. Se você repete prompts de README, revisão, debug e documentação toda semana, um pacote de templates no Gumroad reduz retrabalho.
Em equipes, o desafio é decidir quem aprova, qual erro bloqueia publicação e onde verificar CTA de Gumroad ou consultoria. Para isso, a consultoria de implementação ajuda a criar regras no contexto do seu repositório real.
Resultado do teste prático
Testei o fluxo gerando doc-context.md, separando responsabilidades de README, OpenAPI, ADR e CHANGELOG, e rodando verify-docs.mjs. Comparado com um pedido genérico de README, apareceram menos comandos falsos e os ADRs ficaram mais fáceis de revisar. A especificação de API ainda precisa ser comparada com respostas reais. O objetivo não é documentação totalmente automática, mas documentação rápida, baseada em evidência e com ponto claro de verificação.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Como pedir ao Claude Code para mexer em um único arquivo
Do desastre em que um 'deixa melhor' alterou 40 linhas nasceu um template de prompt que limita o escopo, valida e permite reverter.
Recuperar de negações de permissão no Claude Code sem enfraquecer guardrails
Transforme um comando negado em plano seguro com motivo, alternativa, provas e critérios de nova tentativa.
Claude Code Harness Smoke Test: prova de 15 minutos antes de confiar em um agente
Um smoke test para escopo, áreas bloqueadas, comandos de prova, URL pública e CTAs de receita no Claude Code.