cc-os/plugins/os-doc-hygiene/openspec/project.md

100 lines
4.5 KiB
Markdown

# 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).