Update Project Documentation
Two responsibilities:
- CLAUDE.md — concise project overview (always loaded)
- .llmdocs/ — detailed per-concept docs (loaded on demand). All files here are persistent design docs.
1. CLAUDE.md — The Map
Scope
Find all CLAUDE.md and .llmdocs/ directories in the project and update each. Pay attention to subfolder layers, scope and bounded contexts. Do not leak concepts between documents at different layers. Each CLAUDE.md and .llmdocs/ covers its own directory level and below, never parent concerns.
If the user provided specific guidance or focus areas, apply that context when deciding which docs to update and what to emphasize.
Gather Context
Never run git directly. The baseline script that ships with this plugin covers everything this skill needs from git. Run each command from the repository root and write the script's full path every time, because shell variables do not persist between commands.
Start with the plan. It finds every CLAUDE.md and its .llmdocs/, including required files that do not exist yet, resolves each document's baseline, lists what changed since it, and says what to do with each document. When the user's guidance names directories to focus on, pass them after llmdocs. Otherwise pass nothing.
bash "${CLAUDE_SKILL_DIR}/../../scripts/doc-baseline.sh" plan llmdocs [<focus-dir>...]
The plan prints one block per action.
## updatenames a baseline, a scope, and the documents that share it, followed by the commits, diff stat, and status since that baseline. Bring these documents up to date. A document the changes do not affect keeps its content.## newlists documents to write from the current code. They need no history.## unchangedand## outside the focuslist documents to leave exactly as they are.
head none means the repository has no commits. Every document is new.
For an update block, count the files in its stat. At more than 20, skip the full diff and read the changed files directly. At 20 or fewer, read the diff. Untracked files, marked ??, appear in no diff, so read them directly either way. The scope can be the block's scope or a single file, because it is a git pathspec.
bash "${CLAUDE_SKILL_DIR}/../../scripts/doc-baseline.sh" diff <sha> <scope>
Then, for each CLAUDE.md/.llmdocs/ pair with documents to update or write:
- Read the current
CLAUDE.mdand every file in.llmdocs/(if they exist) - Explore codebase at that directory level and below
- Review conversation history for relevant decisions, changes, or lessons learned
- Use the changes and conversation context to identify what changed. llmdocs are current state specification, not a change log, not a decision log, not a historical record. Never record historical information or choices made, only the specification as it stands at the time of writing the llmdocs.
Write/Update CLAUDE.md
Target: under 500 lines. Every line must earn its place.
# <Name>
<1-2 line purpose of this directory/component>
## Stack
<bullet list: language, frameworks, key deps relevant to this level>
## Layout
<key dirs and what they contain at this level>
## Commands
<build, test, lint, deploy — commands only>
## Conventions
<style, naming, patterns — only what prevents mistakes>
## Key Concepts
<domain terms, business logic Claude must know at this level>
## LLM Docs
Detailed docs in `.llmdocs/`:
- @.llmdocs/architecture.md — <1-line description>
- @.llmdocs/data-model.md — <1-line description>
CLAUDE.md Rules
- NO verbose explanations — Claude infers
- NO duplicating .llmdocs/ content — just reference with short description
- The
## LLM Docssection MUST list all .llmdocs/ files with a 1-line description each - A CLAUDE.md that lists its .llmdocs/ files under
## Docspredates the current heading. Rename that heading to## LLM Docswhenever you update the file - Preserve existing custom instructions (git workflow, env vars, etc.)
- Remove content only when the code contradicts it, and name each removal in the summary
- When the code drops a function, flag, or module, grep every document of this level for its name, then reread each hit and each document's purpose line for a plain-language description of the same thing. Removing the name from one document is not enough
grep -rn '<dropped name>' <dir>/CLAUDE.md <dir>/.llmdocs
- Never include the marker line in text you write or edit. finish adds it after writing. When editing a document that already ends with one, leave that line alone
- Use
@.llmdocs/filename.mdimport if a doc should always be loaded
2. .llmdocs/ — The Territory
Process
A concept file beyond the required seven is yours to add, and the plan never names it. finish stamps it anyway, along with every other document of this level created during the run.
- Assess: use the plan's update blocks to identify which docs are affected
- Identify: determine which existing docs are affected, or if a new doc is needed
- Update CLAUDE.md: ensure the
## LLM Docssection lists any new doc files
If nothing changed that warrants doc updates, say so and move on.
Location
Use the path the first import under CLAUDE.md's ## LLM Docs heading names, or under ## Docs in a CLAUDE.md that predates it. Otherwise default to .llmdocs/ at the target directory level. CLAUDE.md and .llmdocs/ can exist at any directory level in the project.
Structure
Flat, 1 file per concept. The first 7 files are required and must always exist. testing.md is created when the project has a test suite and omitted when it has none. Additional concept files are created as needed.
.llmdocs/
architecture.md # Components, interactions, data flow (required)
api.md # Endpoints, request/response, authentication, authorization (required)
data-model.md # Schema, models, relationships (required)
deployment.md # Deploy process, environments (required)
ops.md # Runbooks, maintenance, troubleshooting (required)
observability.md # Logs, metrics, traces, health checks, dashboards, alerts (required)
security.md # Trust boundaries, secrets handling, authn/authz, threat model (required)
testing.md # Test layout, runner, fixtures, how to run the suite (when the project has tests)
<concept>.md # Domain-specific as needed
Doc File Format
# <Concept>
<1-line purpose>
## <Section>
<content: headers, tables, code blocks — no prose paragraphs>
.llmdocs/ Rules
- Max 500 lines per file — split if larger
- Include file paths with line refs where useful (
src/auth/login.ts:42) - Update existing docs incrementally, don't rewrite from scratch
- If a doc is accurate and unaffected by recent changes, leave its content alone. finish still updates its marker.
- Accuracy over coverage: only document what's verifiable from code
observability.mdholds the signals the system emits, andops.mdholds the actions an operator takes. A health endpoint, a log format, or an alert belongs inobservability.md. A project with no metrics or traces still documents its stdout, stderr, and exit codes there- Never include the marker line in text you write or edit. finish adds it after writing. A concept file you create is the trap here, because every sibling you just read ends with one. Copying that line writes a stale sha claiming the document was checked against a commit it never saw. End a new file at its last content line and let finish add the marker
3. Finish
Run finish, every time, including a run that wrote nothing. plan left a plan file behind and only finish removes it, so a run that skips finish leaves state for the next one to trip over.
bash "${CLAUDE_SKILL_DIR}/../../scripts/doc-baseline.sh" finish llmdocs
It stamps every document the plan marked new or update, and every document created since the plan, such as testing.md, with the HEAD the plan checked. The stamp is a marker line at the end of the document, an HTML comment naming that commit. finish leaves unchanged documents and documents outside the focus alone, and stamps nothing when the repository has no commits. Exit 4 means a planned document is missing. Write it and run finish again.
- Never call
stampdirectly and never write or edit the marker line by hand. finish writes it. - The marker is metadata. The rule against recording history does not apply to it.
4. Summary Output
After running, output this summary. Fill every line from the run and write "none" where a list is empty. Under Stamped, copy finish's own lines verbatim, one per document. Never write a sha there, and never add a word finish did not print.
A sentence reworded to drop a capability is a removal. Name it under Removed with the wording that went away, even when the same line still exists.
Filled example, from a run where the code dropped character counting.
Files created: none
Files modified: CLAUDE.md, .llmdocs/api.md
CLAUDE.md sections added, updated, or removed: Key Concepts updated
Removed because the code contradicts it:
- CLAUDE.md: "or characters" from the purpose line, and the --chars key concept
- .llmdocs/api.md: the count_chars row
Stamped:
- stamped CLAUDE.md (marker)
- stamped .llmdocs/api.md (marker)
When the changes warrant no doc update, write "no doc changes needed" above the summary.