cc-os/plugins/os-doc-hygiene/CLAUDE.md

7.0 KiB
Raw Blame History

doc-hygiene

Claude Code plugin that monitors and manages stale and bloated project documentation. Installed globally, operates per-project. Reminds (deterministic, zero-token) on SessionStart; checks and cleans on demand via skills.

Read PRD.md first — it is the source of truth for scope, decisions, and rationale. This file is the build map.

Vault user guide (nuance/mental-model, not a how-to): ~/Documents/SecondBrain/user-guide/os-doc-hygiene-user-guide.md.

Lifecycle layer (2026-07-15)

A rulebook layer sits on top of the scan/classify/clean core: global rulebook.json + optional per-project .dochygiene-rules.json declare lifetime rules for known-temporary artifacts, feeding tier derivation and a /os-doc-hygiene:calibrate skill for tuning rules against a real project. Read lifecycle-spec.md before touching rulebook.py, the scanner's lifecycle signals, or the calibrate skill; decisions are ADR-00380041.

Core distinction (do not conflate)

  • Stale = the doc is wrong (contradicted, orphaned, superseded, provisional, completed-in-place, duplicated). Remedy: fix or remove.
  • Bloat = the doc is true but mostly irrelevant (distill, split, freeze). Remedy: change its altitude, almost never delete history.

Severity scales with injection frequency — a stale line in CLAUDE.md (auto -injected every session) is worse than the same line in a doc nobody opens.

Design invariants (see PRD + reversion-protection pattern)

  1. The SessionStart hook only reminds — it never runs analysis or mutates anything, and spends no AI tokens. All mutation is user-invoked.
  2. Reminder snoozes (≤ once/day while stale) via last_reminded.
  3. State lives in-project under gitignored .cc-os/dochygiene/ (ADR-0027; legacy .dochygiene/ is fallback-read only). No global index.
  4. Report rollover: keep only the latest report. The tool must not become the bloat it polices.
  5. Cleanup is git-safe: clean/committed tree required (or auto WIP checkpoint), each run is one reviewable commit.
  6. Deterministic-first: scan/state/patch-apply/token-estimate are scripts (no model). AI does only classification and prose distillation.
  7. Safety tiers: auto (deterministic+reversible+objective) runs without prompt; confirm (destructive/subjective/generative) escalates for approval.
  8. mtime guard: never apply a cached edit to a file changed since the check.
  9. Frozen/ignored files (hygiene: frozen frontmatter, .dochygiene-ignore, append-only logs) are never flagged.

Changing any invariant requires updating invariants.md and the golden examples, with explicit human approval.

Build order (report schema gates everything)

  1. Machine report schema — the contract every component consumes. Freeze first. (per-file: category, signals, op, op-type, safety tier, optional exact-edit, token estimate.)
  2. Deterministic corebuild-spike #1 first: a trivial hooks/hooks.json emitting a systemMessage banner on SessionStart, confirmed to render visibly in a real session (no plugin in this collection wires a CC hook yet). Then: scanner (signals + shortlist), state store (timestamps, rollover, snooze, atomic writes, project-root resolution), reminder hook (SessionStart, matcher: startup|resume, injected-clock testable).
  3. check skill — scanner shortlist → AI classify (Sonnet, judgment only) → report_builder.py deterministic finalize pass → human + machine reports → update last_check. The finalize pass sits between model classification and the report write (invariants #6, #10): it computes expected_sha256, looks up is_destructive/is_reversible from exact_edit.kind, derives safety_tier via validate_report.py's single-source derive_safety_tier(...), sources raw_tokens from the token estimator, and assembles the schema-valid machine report + human-report skeleton. The model authors none of those four fields.
  4. clean skill + patch-applier — consume report, mtime-guard, apply deterministic ops mechanically, delegate generative to Sonnet, gate confirm, git checkpoint + single commit, scopable by category/file → update last_clean. Then sweep = check-then-clean.
    • RESOLVED (Phase 4): insert-frontmatter ops have has_anchor=False and carry no expected_sha256, so invariant #8's content hash cannot protect them. The applier re-derives frontmatter freshness at apply time: re-read the file, parse frontmatter; key present with target value → idempotent no-op; key present with different value → skip (frontmatter-key-conflict); key absent → insert. No cached hash is trusted. This resolves the deferred hole noted in add-check.
  5. Bonus (v2) — deterministic patch-apply hardening + token estimator (local tokenizer, injection-frequency weighting, bottom-up rollup).

Intended layout (per cc-plugins conventions)

doc-hygiene/
├── .claude-plugin/plugin.json      # done
├── PRD.md                          # done — source of truth
├── CLAUDE.md                       # this file
├── invariants.md                   # TODO — declare behavioral invariants
├── skills/                         # slash-command entry points: /os-doc-hygiene:<skill>
│   ├── check/SKILL.md
│   ├── clean/SKILL.md
│   ├── status/SKILL.md
│   └── sweep/SKILL.md
├── scripts/                        # Python OOP — scanner, state, reminder, estimator, report_builder, applier
│   └── ...
├── hooks/hooks.json                # SessionStart wiring → reminder script (systemMessage banner)
├── examples/golden/                # classifier golden examples (input tree → expected report)
└── tests/                          # unit tests per deterministic seam + fixture doc trees

Conventions (inherited from cc-plugins)

  • Language: Python, OOP — small single-responsibility classes, dependency injection, immutable transforms where possible. See ../cc-architect/references/tool-patterns/deterministic-scripting.md.
  • Scripts: structured JSON output, correct exit codes, idempotent, testable in isolation with injected clock/filesystem.
  • Model routing: scripts = no model; classification = Sonnet (hard cases → Opus); generative distillation = Sonnet (NOT Haiku); orchestration = Opus.
  • Reversion protection: invariants.md + examples/golden/ + change-impact analysis + human gate for golden-example changes. See ../cc-architect/references/tool-patterns/reversion-protection.md.
  • Read a directory's CONTEXT.md before its source files (progressive disclosure); generate one per directory as it's built.

Completion steps (do NOT do until functional)

  1. Add invariants.md and 35 golden examples.
  2. Register in ../.claude-plugin/marketplace.json (name + source + description, matching plugin.json). See ../.claude/references/plugin-registration.md.
  3. Verify installable via /install doc-hygiene@cc-plugins.