Skill: athola/nm-sanctum-doc-updates (version 1.0.2)

--- name: doc-updates description: | Update documentation after code changes with quality gates, slop detection, consolidation, and accuracy verification version: 1.9.5 triggers: - documentation - readme - adr - docstrings - writing - consolidation - debloat metadata: {"openclaw": {"homepage": "https://github.com/athola/claude-night-market/tree/master/plugins/sanctum", "emoji": "\ud83e\udd9e", "requires": {"config": ["night-market.sanctum:shared", "night-market.sanctum:git-workspace-review", "night-market.imbue:proof-of-work", "night-market.scribe:slop-detector", "night-market.scribe:doc-generator"]}}} source: claude-night-market source_plugin: sanctum --- > **Night Market Skill** — ported from [claude-night-market/sanctum](https://github.com/athola/claude-night-market/tree/master/plugins/sanctum). For the full experience with agents, hooks, and commands, install the Claude Code plugin. ## Table of Contents - [When to Use](#when-to-use) - [Required TodoWrite Items](#required-todowrite-items) - [Step 1: Collect Context](#step-1-collect-context-context-collected) - [Step 2: Identify Targets](#step-2-identify-targets-targets-identified) - [Step 2.5: Check for Consolidation](#step-25-check-for-consolidation-consolidation-checked) - [Step 3: Apply Edits](#step-3-apply-edits-edits-applied) - [Step 4: Enforce Guidelines](#step-4-enforce-guidelines-guidelines-verified) - [Step 4.25: AI Slop Detection](#step-425-ai-slop-detection-slop-scanned) - [Step 4.75: Sync Capabilities Documentation](#step-475-sync-capabilities-documentation-capabilities-synced) - [Step 5: Verify Accuracy](#step-5-verify-accuracy-accuracy-verified) - [Step 6: Preview Changes](#step-6-preview-changes-preview) - [Exit Criteria](#exit-criteria) - [Flags](#flags) # Documentation Update Workflow ## When To Use Use this skill when code changes require updates to the README, plans, wikis, or docstrings. Run `Skill(sanctum:git-workspace-review)` first to capture the change context. ### System Capabilities The documentation update workflow includes several specialized functions. It identifies redundancy through consolidation detection and enforces directory-specific style rules, with strict limits for `docs/` and more lenient ones for the `book/` directory. The system also verifies the accuracy of version numbers and component counts and integrates with the LSP for semantic documentation verification in supported versions of Claude Code. ## When NOT To Use - README-specific updates - use update-readme instead - Complex multi-file consolidation - use doc-consolidation ## Required TodoWrite Items 1. `doc-updates:context-collected` - Git context + CHANGELOG review 2. `doc-updates:targets-identified` 3. `doc-updates:consolidation-checked` (skippable) 4. `doc-updates:edits-applied` 5. `doc-updates:guidelines-verified` 6. `doc-updates:slop-scanned` - AI marker detection via scribe 7. `doc-updates:plugins-synced` - plugin.json ↔ disk audit 8. `doc-updates:capabilities-synced` - plugin.json ↔ documentation sync 9. `doc-updates:accuracy-verified` 10. `doc-updates:preview` ## Step 1: Collect Context (`context-collected`) - Validate `Skill(sanctum:git-workspace-review)` has been run. - Use its notes to understand the delta. - Identify the features or bug fixes that need documentation updates. **CHANGELOG Reference** (critical for version sync): ```bash # Check recent CHANGELOG entries for undocumented features head -100 CHANGELOG.md # Compare documented version vs plugin versions grep -E "^\[.*\]" CHANGELOG.md | head -3 for p in plugins/*/.claude-plugin/plugin.json; do jq -r '"\(.name): \(.version)"' "$p" done | head -5 ``` Cross-reference CHANGELOG entries against: - `book/src/reference/capabilities-reference.md` - All skills/commands/agents - Plugin documentation in `book/src/plugins/` - Per-plugin docs - Plugin READMEs - Quick reference docs ## Step 2: Identify Targets (`targets-identified`) - List the relevant files from the scope across all documentation locations: - `docs/` - Reference documentation (strict style) - `book/` - Technical book content (lenient style) - `README.md` files at project and plugin roots - `wiki/` entries if present - Docstrings in code files - Prioritize user-facing documentation first, then supporting plans and specifications. - When architectural work is planned, confirm whether an Architecture Decision Record (ADR) already exists in `wiki/architecture/` (or wherever ADRs are located). - Add missing ADRs to the target list before any implementation begins. ## Step 2.5: Check for Consolidation (`consolidation-checked`) Load: `@modules/consolidation-integration.md` **Purpose**: Detect redundancy and bloat before making edits. **Scan for:** - Untracked reports (ALL_CAPS *_REPORT.md, *_ANALYSIS.md files) - Bloated committed docs (files exceeding 500 lines in docs/, 1000 in book/) - Stale files (outdated content that should be deleted) **User approval required before:** - Merging content from one file to another - Deleting stale or redundant files - Splitting bloated files **Skip options:** - Use `--skip-consolidation` flag to bypass this phase - Select specific items instead of processing all **Exit criteria**: User has approved/skipped all consolidation opportunities. ## Step 3: Apply Edits (`edits-applied`) - Update each file with grounded language: explain what changed and why. - Reference specific commands, filenames, or configuration options where possible. - For docstrings, use the imperative mood and keep them concise. - For ADRs, see `modules/adr-patterns.md` for complete template structure, status flow, immutability rules, and best practices. ## Step 4: Enforce Guidelines (`guidelines-verified`) Load: `@modules/directory-style-rules.md` ### Style Enforcement Maintain consistent documentation by applying directory-specific rules. The system checks for and removes filler phrases such as "in order to" or "it should be noted" and ensures that no emojis are present in the body text of technical documents. Use grounded language with specific references rather than vague claims, and maintain an imperative mood for instructions. For lists of three or more items, prefer bullets over prose to improve scannability. The audit will issue warnings for paragraphs that exceed length limits or files that surpass the established line count thresholds. We also flag marketing language and abstract adjectives like "capable" or "smooth" to maintain a technical and direct tone across all project documentation. ## Step 4.25: AI Slop Detection (`slop-scanned`) Run `Skill(scribe:slop-detector)` on edited documentation to detect AI-generated content markers. ### Scribe Integration The scribe plugin provides comprehensive AI slop detection: ``` Skill(scribe:slop-detector) --target [edited-files] ``` This detects: - **Tier 1 words**: delve, tapestry, comprehensive, leveraging, etc. - **Phrase patterns**: "In today's fast-paced world", "cannot be overstated" - **Structural markers**: Excessive em dashes, bullet overuse, sentence uniformity - **Sycophantic phrases**: "I'd be happy to", "Great question!" ### Writing Style Guidelines For enhanced writing quality, check for `elements-of-style:writing-clearly-and-concisely`: ``` # If superpowers/elements-of-style is installed: Skill(elements-of-style:writing-clearly-and-concisely) # Fallback if not installed - use scribe:doc-generator principles: Skill(scribe:doc-generator) --remediate ``` The fallback provides equivalent guidance: 1. Ground every claim with specifics 2. Trim rhetorical crutches (no formulaic openers/closers) 3. Use numbers, commands, filenames over adjectives 4. Balance bullets with narrative prose 5. Show authorial perspective (trade-offs, reasoning) ### Remediation If slop score exceeds 2.5 (moderate), run: ``` Agent(scribe:doc-editor) --target [file] ``` This provides interactive section-by-section cleanup with user approval. ### Skip Options - Use `--skip-slop` flag to bypass slop detection - Slop warnings are non-blocking by default ## Step 4.5: Sync Plugin Registrations (`plugins-synced`) **Audit plugin.json files against disk** (prevents registration drift): ```bash # Quick discrepancy check for all plugins for plugin in plugins/*/; do name=$(basename "$plugin") pjson="$plugin/.claude-plugin/plugin.json" [ -f "$pjson" ] || continue # Count commands json_cmds=$(jq -r '.commands | length' "$pjson" 2>/dev/null || echo 0) disk_cmds=$(ls "$plugin/commands/"*.md 2>/dev/null | wc -l) # Count skills (directories only) json_skills=$(jq -r '.skills | length' "$pjson" 2>/dev/null || echo 0) disk_skills=$(ls -d "$plugin/skills"/*/ 2>/dev/null | wc -l) # Report mismatches if [ "$json_cmds" != "$disk_cmds" ] || [ "$json_skills" != "$disk_skills" ]; then echo "$name: commands=$json_cmds/$disk_cmds skills=$json_skills/$disk_skills" fi done ``` **If mismatches found**: Run `/update-plugins --fix` or manually update plugin.json files. **Why this matters**: Unregistered commands/skills won't appear in Claude Code's slash command menu or be discoverable. ## Step 4.75: Sync Capabilities Documentation (`capabilities-synced`) Load: `@modules/capabilities-sync.md` **Purpose**: Ensure plugin.json registrations are reflected in reference documentation. **Sync Targets**: | Source | Documentation Target | |--------|---------------------| | `plugin.json.skills[]` | `book/src/reference/capabilities-reference.md` | | `plugin.json.commands[]` | `book/src/reference/capabilities-reference.md` | | `plugin.json.agents[]` | `book/src/reference/capabilities-reference.md` | | `hooks/hooks.json` | `book/src/reference/capabilities-reference.md` | | Plugin existence | `book/src/plugins/{plugin}.md` | **Quick Check**: ```bash # Compare registered vs documented skills for pjson in plugins/*/.claude-plugin/plugin.json; do plugin=$(basename $(dirname $(dirname "$pjson"))) jq -r --arg p "$plugin" '.skills[]? | sub("^\\./skills/"; "") | "\($p):\(.)"' "$pjson" 2>/dev/null done | sort > /tmp/registered-skills.txt grep -E "^\| \`[a-z-]+\` \|" book/src/reference/capabilities-reference.md | \ head -120 | awk -F'|' '{print $2":"$3}' | sort > /tmp/documented-skills.txt # Show missing comm -23 /tmp/registered-skills.txt /tmp/documented-skills.txt ``` **If discrepancies found**: 1. **Missing from docs**: Add entries to capabilities-reference.md tables 2. **Missing plugin pages**: Create `book/src/plugins/{plugin}.md` 3. **Missing from SUMMARY**: Add plugin to `book/src/SUMMARY.md` **Auto-generate entry format**: ```markdown | `{skill-name}` | [{plugin}](../plugins/{plugin}.md) | {description} | ``` **Skip options**: Use `--skip-capabilities` to bypass this phase. ## Step 5: Verify Accuracy (`accuracy-verified`) Load: `@modules/accuracy-scanning.md` **Validate claims against codebase:** ```bash # Quick version check for p in plugins/*/.claude-plugin/plugin.json; do jq -r '"\(.name): \(.version)"' "$p" done # Quick counts echo "Plugins: $(ls -d plugins/*/.claude-plugin/plugin.json | wc -l)" echo "Skills: $(find plugins/*/skills -name 'SKILL.md' | wc -l)" ``` **Verification:** Run the command with `--help` flag to verify availability. **Flag mismatches:** - Version numbers that don't match plugin.json - Plugin/skill/command counts that don't match actual directories - File paths that don't exist **LSP-Enhanced Verification (2.0.74+)**: When `ENABLE_LSP_TOOL=1` is set, enhance accuracy verification with semantic analysis: 1. **API Documentation Coverage**: - Query LSP for all public functions/classes - Check which lack documentation - Verify all exported items are documented 2. **Signature Verification**: - Compare documented function signatures with actual code - Detect parameter mismatches - Flag return type discrepancies 3. **Reference Finding**: - Use LSP to find all usages of documented items - Include real usage examples in documentation - Verify cross-references are accurate 4. **Code Structure Validation**: - Check documented file paths exist (via LSP definitions) - Verify module organization matches documentation - Detect renamed/moved items **Efficiency**: LSP queries (50ms) vs. manual file tracing (minutes) - dramatically faster verification. **Default Strategy**: Documentation updates should **prefer LSP** for all verification tasks. Enable `ENABLE_LSP_TOOL=1` permanently for best results. **Non-blocking**: Warnings are informational; user decides whether to fix. ## Step 6: Preview Changes (`preview`) - Show diffs for each edited file (`git diff <file>` or `rg` snippets). - Include accuracy warnings if any were flagged. - Summarize: - Files created/modified/deleted - Consolidation actions taken - Style violations fixed - Remaining TODOs or follow-ups ## Exit Criteria - All `TodoWrite` items are completed and documentation is updated. - New ADRs, if any, are in `wiki/architecture/` (or the established ADR directory) with the correct status and links to related work. - Directory-specific style rules are satisfied. - Accuracy warnings addressed or acknowledged. - Content does not sound AI-generated. - Files are staged or ready for review. ## Flags | Flag | Effect | |------|--------| | `--skip-consolidation` | Skip Phase 2.5 consolidation check | | `--skip-slop` | Skip Phase 4.25 AI slop detection | | `--strict` | Treat all warnings as errors | | `--book-style` | Apply book/ rules to all files | ## Troubleshooting ### Common Issues **Documentation out of sync** Run `make docs-update` to regenerate from code **Build failures** Check that all required dependencies are installed **Links broken** Verify relative paths in documentation files

path: modules/accuracy-scanning.md
content: # Accuracy Scanning Module

Validate documentation claims against actual codebase state. Runs as Phase 5.5 before preview to catch stale version numbers, outdated counts, and broken references.

## Scan Types

### 1. Version Number Validation

Compares version references in documentation against `plugin.json` files.

**Patterns to detect:**
- `v1.2.3`, `version: 1.2.3`
- `Plugin Name (v1.2.3)`, `Plugin Name v1.2.3`
- Table cells with version numbers

**Validation:**
```bash
# Extract actual versions
for plugin in plugins/*/.claude-plugin/plugin.json; do
    jq -r '.name + " " + .version' "$plugin"
done

# Sample output:
# abstract 1.0.5
# sanctum 1.0.6
# scry 1.1.0
```

**Warning format:**
```markdown
| File | Claimed | Actual | Action |
|------|---------|--------|--------|
| docs/api-overview.md | abstract v2.1.0 | 1.0.5 | Update version |
| README.md | sanctum v3.0.0 | 1.0.6 | Update version |
```

### 2. Plugin Count Validation

Verifies claims like "13 plugins" against actual directory count.

**Patterns to detect:**
- "N plugins", "contains N plugins"
- Table rows claiming to list all plugins

**Validation:**
```bash
# Count plugin directories with valid plugin.json
ls -d plugins/*/.claude-plugin/plugin.json 2>/dev/null | wc -l
```

### 3. Skill/Command Count Validation

Verifies per-plugin statistics.

**Patterns to detect:**
- "X skills", "Y commands", "Z agents"
- API inventory tables

**Validation:**
```bash
# Count skills for a plugin
ls -d plugins/sanctum/skills/*/SKILL.md 2>/dev/null | wc -l

# Count commands
ls plugins/sanctum/commands/*.md 2>/dev/null | wc -l

# Count agents
ls plugins/sanctum/agents/*.md 2>/dev/null | wc -l
```

### 4. File/Path Reference Validation

Verifies that referenced paths exist.

**Patterns to detect:**
- Backtick paths: `` `plugins/sanctum/skills/doc-updates/SKILL.md` ``
- Relative paths in links: `[link](./modules/foo.md)`
- Configuration examples with paths

**Validation:**
```bash
# Check if path exists
test -e "$path" && echo "EXISTS" || echo "MISSING"
```

## Scan Algorithm

```python
def scan_for_accuracy(file_path: str, content: str) -> list[AccuracyWarning]:
    warnings = []

    # Load current plugin versions
    actual_versions = load_plugin_versions()

    # Find version references
    version_pattern = r'(\w+)[\s\(]v?(\d+\.\d+\.\d+)'
    for match in re.finditer(version_pattern, content):
        plugin_name = match.group(1).lower()
        claimed_version = match.group(2)

        if plugin_name in actual_versions:
            actual = actual_versions[plugin_name]
            if claimed_version != actual:
                warnings.append({
                    'type': 'version_mismatch',
                    'plugin': plugin_name,
                    'claimed': claimed_version,
                    'actual': actual,
                    'line': get_line_number(content, match.start())
                })

    # Find count claims
    count_pattern = r'(\d+)\s+(plugins?|skills?|commands?|agents?)'
    for match in re.finditer(count_pattern, content, re.IGNORECASE):
        claimed_count = int(match.group(1))
        item_type = match.group(2).lower().rstrip('s')
        actual_count = count_items(item_type)

        if abs(claimed_count - actual_count) > 0:
            warnings.append({
                'type': 'count_mismatch',
                'item_type': item_type,
                'claimed': claimed_count,
                'actual': actual_count,
                'line': get_line_number(content, match.start())
            })

    return warnings
```

## Quick Validation Commands

For manual verification during doc updates:

```bash
# All plugin versions
for p in plugins/*/.claude-plugin/plugin.json; do
    jq -r '"\(.name): \(.version)"' "$p"
done | sort

# Total counts
echo "Plugins: $(ls -d plugins/*/.claude-plugin/plugin.json | wc -l)"
echo "Skills: $(find plugins/*/skills -name 'SKILL.md' | wc -l)"
echo "Commands: $(find plugins/*/commands -name '*.md' | wc -l)"
echo "Agents: $(find plugins/*/agents -name '*.md' | wc -l)"
```

## Output Format

### Phase 5.5: Verify Accuracy

```markdown
## Accuracy Scan Results

Scanned: docs/api-overview.md, README.md (2 files)
Time: 0.3 seconds

### Warnings Found

| Type | File | Line | Issue | Fix |
|------|------|------|-------|-----|
| version | docs/api-overview.md | 15 | abstract v2.1.0 → 1.0.5 | Update |
| version | docs/api-overview.md | 18 | sanctum v3.0.0 → 1.0.6 | Update |
| count | README.md | 42 | "11 plugins" → 13 | Update |

### No Issues
- All file paths valid
- Command references exist

**Action**: Review warnings before proceeding to preview.
```

## Integration Notes

- Non-blocking: Warnings don't prevent workflow completion
- Selective: Only scans files being edited (from Phase 2 targets)
- Fast: Bash commands complete in <1 second per file
- Progressive: Loads only when Phase 5 edits are complete

## Cross-Reference: /update-version

When version bumps are performed via `/update-version`, the automated script updates config files but NOT documentation. The `/update-version` command includes Phase 2 to update documentation files. If you're running `/update-docs` after a version bump, pay special attention to `docs/api-overview.md` which contains the plugin version inventory.

## Edge Cases

### Approximate counts
Some docs use "~10 skills" or "about 50 commands". These should be validated but with wider tolerance (±20%).

### Unreleased versions
If a plugin shows "0.0.0" or "dev", skip version validation for that plugin.

### External references
Paths outside the repository (URLs, system paths) are not validated.


path: modules/adr-patterns.md
content: # Architecture Decision Record (ADR) Patterns

## ADR Template Structure

Every ADR must follow a consistent Markdown template with these required sections:

### Required Sections

1. **Title**
   - Format: `ADR-{number}: {Brief Decision Description}`
   - Example: `ADR-001: Use PostgreSQL for primary data store`

2. **Status**
   - One of: Proposed, Accepted, Deprecated, Superseded
   - Include date when status changed

3. **Context**
   - Forces driving the decision
   - Constraints that must be satisfied
   - Prior art or existing patterns
   - Why this decision is needed now

4. **Decision**
   - The chosen option with clear justification
   - Specific implementation approach
   - Rationale for why this solves the context

5. **Alternatives Considered**
   - Other options evaluated
   - Why each alternative was rejected
   - Trade-offs between options

6. **Consequences**
   - Positive outcomes expected
   - Negative outcomes or limitations
   - Impact on other components or teams
   - Future implications

7. **Metadata**
   - Author(s)
   - Date created
   - Approvers (if required)
   - Links to related documents

## Status Flow

ADRs follow this lifecycle:

```
Proposed → Accepted → [Deprecated | Superseded]
```

- **Proposed**: Draft ADR under review
- **Accepted**: Decision approved and implemented
- **Deprecated**: No longer recommended but not replaced
- **Superseded**: Replaced by a newer ADR (reference the new ADR number)

## Immutability Rules

ADRs are treated like code:

1. **Draft during planning**: Create ADR before implementation begins
2. **Review via pull request**: ADRs go through same review process as code
3. **Immutable once accepted**: Never edit an accepted ADR's decision
4. **Supersede, don't modify**: Create new ADR to change direction

## Superseding an ADR

When replacing an existing decision:

1. Create new ADR with next sequential number
2. Reference the superseded ADR number in context
3. Explain what changed and why the shift occurred
4. Update old ADR status to "Superseded by ADR-{new-number}"
5. Add link in old ADR to new record

## Location Conventions

ADRs typically live in one of these locations:
- `wiki/architecture/`
- `docs/adr/`
- `architecture/decisions/`

Check project structure to determine the established location before creating ADRs.

## Best Practices

### Keep Focused
- One architectural decision per ADR
- Maximum 1-2 pages in length
- Don't combine multiple decisions

### Maintain Traceability
- Link to requirements documents
- Reference design documents
- Connect to related ADRs
- Include issue/ticket numbers

### Write Grounded Content
- Reference specific technologies, tools, or approaches
- Include concrete examples where helpful
- Avoid abstract language or filler
- Use imperative mood for clarity

### Review Checklist
- [ ] Single focused decision
- [ ] All required sections present
- [ ] Alternatives documented with rationale
- [ ] Consequences (both positive and negative) identified
- [ ] Links to related work included
- [ ] Status clearly marked
- [ ] Location follows project convention


path: modules/capabilities-sync.md
content: # Capabilities Sync Module

Synchronizes plugin.json registrations with capabilities reference documentation.

## Purpose

Detects drift between:
- **Source of truth**: `plugins/*/.claude-plugin/plugin.json` files
- **Documentation**: `book/src/reference/capabilities-reference.md` and related files

## When Loaded

This module is loaded during Step 4.75 (after plugins-synced, before accuracy-verified).

## Sync Targets

| Source | Documentation Target |
|--------|---------------------|
| `plugin.json.skills[]` | `book/src/reference/capabilities-reference.md` (Skills table) |
| `plugin.json.commands[]` | `book/src/reference/capabilities-reference.md` (Commands table) |
| `plugin.json.agents[]` | `book/src/reference/capabilities-reference.md` (Agents table) |
| `hooks/hooks.json` | `book/src/reference/capabilities-reference.md` (Hooks table) |
| Plugin existence | `book/src/plugins/{plugin}.md` |
| Plugin in layer | `book/src/plugins/{layer}-layer.md` |
| Plugin in SUMMARY | `book/src/SUMMARY.md` |

## Detection Script

```bash
#!/bin/bash
# capabilities-sync-check.sh
# Run from repo root

echo "=== Capabilities Sync Report ==="
echo ""

# Temporary files for comparison
REGISTERED_SKILLS=$(mktemp)
DOCUMENTED_SKILLS=$(mktemp)
REGISTERED_COMMANDS=$(mktemp)
DOCUMENTED_COMMANDS=$(mktemp)
REGISTERED_AGENTS=$(mktemp)
DOCUMENTED_AGENTS=$(mktemp)

# Extract registered skills from plugin.json files
for pjson in plugins/*/.claude-plugin/plugin.json; do
  plugin=$(basename $(dirname $(dirname "$pjson")))
  jq -r --arg p "$plugin" '.skills[]? | sub("^\\./skills/"; "") | "\($p):\(.)"' "$pjson" 2>/dev/null
done | sort -u > "$REGISTERED_SKILLS"

# Extract documented skills from capabilities-reference.md
grep -E "^\| \`[a-z-]+\` \|" book/src/reference/capabilities-reference.md 2>/dev/null | \
  sed -n '/All Skills/,/All Commands/p' | \
  grep -E "^\| \`" | \
  awk -F'|' '{gsub(/[`\[\] ]/, "", $2); gsub(/.*\(\.\.\/plugins\//, "", $3); gsub(/\.md\).*/, "", $3); print $3":"$2}' | \
  sort -u > "$DOCUMENTED_SKILLS"

# Extract registered commands
for pjson in plugins/*/.claude-plugin/plugin.json; do
  plugin=$(basename $(dirname $(dirname "$pjson")))
  jq -r --arg p "$plugin" '.commands[]? | sub("^\\./commands/"; "") | sub("\\.md$"; "") | "/\($p):\(.)"' "$pjson" 2>/dev/null
done | sort -u > "$REGISTERED_COMMANDS"

# Extract documented commands
grep -E "^\| \`/" book/src/reference/capabilities-reference.md 2>/dev/null | \
  sed -n '/All Commands/,/All Agents/p' | \
  grep -E "^\| \`/" | \
  awk -F'|' '{gsub(/[`\[\] ]/, "", $2); gsub(/ /, "", $3); print $2}' | \
  sort -u > "$DOCUMENTED_COMMANDS"

# Extract registered agents
for pjson in plugins/*/.claude-plugin/plugin.json; do
  plugin=$(basename $(dirname $(dirname "$pjson")))
  jq -r --arg p "$plugin" '.agents[]? | sub("^\\./agents/"; "") | sub("\\.md$"; "") | "\($p):\(.)"' "$pjson" 2>/dev/null
done | sort -u > "$REGISTERED_AGENTS"

# Extract documented agents
grep -E "^\| \`[a-z-]+\` \|" book/src/reference/capabilities-reference.md 2>/dev/null | \
  sed -n '/All Agents/,/All Hooks/p' | \
  grep -E "^\| \`" | \
  awk -F'|' '{gsub(/[`\[\] ]/, "", $2); gsub(/ /, "", $3); print $3":"$2}' | \
  sort -u > "$DOCUMENTED_AGENTS"

# Report differences
echo "### Skills"
echo "Missing from docs (registered but not documented):"
comm -23 "$REGISTERED_SKILLS" "$DOCUMENTED_SKILLS" | sed 's/^/  - /'
echo ""
echo "Extra in docs (documented but not registered):"
comm -13 "$REGISTERED_SKILLS" "$DOCUMENTED_SKILLS" | sed 's/^/  - /'

echo ""
echo "### Commands"
echo "Missing from docs:"
comm -23 "$REGISTERED_COMMANDS" "$DOCUMENTED_COMMANDS" | sed 's/^/  - /'
echo ""
echo "Extra in docs:"
comm -13 "$REGISTERED_COMMANDS" "$DOCUMENTED_COMMANDS" | sed 's/^/  - /'

echo ""
echo "### Agents"
echo "Missing from docs:"
comm -23 "$REGISTERED_AGENTS" "$DOCUMENTED_AGENTS" | sed 's/^/  - /'
echo ""
echo "Extra in docs:"
comm -13 "$REGISTERED_AGENTS" "$DOCUMENTED_AGENTS" | sed 's/^/  - /'

# Check for missing plugin pages in book
echo ""
echo "### Plugin Pages"
for plugin in plugins/*/; do
  name=$(basename "$plugin")
  if [ ! -f "book/src/plugins/${name}.md" ]; then
    echo "  - Missing: book/src/plugins/${name}.md"
  fi
done

# Check SUMMARY.md includes all plugins
echo ""
echo "### SUMMARY.md"
for plugin in plugins/*/; do
  name=$(basename "$plugin")
  if ! grep -q "plugins/${name}.md" book/src/SUMMARY.md 2>/dev/null; then
    echo "  - Missing from SUMMARY: ${name}"
  fi
done

# Cleanup
rm -f "$REGISTERED_SKILLS" "$DOCUMENTED_SKILLS" "$REGISTERED_COMMANDS" "$DOCUMENTED_COMMANDS" "$REGISTERED_AGENTS" "$DOCUMENTED_AGENTS"
```

## Workflow Integration

### Step 4.75: Sync Capabilities Documentation (`capabilities-synced`)

After `plugins-synced` (Step 4.5), run capabilities sync:

```bash
# Quick check for capabilities drift
bash plugins/sanctum/skills/doc-updates/modules/capabilities-sync-check.sh
```

**If discrepancies found:**

1. **Missing skills/commands/agents**: Generate table entries
2. **Extra in docs**: Verify if removed or renamed
3. **Missing plugin pages**: Create from template
4. **Missing from SUMMARY**: Add to appropriate layer

### Auto-Generation Templates

#### Skill Entry
```markdown
| `{skill-name}` | [{plugin}](../plugins/{plugin}.md) | {description from SKILL.md frontmatter} |
```

#### Command Entry
```markdown
| `/{plugin}:{command}` | {plugin} | {description from command.md frontmatter} |
```

#### Agent Entry
```markdown
| `{agent-name}` | {plugin} | {description from agent.md frontmatter} |
```

#### Hook Entry
```markdown
| `{hook-file}` | {plugin} | {type} | {description} |
```

## doc-sync Configuration

Config file: `.claude/doc-sync.yaml`

Keeps generated reference documentation in sync with plugin source-of-truth
files (`plugin.json`). The parser reads mappings, resolves source globs,
extracts registered items, compares them against target markdown sections,
and reports (or fixes) discrepancies.

### Schema

```yaml
version: 1

mappings:
  - name: <string>            # unique mapping identifier
    source: <glob>            # glob pattern relative to repo root
    extract:
      - path: <string>        # JSON key to extract from each source
        strip_prefix: <str>   # prefix to remove from each value (optional)
        strip_suffix: <str>   # suffix to remove from each value (optional)
    targets:
      - path: <string>        # markdown file relative to repo root
        section: <string>     # heading text to locate the table in
        format: <string>      # row template with {name}, {plugin}, {type}

defaults:
  on_missing: warn | error | ignore   # item in source but not in target
  on_extra: warn | error | ignore     # item in target but not in source
  auto_fix: true | false              # whether --fix is allowed
```

### Field Reference

#### Top-level

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | int | yes | Schema version, currently `1` |
| `mappings` | list | yes | One or more sync mappings |
| `defaults` | object | no | Fallback behavior settings |

#### mappings[]

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | yes | Human-readable mapping ID |
| `source` | string | yes | Glob for source files (e.g. `plugins/*/.claude-plugin/plugin.json`) |
| `extract` | list | yes | Fields to pull from each matched source |
| `targets` | list | yes | Markdown files to validate against |

#### extract[]

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | string | yes | JSON key name in source file (e.g. `skills`, `commands`, `agents`) |
| `strip_prefix` | string | no | Prefix stripped from each value before comparison |
| `strip_suffix` | string | no | Suffix stripped from each value before comparison |

#### targets[]

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | string | yes | Path to the markdown target file |
| `section` | string | yes | Heading that contains the table. Use `{type}` as placeholder for the extract path name |
| `format` | string | yes | Table row template. Placeholders: `{name}`, `{plugin}`, `{type}`, `{description}` |

#### defaults

| Field | Default | Description |
|-------|---------|-------------|
| `on_missing` | `warn` | Action when source item is absent from target |
| `on_extra` | `warn` | Action when target item is absent from source |
| `auto_fix` | `false` | Allow `--fix` flag to write missing entries |

### Example

```yaml
version: 1

mappings:
  - name: plugin-capabilities
    source: "plugins/*/.claude-plugin/plugin.json"
    extract:
      - path: "skills"
        strip_prefix: "./skills/"
      - path: "commands"
        strip_prefix: "./commands/"
        strip_suffix: ".md"
      - path: "agents"
        strip_prefix: "./agents/"
        strip_suffix: ".md"
    targets:
      - path: "book/src/reference/capabilities-reference.md"
        section: "### All {type}s"
        format: "| `{name}` | [{plugin}](../plugins/{plugin}.md) | {description} |"

defaults:
  on_missing: warn
  on_extra: warn
  auto_fix: false
```

### CLI Usage

```bash
# Check for discrepancies (default config path)
python scripts/parse-doc-sync.py

# Custom config path
python scripts/parse-doc-sync.py --config path/to/doc-sync.yaml

# Auto-fix missing entries
python scripts/parse-doc-sync.py --fix

# Strict mode (exit 1 on any discrepancy)
python scripts/parse-doc-sync.py --strict
```

### Exit Codes

| Code | Meaning |
|------|---------|
| 0 | All targets in sync |
| 1 | Discrepancies found (or errors in strict mode) |
| 2 | Config parse error or missing source files |

## Exit Criteria

- All registered capabilities appear in documentation
- No orphaned documentation entries (items removed from plugin.json)
- All plugins have book pages
- SUMMARY.md is complete


path: modules/consolidation-integration.md
content: # Consolidation Integration Module

Bridges doc-updates with doc-consolidation capabilities. Detects redundancy and bloat in existing documentation, presenting consolidation opportunities before edits begin.

## Purpose

During Phase 2.5, scan for:
1. **Redundant files**: Multiple docs covering the same topic
2. **Bloated files**: Docs exceeding recommended length thresholds
3. **Stale files**: Documentation that should be deleted or archived
4. **Untracked reports**: LLM-generated files that need consolidation

## Detection Approach

### Reuse from doc-consolidation

Import candidate detection logic from `sanctum:doc-consolidation`:
- Git-untracked file detection
- ALL_CAPS naming pattern matching
- Content marker scanning (Executive Summary, Findings, etc.)

### Additional Signals for Committed Files

Extend detection to analyze committed documentation:

**Bloat signals:**
- `docs/`: File exceeds 500 lines, section exceeds 150 lines
- `book/`: File exceeds 1000 lines, section exceeds 300 lines
- Multiple "wall of text" paragraphs (>4 sentences in docs/, >8 in book/)

**Redundancy signals:**
- Similar file names: `api-overview.md` vs `api-reference.md`
- Similar headings across files
- Overlapping content sections (manual inspection)
- Design docs whose content exists in command/skill documentation
- Planning artifacts for completed work (already implemented)

**Redundancy check command:**
```bash
# For a candidate file, check if content exists elsewhere
grep -r "key phrase from candidate" docs/ book/ plugins/*/commands/*.md plugins/*/README.md
```

**Staleness signals:**
- References to deprecated features
- Version numbers more than 2 minor versions behind
- "TODO: update" comments older than 30 days

## Workflow

### Step 1: Scan for Candidates

```bash
# Find untracked .md files (doc-consolidation pattern)
git status --porcelain | grep '^??' | grep '\.md$' | grep -v 'docs/\|book/\|skills/\|commands/\|agents/'

# Find bloated docs/ files (500 line limit)
find docs/ -name '*.md' -exec wc -l {} \; 2>/dev/null | awk '$1 > 500 {print}'

# Find bloated book/ files (1000 line limit)
find book/ -name '*.md' -exec wc -l {} \; 2>/dev/null | awk '$1 > 1000 {print}'

# Find recently unchanged files (potential staleness) - docs: 90 days, book: 180 days
find docs/ -name '*.md' -mtime +90 -type f 2>/dev/null
find book/ -name '*.md' -mtime +180 -type f 2>/dev/null
```

### Step 2: Present Opportunities

Show consolidation candidates with recommended actions:

```markdown
## Phase 2.5: Consolidation Opportunities

### Redundant Files (delete - content exists elsewhere)

| File | Action | Reason |
|------|--------|--------|
| plugins/memory-palace/docs/PALACE_UNIFICATION.md | Delete | Content already in commands/palace.md |
| docs/old-api-design.md | Delete | Superseded by docs/api-overview.md |

### Untracked Reports (merge or delete)

| File | Score | Markers | Recommendation |
|------|-------|---------|----------------|
| API_REVIEW_REPORT.md | 6 | Executive Summary, Findings | Merge to docs/api-overview.md |
| MIGRATION_NOTES.md | 4 | Action Items, Tables | Merge to docs/migration-guide.md |

### Bloated Files (split or trim)

| File | Lines | Threshold | Recommendation |
|------|-------|-----------|----------------|
| book/src/tutorials/error-handling-tutorial.md | 1031 | 1000 | Trim verbose sections |
| docs/function-extraction-guidelines.md | 571 | 500 | Consider splitting principles/patterns |

### Staleness Candidates (review or delete)

| File | Last Modified | Issue | Recommendation |
|------|---------------|-------|----------------|
| docs/enhanced-pre-commit-hooks.md | 45 days | Content moved to imbue | Delete |
| docs/technical-debt-framework.md | 60 days | Replaced by backlog | Delete |

---

**Options:**
- `Y` - Proceed with all recommended actions
- `n` - Skip consolidation, continue to edits
- `select` - Choose specific items to address
- `--skip-consolidation` flag bypasses this phase
```

### Step 3: Execute Approved Actions

For each approved action:

**Delete (redundant) actions:**
1. Verify content exists in target document(s) by searching for key phrases
2. Confirm no unique valuable content would be lost
3. Remove file: `rm <file>`
4. Add deletion to git staging: `git add -u`

**Merge actions:**
1. Extract valuable content from source
2. Integrate into destination (using doc-consolidation merge strategies)
3. Delete source file
4. Add to git staging

**Delete (stale) actions:**
1. Confirm file has no unique valuable content
2. Remove file
3. Add deletion to git staging

**Split actions:**
1. Create new files for logical sections
2. Move content to new locations
3. Update cross-references
4. Preserve original as index if needed

**Action priority:**
1. Delete redundant first (unbloats without adding content)
2. Delete stale second (removes outdated info)
3. Merge third (consolidates remaining value)
4. Split last (increases file count, use sparingly)

## User Controls

### Skip Flag
```bash
/update-docs --skip-consolidation
```
Bypasses Phase 2.5 entirely for quick updates.

### Selective Processing
When user chooses "select":
```
Enter file numbers to process (comma-separated), or 'all'/'none':
> 1,3
Processing: API_REVIEW_REPORT.md, docs/enhanced-pre-commit-hooks.md
```

### Dry Run
```bash
/update-docs --consolidation-dry-run
```
Shows what would be consolidated without executing.

## Thresholds

| Metric | docs/ Limit | book/ Limit | Action |
|--------|-------------|-------------|--------|
| File length | 500 lines | 1000 lines | Flag for review |
| Section length | 150 lines | 300 lines | Suggest split |
| Paragraph sentences | 4 | 8 | Warn, don't block |
| Stale threshold | 90 days | 180 days | Review suggestion |

## Integration with doc-consolidation

This module **imports** patterns from doc-consolidation but **does not** duplicate its full workflow:

- **Imports**: Candidate detection signals, content markers, scoring
- **Extends**: Adds bloat and staleness detection for committed files
- **Defers to**: Full doc-consolidation skill for complex multi-file merges

For straightforward cases (single untracked report, obvious deletion), handle inline. For complex consolidations, recommend: "Run `/merge-docs` for detailed consolidation workflow."

## Exit Criteria

Phase 2.5 completes when:
- All candidates reviewed (approved or skipped)
- Approved merges/deletions executed
- Git staging updated with changes
- Summary logged for Phase 5 preview

Proceed to Phase 3 (Edits Applied) regardless of consolidation outcome.


path: modules/directory-style-rules.md
content: # Directory-Specific Style Rules

Apply different documentation standards based on file location. The `docs/` directory requires strict conciseness while `book/` allows technical book format with longer explanations.

## Rule Sets

### docs/ - Strict Reference Style

Target audience: Developers seeking quick answers.

| Rule | Limit | Rationale |
|------|-------|-----------|
| Max file length | 500 lines | Keeps files navigable |
| Max section length | 100 lines | Forces topic focus |
| Max paragraph sentences | 4 | Prevents wall-of-text |
| Max list items | 10 | Subgroup beyond this |
| Max table rows | 15 | Paginate or summarize |

**Required patterns:**
- Start directly (no "This document describes...")
- Imperative mood for instructions
- Bullets over prose for lists of 3+ items
- Code examples over abstract descriptions

**Anti-patterns to flag:**
- Executive summaries (remove or move to introduction)
- Filler phrases: "in order to", "it should be noted", "as mentioned"
- Qualification hedging: "generally", "typically", "usually"
- Empty transitions: "Moving on", "Now let's look at"

### book/ - Technical Book Style

Target audience: Learners working through chapters.

| Rule | Limit | Rationale |
|------|-------|-----------|
| Max file length | 1000 lines | Chapter-length content |
| Max section length | 300 lines | Tutorial depth allowed |
| Max paragraph sentences | 8 | Explanatory narratives |
| Max list items | 15 | Subgroup for clarity |
| Max table rows | 25 | Comparison tables |

**Allowed patterns:**
- Narrative explanations
- Before/after comparisons
- Step-by-step walkthroughs
- Conceptual introductions
- Callout emojis (sparingly)

**Still flagged:**
- Filler phrases
- Redundant explanations
- Overly long code blocks without commentary

### wiki/ - Wiki Reference Style

Target audience: Internal team and contributors seeking context.

| Rule | Limit | Rationale |
|------|-------|-----------|
| Max file length | 500 lines | Quick reference |
| Max section length | 100 lines | Topic focus |
| Max paragraph sentences | 4 | Scannable |
| Max list items | 10 | Subgroup beyond this |
| Max table rows | 15 | Paginate or summarize |

**Required patterns:**
- Same as docs/ strict style
- Cross-links to related wiki pages
- Architecture Decision Records (ADRs) in wiki/architecture/

### plugins/*/README.md - Plugin Summary Style

Target audience: Users evaluating or installing plugins.

| Rule | Limit | Rationale |
|------|-------|-----------|
| Max file length | 300 lines | Concise overview |
| Max section length | 50 lines | Quick scan |
| Max paragraph sentences | 4 | Brief descriptions |
| Max list items | 10 | Key features only |
| Max table rows | 15 | Command/skill listing |

**Required patterns:**
- Installation instructions
- Quick start example
- Link to detailed docs in book/

### Shared Rules (All Locations)

Apply everywhere regardless of directory:

- No emojis in headings or body (callouts excepted in book/)
- Grounded language (specific references, not vague claims)
- Imperative mood for docstrings
- No marketing language ("capable", "smooth", "elegant")
- No first-person plural ("we can see", "let's explore")
- Prose text wraps at 80 chars per line (hybrid wrapping:
  prefer sentence/clause boundaries over arbitrary breaks)
- Blank line before and after every heading
- ATX headings only (`#` prefix, never setext underlines)
- Blank line before every list (ordered or unordered)
- Reference-style links when inline links push past 80 chars
- Full formatting spec: `Skill(leyline:markdown-formatting)`

## Detection Patterns

### Wall-of-Text Detection

```python
def detect_wall_of_text(content: str, max_sentences: int) -> list[Violation]:
    violations = []
    paragraphs = extract_paragraphs(content)

    for i, para in enumerate(paragraphs):
        sentence_count = len(re.split(r'[.!?]+', para.strip()))
        if sentence_count > max_sentences:
            violations.append({
                'type': 'wall_of_text',
                'location': f'paragraph {i+1}',
                'actual': sentence_count,
                'limit': max_sentences,
                'suggestion': 'Break into smaller paragraphs or convert to bullet list'
            })

    return violations
```

### Filler Phrase Detection

```python
FILLER_PHRASES = [
    r'\bin order to\b',
    r'\bit should be noted\b',
    r'\bas mentioned (above|below|earlier|previously)\b',
    r'\bmoving on\b',
    r'\bnow let\'?s (look at|explore|consider)\b',
    r'\bthis (document|section|chapter) (describes|explains|covers)\b',
]

def detect_filler(content: str) -> list[Violation]:
    violations = []
    for pattern in FILLER_PHRASES:
        matches = re.findall(pattern, content, re.IGNORECASE)
        for match in matches:
            violations.append({
                'type': 'filler_phrase',
                'phrase': match,
                'suggestion': 'Remove or rewrite directly'
            })
    return violations
```

## Validation Workflow

### Step 1: Determine Rule Set

```python
def get_ruleset(file_path: str) -> RuleSet:
    if file_path.startswith('book/'):
        return BOOK_RULES
    elif file_path.startswith('docs/'):
        return DOCS_RULES
    elif file_path.startswith('wiki/'):
        return WIKI_RULES
    elif re.match(r'plugins/[^/]+/README\.md$', file_path):
        return PLUGIN_README_RULES
    else:
        return DOCS_RULES  # Default to strict
```

### Step 2: Run Checks

```python
def validate_file(file_path: str, content: str) -> ValidationResult:
    rules = get_ruleset(file_path)
    violations = []

    # Structure checks
    lines = content.split('\n')
    if len(lines) > rules.max_lines:
        violations.append({
            'severity': 'warning',
            'type': 'file_length',
            'actual': len(lines),
            'limit': rules.max_lines
        })

    # Wall-of-text check
    violations.extend(detect_wall_of_text(content, rules.max_sentences))

    # Filler phrase check
    violations.extend(detect_filler(content))

    return ValidationResult(
        file_path=file_path,
        ruleset=rules.name,
        violations=violations,
        passed=len([v for v in violations if v.get('severity') == 'error']) == 0
    )
```

### Step 3: Report Format

```markdown
## Style Validation: docs/api-overview.md

Using ruleset: **docs/ (strict)**

### Violations Found

| Severity | Type | Details | Suggestion |
|----------|------|---------|------------|
| warning | wall_of_text | Paragraph 3 has 7 sentences (limit: 4) | Break into smaller paragraphs |
| info | filler_phrase | "in order to" | Remove or rewrite directly |
| info | filler_phrase | "This document describes" | Start with content directly |

### Passed Checks
- File length: 287/500 lines
- Section lengths: All under 100 lines
- No marketing language detected
```

## Progressive Loading

This module loads only when Phase 4 (Guidelines Verified) is reached. It does not run during earlier phases to conserve context.

**Load trigger**: `doc-updates:edits-applied` completed
**Dependencies**: None


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)