DEV Community

Carlos Oliva Pascual
Carlos Oliva Pascual

Posted on • Originally published at stacknotice.com

Claude Code for Documentation: Keep Docs in Sync with Your Code (2026)

Documentation has a specific failure mode: written once, stale within weeks, actively misleading within months. Claude Code doesn't fix the cultural problem — it fixes the effort problem.

Start with an Audit

Before generating anything, get a picture of the current state:

Read through src/ and tell me:
1. Which exported functions have zero JSDoc/TSDoc
2. Which have outdated JSDoc (types that don't match the implementation)
3. Whether README.md accurately describes the current entry points
4. What's in the codebase that isn't mentioned in any documentation

Output as a plain list, one issue per line.
Enter fullscreen mode Exit fullscreen mode

JSDoc/TSDoc Generation

Take any undocumented function:

export async function createInvite(
  workspaceId: string,
  email: string,
  role: 'admin' | 'member' | 'viewer',
  expiresInDays?: number
): Promise<{ token: string; expiresAt: Date; link: string }> {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

Prompt:

Read src/lib/invites.ts and add TSDoc to every exported function.
Format: summary  @param  @returns  @throws  @example
Do not change any implementation code. Only add the JSDoc blocks.
Enter fullscreen mode Exit fullscreen mode

Claude's output:

/**
 * Creates a pending workspace invitation and returns a tokenized invite link.
 *
 * @param workspaceId - The workspace to invite the user into
 * @param email - Email address of the person being invited
 * @param role - Permission level granted when the invite is accepted
 * @param expiresInDays - Days until the invite expires (default: 7)
 * @returns Object containing the token, expiry date, and full invite URL
 * @throws {ConflictError} If a pending invite already exists for this email
 *
 * @example
 * const invite = await createInvite('ws_abc123', 'alice@example.com', 'member')
 * // Send invite.link via email
 */
export async function createInvite(/* ... same implementation */)
Enter fullscreen mode Exit fullscreen mode

Batch JSDoc for an entire directory

for file in src/lib/*.ts; do
  echo "Documenting $file..."
  cat "$file" | claude -p \
    "Add TSDoc to every exported function and type. Do not change implementation.
     Output the complete file with documentation added." \
    --output-format text > "$file.tmp" && mv "$file.tmp" "$file"
done
Enter fullscreen mode Exit fullscreen mode

Always review after — Claude occasionally misinterprets ambiguous parameter names.

README Generation

Read the entire project — package.json, src/, .env.example, and any existing README.md.

Generate a README.md with:
1. What this project does (from the code's actual behavior)
2. Prerequisites (Node version, required env vars from .env.example)
3. Setup (exact commands)
4. Running locally (from package.json scripts)
5. Project structure (top-level only)
6. Environment variables (table: name, required/optional, description, example)
7. Deployment (only if Dockerfile or CI config exists)

Be accurate. If unsure about something, say so rather than guessing.
Enter fullscreen mode Exit fullscreen mode

Key instruction: "accurate, not complete." A README that says "I'm not sure about the deployment step" is better than one that confidently describes the wrong process.

Pre-push hook: README staleness check

#!/bin/bash
# .git/hooks/pre-push

CHANGED=$(git diff --name-only origin/main...HEAD -- src/)

if [ -n "$CHANGED" ]; then
  NEEDS_UPDATE=$(echo "$CHANGED" | claude -p \
    "These src files changed: $CHANGED
     Read README.md. Does it reference anything that might now be inaccurate?
     Answer: YES or NO and one sentence." \
    --output-format text)

  if echo "$NEEDS_UPDATE" | grep -q "^YES"; then
    echo "⚠️  README may need updating: $NEEDS_UPDATE"
    exit 1
  fi
fi
Enter fullscreen mode Exit fullscreen mode

This asks you to verify, not auto-update. Auto-updating docs without review produces confidently wrong docs.

Architectural Decision Records (ADRs)

ADRs document why a decision was made. Most valuable, least likely to be written.

We just decided: Use Drizzle ORM instead of Prisma for all new queries.

Write an ADR in this format:
# ADR-[number]: [Short title]
Date: [today]
Status: Accepted

## Context
## Decision
## Consequences (Positive / Negative / Risks)
## Alternatives Considered
Enter fullscreen mode Exit fullscreen mode

Generate a draft from git history:

DIFF=$(git show "abc123")

claude -p "This commit made significant architectural changes:
$DIFF
Write a draft ADR explaining the problem it solves, decision made, and trade-offs." \
  --output-format text > docs/decisions/draft-adr-$(date +%Y%m%d).md
Enter fullscreen mode Exit fullscreen mode

PostToolUse Hook: Remind on Implementation Changes

// .claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const f = process.env.TOOL_INPUT_FILE || ''; if (f.includes('/src/') && !f.includes('.test.') && !f.includes('.md')) { console.log('📝 Check if JSDoc and README need updating for ' + f); }\""
          }
        ]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Every time Claude edits a source file, this reminder appears in context.

CLAUDE.md Documentation Rules

## Documentation rules

### When adding or changing a function:
- Add/update TSDoc on every exported function you touch
- Format: summary → @param → @returns → @throws (if applicable) → @example
- Skip private/internal functions unless non-obvious

### When the change affects:
- Environment variables → update .env.example and README env table
- CLI commands → update README setup section
- New dependencies → add to README prerequisites if they need setup

### Don't document:
- Implementation details obvious from the code
- Internal state variables
- Test setup functions
Enter fullscreen mode Exit fullscreen mode

Keeping Docs Current

Periodically run:

Read docs/ and compare against the current src/.
List documentation that references code, APIs, or behaviors
that no longer exist or have changed significantly.
Enter fullscreen mode Exit fullscreen mode

This surfaces outdated docs faster than a human review.

The rule of minimum viable docs: only document what changes frequently or isn't obvious from the code. Over-documented code creates maintenance overhead without proportional value.


Full article at stacknotice.com/blog/claude-code-documentation-2026

Top comments (0)