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

114 lines
6.4 KiB
Markdown
Raw Normal View 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.
## 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 `.dochygiene/`. 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 core***build-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
├── commands/ # /hygiene entry points (check / clean / sweep / status)
├── skills/
│ ├── hygiene-check/SKILL.md
│ └── hygiene-clean/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`.