Tips & Tricks (업데이트: 2026. 6. 2.)

Claude Code로 문서 자동 생성하기: README, API 명세, ADR, 검증까지

Claude Code로 README, OpenAPI, ADR, 변경 이력을 만들고 Node 스크립트로 검증하는 실무 흐름입니다.

Claude Code로 문서 자동 생성하기: README, API 명세, ADR, 검증까지

문서 자동 생성은 문장력이 아니라 근거가 핵심이다

README, API 명세, ADR, 변경 이력은 프로젝트에서 가장 쉽게 뒤처집니다. 기능을 만들고 배포하고 장애를 처리하다 보면 문서는 늘 마지막으로 밀립니다. 문제는 나중에 새 팀원이 들어오거나 외부 사용자가 API를 볼 때 드러납니다. 실행 명령은 바뀌었고, 응답 형식은 달라졌는데 문서만 예전 상태로 남아 있는 식입니다.

Claude Code는 이 일을 빠르게 줄여 줍니다. 공식 Claude Code overview는 Claude Code가 코드베이스를 읽고, 파일을 수정하고, 명령을 실행할 수 있는 도구라고 설명합니다. 하지만 바로 그 능력 때문에 위험도 있습니다. 충분한 근거 없이 맡기면 존재하지 않는 명령, 실제로 없는 API 응답, 팀이 결정하지 않은 설계 이유까지 자연스럽게 써 버릴 수 있습니다.

이 글은 “문서를 잘 써 줘”가 아니라, 증거를 만들고, Claude Code에게 제한된 범위를 맡기고, 생성 결과를 검증하는 흐름을 다룹니다. 검증 기록까지 남기고 싶다면 Claude Code 검증 영수증 워크플로와 함께 사용하면 좋습니다.

전체 흐름: 컨텍스트 생성, 문서 갱신, 검증

가장 흔한 실수는 Claude Code에게 “README를 개선해 줘”라고만 말하는 것입니다. 그러면 Claude Code는 현재 세션에서 본 파일을 중심으로 추측합니다. 더 안정적인 방법은 git 상태, 최근 커밋, 패키지 스크립트, 기존 문서를 작은 컨텍스트 파일로 만든 뒤, 그 근거 안에서만 문서를 고치게 하는 것입니다.

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 경로, 요청, 응답을 기계가 읽을 수 있는 형식으로 적는 명세입니다. 초보자에게는 거창하게 보일 수 있지만, 핵심은 검증 가능한 문서를 만드는 것입니다.

먼저 저장소 컨텍스트를 만든다

아래 코드를scripts/doc-context.mjs로 저장하고 저장소 루트에서node scripts/doc-context.mjs를 실행하세요. 결과는docs/_generated/doc-context.md에 저장됩니다. 이 파일은 독자용 문서가 아니라 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}`);

큰 저장소 전체를 한 번에 읽히는 것보다, 현재 상태를 요약한 파일을 먼저 주는 편이 안정적입니다. 특히 README와 CHANGELOG는 최근 변경과 실제 명령을 확인하지 않으면 쉽게 틀립니다.

문서 갱신 규칙을 skill로 고정한다

Claude Code의 skill은 반복 작업 절차를 저장하는 방법입니다. 공식 skills / slash commands 문서SKILL.md/docs-refresh같은 명령으로 동작할 수 있다고 설명합니다. 문서 갱신은 매번 확인할 항목이 비슷하므로 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.

핵심은 범위를 문서로 제한하는 것입니다. Claude Code는 구현 파일도 수정할 수 있으므로, 문서 작업만 맡길 때는 “documentation only”를 분명히 적어야 합니다. 팀에서는 Claude Code 권한 설정 가이드를 참고해 읽어도 되는 파일과 실행해도 되는 명령을 정리하세요.

예시 1: README를 온보딩 문서로 만든다

README는 멋진 소개문이 아니라 첫날 실행 안내서입니다. 새 팀원에게 필요한 것은 설치, 실행, 테스트, 자주 나는 오류, 다음에 읽을 문서입니다. Claude Code에게도 이 독자 기준을 알려 줘야 합니다.

# 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`.

추상적인 설명보다 실제로 입력할 명령과 실패했을 때 돌아오는 방법이 중요합니다.

예시 2: API 문서는 OpenAPI로 남긴다

API 설명을 자연어로만 쓰면 나중에 검증하기 어렵습니다. 라우트, 검증 스키마, 테스트를 읽히고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라고 쓰면 문서는 오히려 해롭습니다. 근거가 없는 필드는 확정하지 말고 확인 필요 항목으로 남기세요.

예시 3: 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은 팀 합의를 나타내기 때문입니다.

예시 4: 변경 이력은 Unreleased에 초안으로 둔다

CHANGELOG는 릴리스 당일에 쓰면 기억에 의존하게 됩니다. 현재 diff를 보고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 제목, 코드 펜스, 미완성 플레이스홀더를 확인합니다.

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를 넣기보다, 수동으로 어떤 실패를 막아야 하는지 확인한 뒤 자동화하는 편이 안전합니다.

자주 생기는 실패

첫째, 존재하지 않는 명령을 쓰는 실패입니다. README의 명령은 반드시package.json, Makefile, CI 설정에서 확인해야 합니다.

둘째, API 명세를 그럴듯하게 꾸미는 실패입니다. 보기 좋은 OpenAPI가 실제 응답과 다르면 사용자에게 더 위험합니다.

셋째, 비밀 정보가 문서에 들어가는 실패입니다. .env, 토큰, 고객명, 내부 URL은 문서가 아니라 보호 대상입니다.

넷째, 생성 컨텍스트를 공개 문서와 섞는 실패입니다. docs/_generated/doc-context.md는 Claude Code 입력이지 독자용 문서가 아닙니다.

다섯째, 검증을 마지막 의식처럼 취급하는 실패입니다. diff가 작을 때docs:contextdocs:verify를 돌리는 편이 훨씬 쉽습니다.

템플릿, 자료, 상담 경로

개인 프로젝트라면 이 글의 두 Node 스크립트와docs-refresh skill만으로 시작할 수 있습니다. 프로젝트 규칙을 계속 유지하고 싶다면 CLAUDE.md 베스트 프랙티스와 함께 사용하세요.

자주 쓰는 명령을 빠르게 확인하고 싶다면 무료 Claude Code 치트시트가 가볍습니다. README, 검증, 리뷰, 디버깅 프롬프트를 반복해서 쓰는 팀이라면 Gumroad 템플릿이 시간을 줄여 줍니다.

팀 도입에서는 누가 최종 확인을 맡는지, 어떤 문서 오류가 배포를 막는지, Gumroad나 상담 CTA를 어디서 확인하는지가 중요합니다. 이런 운영 규칙은 도입 상담에서 실제 저장소 기준으로 설계하는 편이 빠릅니다.

실제로 시험해 본 결과

이 흐름으로doc-context.md를 만들고 README, OpenAPI, ADR, CHANGELOG를 나누어 Claude Code에 맡겨 보았습니다. 단순히 “README를 써 줘”라고 했을 때보다 가짜 명령이 줄었고, ADR에는 결정 이유가 더 잘 남았습니다. 다만 API 명세는 여전히 실제 응답과 사람이 대조해야 합니다. 완전 자동화보다 중요한 것은 빠른 초안, 명확한 근거, 검증 가능한 중단 지점입니다.

#Claude Code #documentation #JSDoc #API specs #auto-generation
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.