Sync CLAUDE.md Hierarchy
Detect drift between documented context and actual codebase state across ALL files: root, module-level, and .claude/rules/. Apply surgical updates.
Workflow
1. Discover All Context Files
find . -name 'CLAUDE.md' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/target/*' -not -path '*/dist/*' 2>/dev/null
find .claude/rules -name '*.md' -type f 2>/dev/null
Classify each as Root, Module, or Rule (same as audit).
If no files found: "No context files to sync. Run /claudemd:init first."
2. Read Current State
Read all discovered files. For each file, note:
- Level (root/module/rule)
- Sections and their content
- References to specific versions, paths, commands, files
3. Analyze Codebase (Current Truth)
Run these in parallel:
a) Tech stack:
cat package.json 2>/dev/null | jq '{name, dependencies, devDependencies}' 2>/dev/null
cat pyproject.toml 2>/dev/null
cat go.mod 2>/dev/null | head -20
cat Cargo.toml 2>/dev/null | head -30
b) Directory structure:
git ls-files | xargs -n1 dirname | sort -u
c) Available commands:
jq -r '.scripts | to_entries[] | "\(.key): \(.value)"' package.json 2>/dev/null
cat Makefile 2>/dev/null | grep -E '^[a-zA-Z_-]+:' 2>/dev/null
d) Linter/formatter config:
ls .editorconfig .eslintrc* .prettierrc* ruff.toml biome.json .flake8 .rubocop.yml 2>/dev/null
e) Module-level changes:
For each module CLAUDE.md, check its directory:
# Files in module directory vs what module documents
find {module_path} -maxdepth 1 -type f | head -30
f) Staleness signals:
# For each context file, compare its last commit to codebase changes
find . -name 'CLAUDE.md' -not -path '*/node_modules/*' -exec sh -c 'echo "$(git log --format=%ci -1 -- "$1" 2>/dev/null) $1"' _ {} \;
git log --format=%ci -1 -- package.json pyproject.toml Makefile 2>/dev/null
4. Compute Diff (Per File)
For EACH context file, compare documented state vs reality:
Root drift dimensions:
| Dimension | Source of Truth | Documented In |
|---|---|---|
| Dependencies | package.json / pyproject.toml | Tech Stack section |
| Directories | Filesystem + git ls-files | Structure section |
| Commands | package.json scripts / Makefile | Commands section |
Module drift dimensions:
| Dimension | Source of Truth | Documented In |
|---|---|---|
| Module files | Filesystem | Architecture / structure references |
| Entry points | Source code exports | Key interfaces section |
| Local commands | Package scripts / Makefile targets | Commands section |
Rule drift dimensions:
| Dimension | Source of Truth | Documented In |
|---|---|---|
| Path globs | Filesystem | YAML frontmatter paths: |
| Cross-cutting conventions | Codebase patterns | Rule content |
Change classification:
| Symbol | Meaning |
|---|---|
| + | New in codebase, not documented |
| - | Documented but no longer exists |
| ~ | Changed (version, path, name) |
5. Present Changes
## Sync Report
### Root CLAUDE.md
~ react: 18.2.0 → 19.1.0 (line 8)
+ vitest: 3.1.0 (new, not documented)
- jest: removed from deps (line 12)
~ test command: "jest" → "vitest run" (line 22)
### Module: src/billing/CLAUDE.md
- src/billing/legacy.py referenced but deleted
+ src/billing/v2/ new subdirectory, not documented
~ entry point changed: BillingService → BillingV2Service
### Module: src/auth/CLAUDE.md
= No drift detected
### Rule: .claude/rules/api.md
~ paths glob "src/api/**" matches 0 files (directory renamed to src/endpoints/)
### Hierarchy Changes
+ src/notifications/ qualifies as Domain Boundary, no CLAUDE.md
- src/legacy/CLAUDE.md orphaned (directory has 0 source files)
6. Ask User
AskUserQuestion:
question: "How should I apply these changes?"
header: "Apply"
options:
- label: "Apply all (Recommended)"
description: "Update all drifted files automatically"
- label: "Review each"
description: "Step through each file for approval"
- label: "Preview only"
description: "Show proposed edits without applying"
7. Apply Updates
For each approved change:
- Edit specific lines in the affected file
- Preserve surrounding context and formatting
- Keep within size budgets per level
- For orphaned module files: ask before deleting
- For new qualifying directories: suggest
/claudemd:init {path}
8. Post-Sync Report
## Sync Complete
### Updated Files
Path Changes Lines before → after
./CLAUDE.md 3 82 → 80
src/billing/CLAUDE.md 2 55 → 48
.claude/rules/api.md 1 25 → 25
### Unresolved
+ src/notifications/ needs CLAUDE.md → /claudemd:init src/notifications
- src/legacy/CLAUDE.md orphaned → delete manually or /claudemd:optimize
### Context Load (post-sync)
Working in... Total loaded
src/billing/ root (80) + billing (48) = 128/250
△ Review changes with `git diff` before committing.
What Sync Does
- Updates facts: versions, paths, commands, file references
- Flags orphaned module files
- Flags new directories that qualify for CLAUDE.md
- Updates stale path globs in rule frontmatter
What Sync Does NOT Do
- Does not restructure files (use
/claudemd:optimize) - Does not generate new module files (use
/claudemd:init {path}) - Does not rewrite prose or change writing style
- Does not touch CLAUDE.local.md (personal file)
- Does not delete files without explicit user approval
Sync is surgical: facts only, no restructuring.
