Generowanie i utrzymanie dokumentacji z Claude Code
Claude Code generuje dokumentację referencyjną (komentarze JSDoc i TSDoc, specyfikacje OpenAPI, README, dokumenty architektury i changelogi) na podstawie kodu źródłowego, a nie z pamięci czy starej wiki. Generowanie to łatwiejsza połowa. Hooki, deterministyczne bramki, takie jak walidacja TypeDoc i lint Redocly, oraz bezobsługowa kontrola rozjazdów w CI dowodzą, że dokumentacja wciąż zgadza się z kodem.
Ta strona jest dla programistów odpowiedzialnych za dokumentację serwisu i dla tech leadów, którzy chcą, żeby dokumentacja przestała obciążać code review. Znasz ten obrazek: README wciąż opisuje polecenie usunięte w poprzednim sprincie, openapi.yaml zawiera pole, które dawno zmieniło nazwę, a nowe osoby zadają te same pytania, bo ARCHITECTURE.md opisuje system sprzed dwóch refaktoryzacji. Nikt nie aktualizuje dokumentacji ręcznie, więc rozwiązaniem musi być workflow, który ją regeneruje, i bramka, która pada, gdy dokumentacja się rozjedzie.
Co zyskasz, generując dokumentację w Claude Code
Dział zatytułowany „Co zyskasz, generując dokumentację w Claude Code”- Tabelę decyzyjną: które dokumenty Claude Code ma generować, które tylko szkicować i jaka kontrola dowodzi poprawności każdego z nich.
- Prompty do skopiowania dla TSDoc, OpenAPI, README ze sprawdzonymi poleceniami i
ARCHITECTURE.mdz cytowaniami. - Skrypt
docs:checki hookStop, który nie pozwala zakończyć sesji z zepsutą dokumentacją. - Bezobsługowy raport rozjazdów dla pull requestów, zwracający ustrukturyzowany JSON, na podstawie którego CI może oblać build.
Zanim zaczniesz, zapisz konwencje dokumentacji w CLAUDE.md (zobacz system pamięci Claude Code), żeby każda sesja pisała dokumentację tak samo.
Którą dokumentację powinien pisać Claude Code?
Dział zatytułowany „Którą dokumentację powinien pisać Claude Code?”Claude Code jest wiarygodny tam, gdzie odpowiedź jest w kodzie. Zawodzi tam, gdzie odpowiedź jest w czyjejś głowie. Zdecyduj osobno dla każdego typu dokumentu, zanim napiszesz prompt:
| Dokument | Źródło prawdy | Rola Claude Code | Co dowodzi poprawności |
|---|---|---|---|
| TSDoc / JSDoc eksportowanych symboli | Sygnatury, typy, rzucane błędy | Generuje | Walidacja TypeDoc pada na każdym nieudokumentowanym eksporcie |
| Specyfikacja OpenAPI | Handlery tras, schematy walidacji, middleware | Generuje | Lint Redocly plus test kontraktowy porównujący ścieżki ze specyfikacji z zarejestrowanymi trasami |
| Sekcja instalacji w README | Skrypty, które faktycznie działają | Generuje, potem uruchamia | CI wykonuje polecenia z README na czystym checkoucie |
ARCHITECTURE.md | Struktura katalogów, punkty wejścia, przepływ danych | Generuje z cytowaniami | Skrypt sprawdza, czy każda cytowana ścieżka istnieje |
| Changelog | git log między tagami | Szkicuje | Właściciel wydania poprawia treść i zatwierdza |
| Rekordy decyzji („dlaczego wybraliśmy X”) | Rozumowanie ludzi | Tylko wywiad i szkic | Właściciel decyzji pisze lub zatwierdza każde uzasadnienie |
Ostatni wiersz jest najważniejszy. Zapytany „dlaczego ten moduł używa kolejki?”, Claude Code poda wiarygodnie brzmiący powód, niezależnie od tego, czy taki powód istnieje. Przy uzasadnieniach użyj workflow z wywiadem opisanego w decyzjach architektonicznych, których agenci się trzymają i zostaw „dlaczego” człowiekowi.
Generuj dokumentację referencyjną z kodu
Dział zatytułowany „Generuj dokumentację referencyjną z kodu”-
Najpierw dodaj bramki do repozytorium, żeby już pierwszy wygenerowany dokument był sprawdzany. Dla serwisu w TypeScripcie:
Okno terminala npm install -D typedoc @redocly/cliNastępnie dodaj skrypt
docs:checkdopackage.json:{"scripts": {"docs:check": "typedoc --emit none --entryPointStrategy expand --entryPoints src --validation.notDocumented --treatValidationWarningsAsErrors && redocly lint docs/openapi.yaml && bash scripts/check-doc-citations.sh"}}--emit nonewaliduje bez generowania HTML. Z flagą--treatValidationWarningsAsErrorsTypeDoc 0.28 (sprawdzone na 0.28.20) kończy się niezerowym kodem, gdy którykolwiek eksportowany symbol wsrc/nie ma dokumentacji. -
Uruchom raz
npm run docs:checki zapisz listę błędów. To backlog, który przekażesz Claude Code. -
Wklej poniższy prompt TSDoc do sesji Claude Code, po jednym katalogu naraz. Jeden katalog na sesję utrzymuje diff na tyle mały, że da się go wyrywkowo sprawdzić.
-
Uruchom ponownie
npm run docs:check. Zielony wynik oznacza, że każdy eksport ma dokumentację, a specyfikacja się parsuje. Nie oznacza, że opis jest prawdziwy. Dlatego istnieją test kontraktowy i kontrola cytowań opisane niżej.
Warunek „krócej niż ciało funkcji” to najtańsze lekarstwo na główny nawyk Claude Code przy dokumentacji, czyli nadmierne tłumaczenie. Linia @throws to miejsce, w którym generowana dokumentacja wygrywa z ręczną: Claude Code przechodzi łańcuch wywołań i znajduje ponownie rzucane błędy, o których autor zapomina.
Wygeneruj specyfikację OpenAPI zgodną z działającymi trasami
Dział zatytułowany „Wygeneruj specyfikację OpenAPI zgodną z działającymi trasami”Specyfikacja wygenerowana z samych handlerów pomija to, co dokłada middleware: odrzucenia autoryzacji, nagłówki limitów zapytań i kształt, jaki handler błędów nadaje każdej porażce. Wymień middleware w prompcie i poproś o test, który wiąże specyfikację z routerem, bo lint dowodzi tylko, że YAML jest poprawnym OpenAPI.
Od tej chwili wyrocznią jest test kontraktowy: trasa dodana bez wpisu w specyfikacji zmienia CI na czerwono, bez względu na to, czy dodał ją człowiek, czy agent. Resztę workflow dla API znajdziesz w budowaniu API REST i GraphQL z Claude Code.
Napisz README ze sprawdzonymi poleceniami
Dział zatytułowany „Napisz README ze sprawdzonymi poleceniami”README zawodzi nowe osoby w poleceniach, nie w opisach. Każ Claude Code wykonać każde polecenie, które zapisze, a potem niech CI wykona je jeszcze raz.
W CI wyciągnij ten jeden blok i uruchom go w świeżym kontenerze. Ekstraktor czyta tylko pierwszy blok bash w sekcji Quick start i zatrzymuje się na następnym nagłówku ##, więc polecenia z dalszej sekcji nigdy nie uruchomią się przypadkiem. README, na którym job pada, zawiódłby też nową osobę w zespole:
# CI step in a clean container: run the README's Quick start block, stop at the first failure.awk 'c&&/^```/{exit} c{print;next} /^## /{if(f)exit; f=($0 ~ /^## Quick start/); next} f&&/^```bash/{c=1}' README.md > /tmp/quickstart.shtest -s /tmp/quickstart.sh || { echo "README has no Quick start bash block"; exit 1; }bash -euo pipefail /tmp/quickstart.shWygeneruj ARCHITECTURE.md, który da się sprawdzić automatycznie
Dział zatytułowany „Wygeneruj ARCHITECTURE.md, który da się sprawdzić automatycznie”Poproś o cytowania w stałym formacie, a potem sprawdzaj je skryptem zamiast czytać tekst linijka po linijce.
Zapisz poniższy skrypt jako scripts/check-doc-citations.sh. Pada, gdy cytowana ścieżka przestała istnieć, a właśnie tak zwykle psują się dokumenty architektury:
#!/usr/bin/env bash# Fails if docs/ARCHITECTURE.md cites a path that does not exist.set -euo pipefailmissing=0while read -r path; do [[ -e $path ]] || { echo "missing: $path"; missing=1; }done < <(grep -oE '`[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+)+/?(:[0-9]+)?`|`[A-Za-z0-9_.-]+\.(json|ya?ml|toml|md|lock|ts|js|mjs|py|go|rs|sql)(:[0-9]+)?`' docs/ARCHITECTURE.md \ | tr -d '`' | sed -E 's/:[0-9]+$//' | sort -u)exit $missingSkrypt sprawdza każdy fragment w backtickach, który zawiera ukośnik (w dowolnym katalogu, nie tylko src/), oraz każdy plik w katalogu głównym z typowym rozszerzeniem, na przykład package.json albo pnpm-lock.yaml. Końcówkę :linia usuwa przed sprawdzeniem. Ceną tej szerokości jest to, że fragment w backtickach, który nie jest ścieżką, na przykład request/response, zostanie zgłoszony jako brakujący, więc w tym dokumencie używaj backticków tylko dla ścieżek.
Lista „Drift found” bywa najcenniejszym wynikiem całego ćwiczenia. To darmowy audyt każdej nieaktualnej dokumentacji, którą Claude Code przeczytał po drodze. Tę samą technikę cytowań przy poznawaniu kodu opisuje poznawanie nieznanego kodu z Claude Code.
Naszkicuj changelog z historii gita
Dział zatytułowany „Naszkicuj changelog z historii gita”Changelog celowo pozostaje szkicem. Jego treść to obietnica wobec użytkowników, więc zatwierdza go właściciel wydania.
Utrzymuj dokumentację w zgodzie z kodem podczas pracy Claude Code
Dział zatytułowany „Utrzymuj dokumentację w zgodzie z kodem podczas pracy Claude Code”Wygenerowana dokumentacja zaczyna się starzeć w chwili, gdy trafia kolejna zmiana. Dwa hooki zamykają tę lukę w obrębie sesji. Mechanikę wszystkich zdarzeń opisuje strona hooki Claude Code: zabezpieczenia, bramki i kontekst na żywo. Tu są dwa hooki, których potrzebuje workflow dokumentacji.
Przypomnienie w PostToolUse, które Claude Code faktycznie widzi. Zwykły echo z hooka PostToolUse nie trafia do modelu. Żeby przypomnienie znalazło się w kontekście Claude Code, zwróć je jako additionalContext:
#!/usr/bin/env bash# .claude/hooks/doc-drift-reminder.sh (PostToolUse, matcher "Edit|Write")set -uo pipefailfile=$(jq -r '.tool_input.file_path // empty')case "$file" in */src/routes/*|*/src/middleware/*) jq -nc '{hookSpecificOutput: {hookEventName: "PostToolUse", additionalContext: "You changed an API route or middleware. Before you finish, update docs/openapi.yaml if the request, response, auth or error contract changed."}}' ;;esacexit 0Hook Stop, który uruchamia bramkę. Przypomnienie to rada, a ten hook ją egzekwuje. Blokuje pierwszą próbę zakończenia pracy, gdy docs:check nie przechodzi, a jeśli ponowna próba też się nie uda, oddaje sprawę człowiekowi:
#!/usr/bin/env bash# .claude/hooks/docs-before-stop.sh (Stop)set -uo pipefailretrying=$(jq -r '.stop_hook_active')[[ -z $(git status --porcelain) ]] && exit 0if out=$(npm run --silent docs:check 2>&1); then exit 0; fiif [[ $retrying == "true" ]]; then jq -nc '{systemMessage: "docs:check still fails after one retry. Stopping for a human."}' exit 0fijq -nc --arg r "docs:check fails. Fix the docs, not the check. Last 30 lines:$(tail -n 30 <<<"$out")" '{decision: "block", reason: $r}'Zarejestruj oba w .claude/settings.json:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/doc-drift-reminder.sh", "args": [] }] } ], "Stop": [ { "hooks": [{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/docs-before-stop.sh", "args": [], "timeout": 180 }] } ] }}Uruchom chmod +x .claude/hooks/*.sh, a potem otwórz /hooks w sesji i sprawdź, czy oba się załadowały.
Wyłapuj rozjazdy dokumentacji w CI dzięki bezobsługowemu Claude Code
Dział zatytułowany „Wyłapuj rozjazdy dokumentacji w CI dzięki bezobsługowemu Claude Code”Hooki działają tylko w sesjach, które ich używają. Zmiany przychodzą też od ludzi, od innych agentów i z sesji bez twoich ustawień, więc pull request potrzebuje własnej kontroli. Poniższy job tylko czyta: pyta Claude Code, czy diff unieważnił jakąś dokumentację, i zwraca zwalidowany werdykt w JSON-ie, który na zielony albo czerwony wynik zamienia skrypt, a nie model.
Zapisz go jako .github/workflows/docs-drift.yml:
name: docs-drifton: pull_requestpermissions: contents: readjobs: drift: # Fork PRs get no secrets; skip them instead of failing. if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v7 with: fetch-depth: 0 # the diff needs the base branch's history persist-credentials: false - uses: actions/setup-node@v7 with: node-version: 22 - run: npm install -g @anthropic-ai/claude-code - name: Report docs made stale by this diff env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} BASE_REF: ${{ github.base_ref }} run: | schema='{"type":"object","required":["stale"],"properties":{"stale":{"type":"array","items":{"type":"object","required":["doc","reason"],"properties":{"doc":{"type":"string"},"reason":{"type":"string"}}}}}}' out=$(claude -p "Run git diff --name-only origin/$BASE_REF...HEAD, then read the changed files and README.md, docs/openapi.yaml and docs/ARCHITECTURE.md. List every statement in those docs that this diff made false, with the doc path and the reason. Ignore wording and style. Return an empty list if nothing is stale." \ --bare --setting-sources "" --strict-mcp-config \ --permission-mode dontAsk --allowedTools "Bash(git diff *)" \ --output-format json --json-schema "$schema" --max-budget-usd 2) jq -e '.subtype == "success"' <<<"$out" >/dev/null || { echo "drift check did not complete"; exit 1; } if [ "$(jq '.structured_output.stale | length' <<<"$out")" -gt 0 ]; then jq -r '.structured_output.stale[] | "\(.doc): \(.reason)"' <<<"$out" exit 1 fiKażdą flagę sprawdzono w claude --help 2.1.283 (kanał latest, 2026-09-26). fetch-depth: 0 jest konieczne: domyślny płytki checkout nie ma origin/main, więc git diff się wysypuje, a job nie zgłasza niczego przydatnego. --bare --setting-sources "" --strict-mcp-config sprawia, że hooki, ustawienia i .mcp.json z pull requesta nie uruchomią się w jobie, który ma dostęp do sekretu. Tryb bare pomija też logowanie subskrypcją, dlatego job używa ANTHROPIC_API_KEY. dontAsk odrzuca każde wywołanie, które w innym trybie wymagałoby zgody, więc job może czytać checkout i uruchamiać git diff, ale nie może używać narzędzi Edit ani Write. Linia if: pomija pull requesty z forków, które GitHub uruchamia bez sekretów. Nie przechodź na pull_request_target, żeby dostarczyć do nich klucz: ten wyzwalacz uruchamia kod z forka obok twojego sekretu. Podłączenie do CI i wybór wyzwalaczy opisują skryptowanie Claude Code oraz konfiguracja pipeline’ów z Claude Code.
Żeby regenerować dokumentację po merge’u, uruchom podobny job na main z wąskim prawem zapisu: --allowedTools "Edit(./docs/**)" "Edit(./README.md)". Potem niech skrypt wykona npm run docs:check i wgra zmiany jako artefakt z patchem; osobny job z contents: write i pull-requests: write, w którym nie działa żaden agent, nakłada patch i otwiera pull request. W jobie agenta zostaw persist-credentials: false, żeby tam, gdzie działa agent, nie leżał token z prawem zapisu. Nigdy nie pozwalaj żadnemu z tych jobów pushować na main.
Przy pull_request GitHub uruchamia docs-drift.yml z samego pull requesta, więc pull request może tę kontrolę zmienić albo usunąć. Zanim potraktujesz ten job jako bramkę przed merge’em, obejmij .github/ wpisem w CODEOWNERS i wymagaj przeglądu code ownera.
Rozdziel duży backlog dokumentacji między subagentów
Dział zatytułowany „Rozdziel duży backlog dokumentacji między subagentów”Przegląd dokumentacji całego repozytorium zapycha główny kontekst zawartością plików. Przekaż każdy obszar subagentowi, żeby każdy czytał dokładnie, a zwracał tylko podsumowanie.
Wielokrotnego użytku specjalistów od dokumentacji, z własnymi narzędziami i instrukcjami, opisuje strona własni subagenci w Claude Code.
Które skille i serwery MCP pomagają przy dokumentacji?
Dział zatytułowany „Które skille i serwery MCP pomagają przy dokumentacji?”Sięgnij po skill, gdy chcesz powtarzalnej procedury, którą agent wczytuje na żądanie. Sięgnij po serwer MCP, gdy agent potrzebuje danych na żywo, których nie przeczyta z repozytorium.
-
doc-coauthoring(Anthropic, anthropics/skills) prowadzi trzyetapowy workflow: zbieranie kontekstu, dopracowanie i struktura, test z czytelnikiem. Pasuje do dokumentów, których Claude Code nie powinien wymyślać sam: design docs, propozycji i rekordów decyzji.Okno terminala npx skills add anthropics/skills --skill doc-coauthoring -a claude-code -
Context7 (
@upstash/context7-mcp) wczytuje do kontekstu dokumentację bibliotek zewnętrznych w konkretnej wersji. Użyj go, gdy twoja dokumentacja opisuje integrację, żeby przykład pasował do wersji biblioteki z lockfile’a, a nie do tej z danych treningowych modelu.Okno terminala claude mcp add --scope user context7 -- npx -y @upstash/context7-mcp
Więcej opcji znajdziesz w katalogach skille do dokumentacji i pisania oraz serwery MCP z dokumentacją, takie jak Context7.
Jak sprawdzić wygenerowaną dokumentację bez czytania każdej linijki?
Dział zatytułowany „Jak sprawdzić wygenerowaną dokumentację bez czytania każdej linijki?”Czytaj tylko to, czego żadna kontrola nie obejmie. Cała reszta ma bramkę, a jej wynik trafia do pull requesta jako dowód:
| Kontrola | Polecenie | Co wyłapuje | Kto zatwierdza |
|---|---|---|---|
| Pokrycie eksportów | npm run docs:check (krok TypeDoc) | Nieudokumentowane lub nowo dodane eksporty | CI |
| Poprawność specyfikacji | npx @redocly/cli lint docs/openapi.yaml | Niepoprawne OpenAPI, zepsute $ref | CI |
| Specyfikacja zgodna z routerem | tests/contract/openapi-routes.test.ts | Brakujące lub widmowe endpointy | CI |
| README działa | Blok „Quick start” uruchomiony w czystym kontenerze | Martwe polecenia, brakujące wymagania | CI |
| Cytowania w architekturze | scripts/check-doc-citations.sh | Odwołania do przeniesionych lub usuniętych plików | CI |
| Rozjazd w tym PR | Bezobsługowy raport rozjazdów | Dokumentacja, którą diff uczynił nieprawdziwą | CI; poprawia autor PR |
| Uzasadnienia i treść changeloga | Brak | Wymyślone powody, mylące obietnice | Właściciel modułu, właściciel wydania |
Przegląd przez człowieka kurczy się do ostatniego wiersza: sekcji „dlaczego” i changeloga. Tam osąd człowieka jest niezastąpiony i tam wygenerowane zdanie może wyrządzić realną szkodę. Pełną listę tego, co powinien zawierać pull request od agenta, znajdziesz w opisie pakietu dowodów (evidence bundle).
Kiedy wygenerowana dokumentacja zawodzi
Dział zatytułowany „Kiedy wygenerowana dokumentacja zawodzi”Dokumentacja jest długa i nic nie mówi. Claude Code opowiada kod prozą. Naprawa: dopisz do promptu „Keep each comment shorter than the function body” i „explain why and when to use it, not what each line does”, a regułę przenieś do CLAUDE.md, żeby działała w każdej sesji.
Specyfikacja OpenAPI przechodzi lint, ale jest błędna. Lint sprawdza strukturę, nie prawdziwość. Zwykle winne jest middleware, o którym prompt nie wspomniał. Naprawa: wskaż w prompcie katalog middleware i niech o zgodności specyfikacji z routerem decyduje test kontraktowy, a nie lint.
Claude Code ignoruje przypomnienie o rozjeździe. Hook wypisuje komunikat przez echo, a stdout z PostToolUse nie trafia do modelu. Naprawa: zwróć komunikat jako hookSpecificOutput.additionalContext, jak w przykładzie wyżej, albo zakończ hook kodem 2 z komunikatem na stderr.
Job regenerujący dokumentację w CI kończy się sukcesem i niczego nie zmienia. Każdy zapis został odrzucony: sesje -p nigdy nie pytają o zgodę, a reguły uprawnień z projektu mogą nie obowiązywać w CI. Naprawa: wypisz .permission_denials z wyniku JSON i przekaż dokładne reguły Edit(...) przez --allowedTools.
Rekord decyzji zawiera pewnie brzmiący, wymyślony powód. Model wypełnił lukę w kodzie wiarygodną historią. Naprawa: każ Claude Code wpisywać „reason not recorded” wszędzie tam, gdzie kod, opisy commitów ani powiązane zgłoszenia nie podają powodu, a potem poproś właściciela decyzji o uzupełnienie luk.
Hook Stop zapętla się albo blokuje bez końca. Kontrola pada z powodu, którego Claude Code nie naprawi, na przykład brakującej zależności deweloperskiej. Naprawa: gałąź stop_hook_active w przykładzie kończy pracę po jednej ponownej próbie, a sam Claude Code kończy turę po ośmiu kolejnych kontynuacjach wymuszonych przez hooki Stop (limit zmienia CLAUDE_CODE_STOP_HOOK_BLOCK_CAP). Jeśli pętla trwa dalej, uruchom npm run docs:check samodzielnie i napraw środowisko, zanim spróbujesz ponownie.
Job rozjazdów pada z unknown revision albo zgłasza pusty diff. Checkout jest płytki, więc brakuje gałęzi bazowej. Naprawa: ustaw fetch-depth: 0 w actions/checkout, jak w workflow powyżej, i sprawdź w lokalnym klonie gałęzi PR, czy git diff --name-only origin/main...HEAD wypisuje pliki.
Dokąd dalej z dokumentacją w Claude Code
Dział zatytułowany „Dokąd dalej z dokumentacją w Claude Code”- Hooki Claude Code: zabezpieczenia, bramki i kontekst na żywo omawiają każde zdarzenie hooków i testowanie hooków na przygotowanych danych.
- Skryptowanie Claude Code: uruchomienia bezobsługowe, potoki, cron i hooki gita to kolejny krok, żeby raport rozjazdów działał według harmonogramu.
- Dokumentacja jako skuteczny kontekst dla AI to druga połowa tematu: dokumentacja pisana do czytania przez agentów, nie tylko przez ludzi.
- Ten sam workflow w innych narzędziach: generowanie dokumentacji z Codex oraz automatyczne generowanie dokumentacji w Cursorze.