Generar documentación con Claude Code: README, API, ADR y verificación
Genera README, OpenAPI, ADR y changelog con Claude Code, y verifica el resultado con scripts Node prácticos.
La documentación generada necesita pruebas, no solo buen estilo
README, especificaciones de API, ADR y changelog suelen quedarse atrás porque el equipo prioriza implementar, probar y desplegar. El problema aparece cuando una persona nueva clona el repositorio y descubre que los comandos no funcionan, o cuando un consumidor de la API sigue una respuesta documentada que ya no existe.
Claude Code puede acelerar mucho este trabajo. La documentación oficial de Claude Code overview lo describe como una herramienta capaz de leer el código, editar archivos y ejecutar comandos. Eso sirve para producir documentación útil, pero también puede producir errores convincentes: comandos inventados, endpoints que no existen o decisiones arquitectónicas que el equipo nunca tomó.
La solución práctica es trabajar con evidencia. Primero generamos un contexto pequeño del repositorio, luego pedimos a Claude Code cambios acotados de documentación y, al final, ejecutamos un script de verificación. Para dejar constancia de la revisión, puedes combinar este flujo con el artículo de recibos de verificación en Claude Code.
Flujo recomendado: contexto, generación, verificación y decisión humana
Pedir “mejora el README” es demasiado abierto. Claude Code puede completar huecos con lo que parece razonable, aunque no esté respaldado por el repositorio. En cambio, conviene definir primero qué información cuenta como fuente de verdad: scripts de package.json, diff de git, commits recientes y documentación existente.
flowchart LR
A["Diff de código"] --> B["doc-context.mjs"]
B --> C["Skill de Claude Code"]
C --> D["README / OpenAPI / ADR / CHANGELOG"]
D --> E["verify-docs.mjs"]
E --> F["Decisión humana"]
ADR significa Architecture Decision Record: una nota corta que explica por qué se tomó una decisión técnica. OpenAPI es un formato legible por máquinas para describir rutas, request bodies y respuestas. No hay que convertirlo en burocracia; lo importante es que el documento sea verificable.
Generar contexto del repositorio
Guarda este archivo como scripts/doc-context.mjs y ejecútalo desde la raíz con node scripts/doc-context.mjs. Crea docs/_generated/doc-context.md, que será el material de trabajo para Claude Code.
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}`);
Este archivo no debe publicarse como guía para usuarios. Es contexto operativo para el agente. Separarlo bajo docs/_generated ayuda a revisar qué contenido fue generado para alimentar a Claude Code y qué contenido está escrito para lectores.
Crear un skill reutilizable para refrescar documentación
Claude Code usa skills para procedimientos repetibles. La guía oficial de skills y slash commands explica que un SKILL.md puede crear un comando como /docs-refresh; los antiguos archivos en .claude/commands/ siguen funcionando, pero los skills son el patrón más flexible.
Crea .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.
La frase “documentation only” evita que una tarea de documentación se convierta en una edición de código. Si trabajas con un equipo, revisa también la guía de permisos de Claude Code para limitar comandos y archivos sensibles.
Caso 1: README como guía de onboarding
Un buen README no intenta vender el proyecto. Ayuda a alguien que acaba de clonar el repositorio a instalar, ejecutar, probar y resolver errores comunes.
# 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`.
Al pedir a Claude Code que actualice el README, especifica el lector: “una persona que acaba de clonar el repo”. Eso produce instrucciones más concretas que “hazlo más claro”.
Caso 2: OpenAPI para especificaciones de API
La documentación de API en texto libre es fácil de leer, pero difícil de comprobar. Para APIs, pide a Claude Code que actualice docs/api/openapi.yaml leyendo rutas, esquemas de validación y tests.
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
El riesgo es que Claude Code complete demasiado. Si el servidor devuelve open y la especificación dice todo, el documento falla aunque se vea profesional.
Caso 3: ADR para guardar el motivo de una decisión
Un ADR no es un historial de tareas. Debe explicar una decisión técnica y sus consecuencias. Claude Code puede redactar un borrador, pero la razón final debe confirmarla el equipo.
# 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.
En este ejemplo, la decisión es separar contexto generado y documentación escrita para humanos. Esa separación facilita revisiones y reduce confusión.
Caso 4: Changelog como borrador en Unreleased
El changelog se mantiene mejor si se redacta antes del día de release. Pide a Claude Code que escriba bajo Unreleased y no fije versión ni fecha hasta que estén confirmadas.
# 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`.
Así conservas información útil sin fingir que el release ya ocurrió.
Verificar la documentación generada
Guarda este script como scripts/verify-docs.mjs. Comprueba archivos obligatorios, frases clave, estructura de ADR, code fences y 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.");
Añade scripts al package.json:
{
"scripts": {
"docs:context": "node scripts/doc-context.mjs",
"docs:verify": "node scripts/verify-docs.mjs"
}
}
Para equipos, la documentación oficial de settings ayuda a separar configuración compartida y local. Puedes permitir los scripts de docs y bloquear secretos:
{
"$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 *)"
]
}
}
Si después quieres verificación automática tras editar archivos, revisa la referencia oficial de hooks. Empieza manualmente; automatiza cuando sepas qué errores deben bloquear el flujo.
Errores frecuentes
El primer error es documentar comandos inexistentes. No aceptes comandos que no estén en package.json, Makefile o CI.
El segundo es inventar comportamiento de API. Una especificación bonita pero falsa es peor que una incompleta.
El tercero es filtrar secretos. .env, tokens, nombres de clientes y URLs internas no deben entrar en la documentación.
El cuarto es mezclar contexto interno con documentación pública. docs/_generated/doc-context.md es insumo para Claude Code, no una guía para usuarios.
El quinto es verificar al final, cuando el diff ya es grande. Ejecuta docs:context y docs:verify mientras el cambio todavía es pequeño.
Plantillas, productos y consultoría
Para un proyecto individual, los dos scripts y el skill docs-refresh bastan para empezar. Si quieres instrucciones persistentes, combínalo con la guía de buenas prácticas de CLAUDE.md.
Como siguiente paso ligero, usa la chuleta gratuita de Claude Code para tener comandos de verificación a mano. Si repites prompts de README, revisión, depuración y documentación cada semana, una plantilla de Gumroad te ahorra tiempo.
En equipos, lo difícil es decidir quién aprueba, qué error bloquea publicación y cómo se revisan los CTA de Gumroad o consultoría. Para eso, la consultoría de implementación permite diseñar reglas sobre tu repositorio real.
Resultado de la prueba práctica
Probé este flujo generando doc-context.md, separando responsabilidades de README, OpenAPI, ADR y CHANGELOG, y ejecutando verify-docs.mjs. Frente a un prompt simple de “escribe el README”, aparecieron menos comandos falsos y los ADR quedaron más fáciles de revisar. Las especificaciones de API todavía requieren comparación humana con respuestas reales. La meta no es documentación totalmente automática, sino documentación rápida, con evidencia visible y un punto claro de verificación.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Escalera de permisos de Claude Code para ampliar acceso sin perder control
Pasa de read-only a ediciones limitadas, comandos de prueba y checks de deploy con menos riesgo.
Claude Code Small PR Proof Pack: cambios pequeños que sí se pueden revisar
Un paquete de prueba para PRs de Claude Code: diff, checks, URL pública, CTA y rollback.
Gate de revisión antes del commit con Claude Code
Cómo revisar con Claude Code antes del commit: diff, build, URL pública, Gumroad, consultoría, tests y archivos ajenos.