# Project Context ## Purpose **doc-hygiene** is a Claude Code plugin that monitors and manages **stale** and **bloated** project documentation. It is installed globally but operates per-project. It reminds the developer (deterministically, zero AI tokens) on `SessionStart` when docs haven't been checked recently, then checks and cleans on demand via skills. The plugin holds a core distinction: - **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 an auto-injected file (`CLAUDE.md`, memory index) misleads every session, so it is worse than the same line in a doc nobody opens. ### Design Principles 1. **Deterministic-first** — scan, state, patch-apply, and token-estimate are scripts (no model). AI does only classification and prose distillation. 2. **Remind, don't nag** — the `SessionStart` hook only reminds; it never runs analysis or mutates anything. All mutation is user-invoked. Reminders snooze (at most once/day while stale). 3. **Non-intrusive** — state lives in-project under a gitignored `.dochygiene/`; no global index. The tool never silently edits the user's repo. 4. **Git-safe cleanup** — runs only on a clean/committed tree (or after an auto WIP checkpoint); each run lands as one reviewable commit. 5. **The tool must not become the bloat it polices** — report rollover keeps only the latest report. ## Tech Stack - **Plugin format:** Claude Code plugin (skills + commands + a `SessionStart` hook declared in `hooks/hooks.json`, emitting a `systemMessage` banner). - **Language:** Python, OOP — small single-responsibility classes, dependency injection, immutable transforms where possible. - **Scripts:** structured JSON output, correct exit codes, idempotent, testable in isolation with injected clock/filesystem. - **AI layers:** classification = Sonnet (hard cases → Opus); generative distillation = Sonnet (explicitly not Haiku); orchestration = Opus. ## Project Conventions ### Code Style - Small composable single-responsibility classes; dependency injection for testability; immutable transforms where practical. - Scripts emit structured JSON and correct exit codes; deterministic and idempotent. ### Architecture Patterns - **Deterministic / AI split:** the deterministic scanner gathers objective signals and a candidate shortlist; the AI pass classifies and distills. - **Report schema is the linchpin:** the machine report (per-file category, signals, op, op-type, safety tier, optional exact-edit, token estimate) is the contract every component consumes. It is designed and frozen first. - **Operation taxonomy:** each op is tagged op-type (`deterministic` | `generative`) and safety tier (`auto` | `confirm`). `auto` runs without prompt; `confirm` (destructive/subjective/generative) escalates for approval. - **mtime guard:** never apply a cached edit to a file changed since the check. ### Testing Strategy - Assert external behavior at the highest deterministic seam — given an input doc tree / state file / report, the script produces correct structured output and exit code. Do not assert internal class structure. - The AI classification layer is pinned by **golden examples** (`examples/golden/`) plus `invariants.md`, per the reversion-protection pattern — not by unit assertions. ### Git Workflow - Cleanup requires a clean/committed working tree, or auto-commits a WIP checkpoint first; each cleanup run lands as a single reviewable commit. - `confirm`-tier approvals are recorded to a decisions log. - No pushing or outbound/network actions — cleanup is local commits only. ## Important Constraints - The `SessionStart` hook spends no AI tokens, never mutates, keeps `timeout` low (≤5s), and always exits 0 (never blocks the session). - State and the single most-recent report live under gitignored `.dochygiene/`; the scanner always self-excludes it. - Frozen/ignored files (`hygiene: frozen` frontmatter, `.dochygiene-ignore`, append-only logs) are never flagged. - Changing any behavioral invariant requires updating `invariants.md` and the golden examples, with explicit human approval. ## External Dependencies - Claude Code plugin/hook runtime (`hooks/hooks.json`, `systemMessage` banner). - A local tokenizer approximation for the token estimator (no API token counting at check time).