Align os-doc-hygiene skill naming and invocation with marketplace convention
Rename skills to bare verbs (hygiene-check -> check, hygiene-clean -> clean), matching the os-vault/os-orchestration pattern. Remove the commands/hygiene.md dispatcher in favor of two new skills, status and sweep, so all four actions are invoked directly as /os-doc-hygiene:<skill> instead of through a custom subcommand parser that no other plugin in the marketplace uses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b235e99145
commit
7ae45c7bf8
|
|
@ -89,8 +89,8 @@ to those two and fix the stale doc.
|
||||||
|
|
||||||
**Global os-doc-hygiene plugin** — `cc-os/plugins/os-doc-hygiene/` (git-tracked, 2026-07-03); symlinked into `~/.claude/plugins/os-doc-hygiene`
|
**Global os-doc-hygiene plugin** — `cc-os/plugins/os-doc-hygiene/` (git-tracked, 2026-07-03); symlinked into `~/.claude/plugins/os-doc-hygiene`
|
||||||
- Hooks: `hooks/hooks.json` → SessionStart hook (matcher: startup|resume) runs `scripts/reminder.py` via `${CLAUDE_PLUGIN_ROOT}` (5s timeout), emitting a deterministic zero-token reminder banner
|
- Hooks: `hooks/hooks.json` → SessionStart hook (matcher: startup|resume) runs `scripts/reminder.py` via `${CLAUDE_PLUGIN_ROOT}` (5s timeout), emitting a deterministic zero-token reminder banner
|
||||||
- Behavior: Monitors stale and bloated project documentation per-project under `.dochygiene/` state dir (gitignored). SessionStart reminder is deterministic (no AI tokens, once/day snooze). Skills: `hygiene-check` (AI-assisted classification of staleness signals, emits machine+human reports), `hygiene-clean` (AI-assisted or deterministic patch application with git-safe scoped cleanup). Reversion-protected via invariants.md + golden-example test fixtures.
|
- Behavior: Monitors stale and bloated project documentation per-project under `.dochygiene/` state dir (gitignored). SessionStart reminder is deterministic (no AI tokens, once/day snooze). Skills (verb-first, no `commands/` dispatcher — invoked directly as `/os-doc-hygiene:<skill>`, per [[cc-os-plugin-skill-naming-convention]]): `check` (AI-assisted classification of staleness signals, emits machine+human reports), `clean` (AI-assisted or deterministic patch application with git-safe scoped cleanup), `status` (read-only lifecycle-timestamp read), `sweep` (check then clean in sequence). Reversion-protected via invariants.md + golden-example test fixtures.
|
||||||
- Migration: migrated from standalone repo (`~/dev/cc-plugins/doc-hygiene/`, 2026-07-03) and integrated into cc-os. No content conflicts detected (doc-hygiene scope does not overlap cc-os memory system). Renamed from `doc-hygiene` to `os-doc-hygiene` per cc-os plugin naming convention.
|
- Migration: migrated from standalone repo (`~/dev/cc-plugins/doc-hygiene/`, 2026-07-03) and integrated into cc-os. No content conflicts detected (doc-hygiene scope does not overlap cc-os memory system). Renamed from `doc-hygiene` to `os-doc-hygiene` per cc-os plugin naming convention. Skills renamed `hygiene-check`/`hygiene-clean` → `check`/`clean`, and the `commands/hygiene.md` dispatcher removed in favor of two new skills (`status`, `sweep`), aligning with the `os-vault`/`os-orchestration` pattern of no `commands/` directory (2026-07-03).
|
||||||
|
|
||||||
**Graphify** — v0.8.31 at `/home/jared/.local/bin/graphify`
|
**Graphify** — v0.8.31 at `/home/jared/.local/bin/graphify`
|
||||||
- Vault graph: `~/Documents/SecondBrain/graphify-out/` — disposable, structural index rebuilt by SessionStart hook; handles relational/graph queries. Distinct from vault-index.json (planned, Plan B Phase 1): a flat `{tag: [{path, title, summary}]}` lookup rebuilt at SessionEnd, queried by the `/memory-find` skill for fast tag-based SB note discovery.
|
- Vault graph: `~/Documents/SecondBrain/graphify-out/` — disposable, structural index rebuilt by SessionStart hook; handles relational/graph queries. Distinct from vault-index.json (planned, Plan B Phase 1): a flat `{tag: [{path, title, summary}]}` lookup rebuilt at SessionEnd, queried by the `/memory-find` skill for fast tag-based SB note discovery.
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,11 @@ doc-hygiene/
|
||||||
├── PRD.md # done — source of truth
|
├── PRD.md # done — source of truth
|
||||||
├── CLAUDE.md # this file
|
├── CLAUDE.md # this file
|
||||||
├── invariants.md # TODO — declare behavioral invariants
|
├── invariants.md # TODO — declare behavioral invariants
|
||||||
├── commands/ # /hygiene entry points (check / clean / sweep / status)
|
├── skills/ # slash-command entry points: /os-doc-hygiene:<skill>
|
||||||
├── skills/
|
│ ├── check/SKILL.md
|
||||||
│ ├── hygiene-check/SKILL.md
|
│ ├── clean/SKILL.md
|
||||||
│ └── hygiene-clean/SKILL.md
|
│ ├── status/SKILL.md
|
||||||
|
│ └── sweep/SKILL.md
|
||||||
├── scripts/ # Python OOP — scanner, state, reminder, estimator, report_builder, applier
|
├── scripts/ # Python OOP — scanner, state, reminder, estimator, report_builder, applier
|
||||||
│ └── ...
|
│ └── ...
|
||||||
├── hooks/hooks.json # SessionStart wiring → reminder script (systemMessage banner)
|
├── hooks/hooks.json # SessionStart wiring → reminder script (systemMessage banner)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Task 1.2 requires a human to start a real Claude Code session and **visually con
|
||||||
|
|
||||||
**To confirm:** start a fresh Claude Code session (any directory; plugin is user-scoped) and look for, alongside the memsearch line:
|
**To confirm:** start a fresh Claude Code session (any directory; plugin is user-scoped) and look for, alongside the memsearch line:
|
||||||
|
|
||||||
[doc-hygiene] Documentation health reminder is active. Run /hygiene check to scan for stale or bloated docs.
|
[doc-hygiene] Documentation health reminder is active. Run /os-doc-hygiene:check to scan for stale or bloated docs.
|
||||||
|
|
||||||
- **Renders** → check task 1.2, then do task 1.3 (record the confirmed format: plugin-root `hooks/hooks.json`, top-level `hooks` key, per-matcher nested `hooks` array, `systemMessage` field, `matcher: startup|resume`, `timeout: 5`). Then build Group 4, then Group 5.
|
- **Renders** → check task 1.2, then do task 1.3 (record the confirmed format: plugin-root `hooks/hooks.json`, top-level `hooks` key, per-matcher nested `hooks` array, `systemMessage` field, `matcher: startup|resume`, `timeout: 5`). Then build Group 4, then Group 5.
|
||||||
- **Blank** → the hooks.json format or loading is wrong for this build; debug BEFORE Group 4 inherits the format. (Format currently mirrors the canonical corrected shape from commit `4d595a9`, avoiding the 3 prior hook-format bugs.)
|
- **Blank** → the hooks.json format or loading is wrong for this build; debug BEFORE Group 4 inherits the format. (Format currently mirrors the canonical corrected shape from commit `4d595a9`, avoiding the 3 prior hook-format bugs.)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# commands/
|
|
||||||
|
|
||||||
Slash-command entry points for the doc-hygiene plugin. Thin dispatchers — they
|
|
||||||
parse `$ARGUMENTS`, route to a skill or run a read-only state read, and surface
|
|
||||||
the result. They own no analysis logic of their own (invariant #6 lives in the
|
|
||||||
scripts/skills they call).
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `hygiene.md` | `/hygiene` — the single user entry point. Parses the first token of `$ARGUMENTS` as the subcommand and passes the rest through. Subcommands: **`check [--scope <glob-or-path>] [--category <class\|subtype>]`** invokes the `hygiene-check` skill verbatim (the skill owns the full scan → classify → finalize → validate → write → stamp `last_check` workflow; the command does NOT scan or classify); **`status`** is read-only (no skill, no model, no scan) — calls `state_store.py` via `python3 -c` and prints the three lifecycle timestamps (`last_check`/`last_clean`/`last_reminded`) plus report presence; **`clean`** / **`sweep`** are reserved and respond "not yet implemented (Phase 4)". No args or an unrecognized subcommand prints usage then runs the `status` read. Scripts resolve under `${CLAUDE_PLUGIN_ROOT}/scripts/` (mirrors `hooks/hooks.json`). |
|
|
||||||
|
|
||||||
## Arg semantics (pass-through to `hygiene-check`)
|
|
||||||
|
|
||||||
- `--scope <glob-or-path>` — narrows the scan. A glob (contains `*`) maps to the
|
|
||||||
scanner's `--globs`; a bare path is handled by the skill as a post-scan prefix
|
|
||||||
filter (the scanner's glob matcher is unreliable for mid-pattern `**`).
|
|
||||||
- `--category <class|subtype>` — filters which **entries** are produced, applied
|
|
||||||
by the skill *after* classification (the scanner is category-agnostic). `class`
|
|
||||||
∈ { `stale`, `bloat` }; `subtype` is one of the closed enum values.
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
---
|
|
||||||
name: hygiene
|
|
||||||
description: Manage stale and bloated docs. `/hygiene check` scans the project for stale/bloated documentation and writes a report; `/hygiene clean` applies documented findings; `/hygiene sweep` runs check then clean; `/hygiene status` shows the last check/clean/reminded timestamps and whether a report exists.
|
|
||||||
argument-hint: "[check [--scope <glob-or-path>] [--category <class|subtype>] | status | clean [--scope <glob-or-path>] [--category <class|subtype>] | sweep [--scope <glob-or-path>] [--category <class|subtype>]]"
|
|
||||||
---
|
|
||||||
|
|
||||||
# /hygiene — Documentation Hygiene
|
|
||||||
|
|
||||||
Single entry point for the doc-hygiene plugin. Dispatch on `$ARGUMENTS`.
|
|
||||||
|
|
||||||
Parse the first token of `$ARGUMENTS` as the subcommand; everything after it is
|
|
||||||
passed through. Scripts live under `${CLAUDE_PLUGIN_ROOT}/scripts/` (mirrors
|
|
||||||
`hooks/hooks.json`).
|
|
||||||
|
|
||||||
## `check [--scope <glob-or-path>] [--category <class|subtype>]`
|
|
||||||
|
|
||||||
Invoke the **`hygiene-check`** skill (Skill tool, `skill: "hygiene-check"`),
|
|
||||||
passing the `--scope` and `--category` arguments through verbatim. The skill owns
|
|
||||||
the full workflow — scan → classify → finalize → validate → write report → stamp
|
|
||||||
`last_check`. Do not scan or classify here; just route to the skill and surface
|
|
||||||
its summary.
|
|
||||||
|
|
||||||
## `status`
|
|
||||||
|
|
||||||
Read-only. No skill, no model, no scan. Run the state store directly and report
|
|
||||||
the three lifecycle timestamps plus whether a report exists. `state_store.py` is a
|
|
||||||
module (no CLI), so call it via `python3 -c`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 -c '
|
|
||||||
import sys, os
|
|
||||||
sys.path.insert(0, os.environ["CLAUDE_PLUGIN_ROOT"] + "/scripts")
|
|
||||||
from state_store import StateStore, resolve_project_root
|
|
||||||
from pathlib import Path
|
|
||||||
s = StateStore(resolve_project_root(Path(os.getcwd())))
|
|
||||||
def fmt(dt): return dt.isoformat() if dt else "never"
|
|
||||||
print("last_check: " + fmt(s.get_last_check()))
|
|
||||||
print("last_clean: " + fmt(s.get_last_clean()))
|
|
||||||
print("last_reminded: " + fmt(s.get_last_reminded()))
|
|
||||||
print("report: " + ("present" if s.read_report() else "none"))
|
|
||||||
'
|
|
||||||
```
|
|
||||||
|
|
||||||
Present the output as a short human summary, for example:
|
|
||||||
|
|
||||||
```
|
|
||||||
doc-hygiene status for: <project-root>
|
|
||||||
|
|
||||||
last check 2026-06-20T14:03:11+00:00
|
|
||||||
last clean never
|
|
||||||
last reminded 2026-06-24T09:00:00+00:00
|
|
||||||
report present (run /hygiene check to refresh)
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not classify or distill anything — these are timestamp reads only.
|
|
||||||
|
|
||||||
## `clean [--scope <glob-or-path>] [--category <class|subtype>]`
|
|
||||||
|
|
||||||
Invoke the **`hygiene-clean`** skill (Skill tool, `skill: "hygiene-clean"`),
|
|
||||||
passing the `--scope` and `--category` arguments through verbatim. The skill owns
|
|
||||||
the full workflow — load report → gate confirm-tier entries → apply deterministic
|
|
||||||
ops → dispatch generative ops → commit → stamp `last_clean`. Do not apply any
|
|
||||||
edits here; just route to the skill and surface its summary.
|
|
||||||
|
|
||||||
A report must exist before running `clean`. If the user has not yet run
|
|
||||||
`/hygiene check`, the skill will stop and instruct them to do so.
|
|
||||||
|
|
||||||
## `sweep [--scope <glob-or-path>] [--category <class|subtype>]`
|
|
||||||
|
|
||||||
`sweep` is check-then-clean: a convenience that runs both skills in sequence,
|
|
||||||
passing the same `--scope` and `--category` through to each.
|
|
||||||
|
|
||||||
1. **First**, invoke the **`hygiene-check`** skill (Skill tool,
|
|
||||||
`skill: "hygiene-check"`), passing `--scope` and `--category` verbatim.
|
|
||||||
Surface the check summary to the user.
|
|
||||||
|
|
||||||
2. **Then**, invoke the **`hygiene-clean`** skill (Skill tool,
|
|
||||||
`skill: "hygiene-clean"`), passing the same `--scope` and `--category`
|
|
||||||
verbatim.
|
|
||||||
|
|
||||||
The confirm gate in `hygiene-clean` applies identically under `sweep` — sweep
|
|
||||||
does **not** auto-approve any confirm-tier or generative entries. The user will
|
|
||||||
still be prompted to approve any entries that require it before any file
|
|
||||||
mutation occurs (invariant #7).
|
|
||||||
|
|
||||||
`sweep` produces at most one cleanup commit (the clean step); the check step
|
|
||||||
writes only to the gitignored `.dochygiene/` and does not commit.
|
|
||||||
|
|
||||||
## No arguments or unrecognized subcommand
|
|
||||||
|
|
||||||
Print usage, then run the `status` block above and show current state:
|
|
||||||
|
|
||||||
```
|
|
||||||
/hygiene — documentation hygiene
|
|
||||||
|
|
||||||
check [--scope <glob-or-path>] [--category <class|subtype>]
|
|
||||||
scan for stale/bloated docs and write a report
|
|
||||||
status show last check/clean/reminded timestamps + report presence
|
|
||||||
clean [--scope <glob-or-path>] [--category <class|subtype>]
|
|
||||||
apply documented findings (requires a report; run check first)
|
|
||||||
sweep [--scope <glob-or-path>] [--category <class|subtype>]
|
|
||||||
check then clean in sequence (confirm gate still applies)
|
|
||||||
```
|
|
||||||
|
|
@ -57,15 +57,15 @@ you want to confirm the classifier still reaches the expected judgment.
|
||||||
|
|
||||||
For each case directory:
|
For each case directory:
|
||||||
|
|
||||||
1. Run an actual classification over `input/` — either `/hygiene check
|
1. Run an actual classification over `input/` — either `/os-doc-hygiene:check
|
||||||
--scope <case>/input` or by invoking the `hygiene-check` skill against that
|
--scope <case>/input` or by invoking the `check` skill against that
|
||||||
tree. This produces a fresh machine report.
|
tree. This produces a fresh machine report.
|
||||||
|
|
||||||
> **Confirm the invocation once the check command lands.** `--scope` is a
|
> **Confirm the invocation once the check command lands.** `--scope` is a
|
||||||
> filter on a scan rooted at the resolved project root, not a re-root — to
|
> filter on a scan rooted at the resolved project root, not a re-root — to
|
||||||
> classify a case in isolation you want the check *rooted at*
|
> classify a case in isolation you want the check *rooted at*
|
||||||
> `<case>/input` (as the hermetic suite roots the scanner). Verify the exact
|
> `<case>/input` (as the hermetic suite roots the scanner). Verify the exact
|
||||||
> flag/rooting against the shipped `commands/hygiene.md` before relying on it.
|
> flag/rooting against the shipped `skills/check/SKILL.md` before relying on it.
|
||||||
2. Diff the produced classification's **stable** fields against `expected.json`,
|
2. Diff the produced classification's **stable** fields against `expected.json`,
|
||||||
per entry:
|
per entry:
|
||||||
- `category.class`
|
- `category.class`
|
||||||
|
|
|
||||||
|
|
@ -6,26 +6,26 @@ TBD - created by archiving change add-check. Update Purpose after archive.
|
||||||
### Requirement: `/hygiene` Command Surface
|
### Requirement: `/hygiene` Command Surface
|
||||||
|
|
||||||
The plugin SHALL provide a single `/hygiene` command that dispatches on its
|
The plugin SHALL provide a single `/hygiene` command that dispatches on its
|
||||||
arguments. `/hygiene check [--scope <glob-or-path>] [--category <class|subtype>]`
|
arguments. `/os-doc-hygiene:check [--scope <glob-or-path>] [--category <class|subtype>]`
|
||||||
SHALL invoke the `hygiene-check` skill. `/hygiene status` SHALL read and report the
|
SHALL invoke the `check` skill. `/os-doc-hygiene:status` SHALL read and report the
|
||||||
lifecycle timestamps (`last_check`, `last_clean`, `last_reminded`) and whether a
|
lifecycle timestamps (`last_check`, `last_clean`, `last_reminded`) and whether a
|
||||||
report exists, using no scan and no model. `/hygiene clean` and `/hygiene sweep`
|
report exists, using no scan and no model. `/os-doc-hygiene:clean` and `/os-doc-hygiene:sweep`
|
||||||
SHALL be reserved and SHALL report that they are not yet implemented (Phase 4). No
|
SHALL be reserved and SHALL report that they are not yet implemented (Phase 4). No
|
||||||
arguments or unknown arguments SHALL print usage plus the current status.
|
arguments or unknown arguments SHALL print usage plus the current status.
|
||||||
|
|
||||||
#### Scenario: Check dispatches to the skill
|
#### Scenario: Check dispatches to the skill
|
||||||
|
|
||||||
- **WHEN** the user runs `/hygiene check`
|
- **WHEN** the user runs `/os-doc-hygiene:check`
|
||||||
- **THEN** the command invokes the `hygiene-check` skill, passing through any `--scope` or `--category` flag
|
- **THEN** the command invokes the `check` skill, passing through any `--scope` or `--category` flag
|
||||||
|
|
||||||
#### Scenario: Status is read-only
|
#### Scenario: Status is read-only
|
||||||
|
|
||||||
- **WHEN** the user runs `/hygiene status`
|
- **WHEN** the user runs `/os-doc-hygiene:status`
|
||||||
- **THEN** the command reports `last_check`, `last_clean`, `last_reminded`, and whether a report exists, without running a scan or any model
|
- **THEN** the command reports `last_check`, `last_clean`, `last_reminded`, and whether a report exists, without running a scan or any model
|
||||||
|
|
||||||
#### Scenario: Clean and sweep are reserved
|
#### Scenario: Clean and sweep are reserved
|
||||||
|
|
||||||
- **WHEN** the user runs `/hygiene clean` or `/hygiene sweep`
|
- **WHEN** the user runs `/os-doc-hygiene:clean` or `/os-doc-hygiene:sweep`
|
||||||
- **THEN** the command reports that the subcommand is not yet implemented (Phase 4) and does not mutate anything
|
- **THEN** the command reports that the subcommand is not yet implemented (Phase 4) and does not mutate anything
|
||||||
|
|
||||||
#### Scenario: Unknown arguments print usage
|
#### Scenario: Unknown arguments print usage
|
||||||
|
|
@ -35,7 +35,7 @@ arguments or unknown arguments SHALL print usage plus the current status.
|
||||||
|
|
||||||
### Requirement: Check Skill Orchestrates Scan, Classification, and Report Writing
|
### Requirement: Check Skill Orchestrates Scan, Classification, and Report Writing
|
||||||
|
|
||||||
The `hygiene-check` skill SHALL orchestrate the check pipeline: run the deterministic
|
The `check` skill SHALL orchestrate the check pipeline: run the deterministic
|
||||||
scanner, dispatch a Sonnet subagent for judgment-only classification of the
|
scanner, dispatch a Sonnet subagent for judgment-only classification of the
|
||||||
signal-bearing candidates, run the deterministic finalize pass, validate, write the
|
signal-bearing candidates, run the deterministic finalize pass, validate, write the
|
||||||
report pair, and stamp `last_check`. The skill SHALL run all non-judgment steps as
|
report pair, and stamp `last_check`. The skill SHALL run all non-judgment steps as
|
||||||
|
|
@ -47,7 +47,7 @@ after classification; both SHALL be recorded in the human-report header.
|
||||||
|
|
||||||
#### Scenario: Skill runs the full pipeline
|
#### Scenario: Skill runs the full pipeline
|
||||||
|
|
||||||
- **WHEN** the `hygiene-check` skill runs
|
- **WHEN** the `check` skill runs
|
||||||
- **THEN** it scans (deterministic), classifies signal-bearing candidates (Sonnet), finalizes (deterministic), validates (deterministic), writes the report pair (deterministic), and stamps `last_check` (deterministic)
|
- **THEN** it scans (deterministic), classifies signal-bearing candidates (Sonnet), finalizes (deterministic), validates (deterministic), writes the report pair (deterministic), and stamps `last_check` (deterministic)
|
||||||
|
|
||||||
#### Scenario: Zero-signal files are not read by the model
|
#### Scenario: Zero-signal files are not read by the model
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ single batch-confirm list showing path, category, op, token count, and rationale
|
||||||
per-entry opt-out, visually distinguishing irreversible `delete-range` entries from
|
per-entry opt-out, visually distinguishing irreversible `delete-range` entries from
|
||||||
reversible entries. The approved set SHALL be all `auto` entries plus any
|
reversible entries. The approved set SHALL be all `auto` entries plus any
|
||||||
user-approved `confirm` entries. The gate SHALL run identically under `sweep` — the
|
user-approved `confirm` entries. The gate SHALL run identically under `sweep` — the
|
||||||
`/hygiene sweep` convenience path SHALL NOT bypass invariant #7.
|
`/os-doc-hygiene:sweep` convenience path SHALL NOT bypass invariant #7.
|
||||||
|
|
||||||
#### Scenario: auto entries apply without prompt
|
#### Scenario: auto entries apply without prompt
|
||||||
|
|
||||||
|
|
@ -113,8 +113,8 @@ user-approved `confirm` entries. The gate SHALL run identically under `sweep`
|
||||||
|
|
||||||
#### Scenario: sweep does not bypass the gate
|
#### Scenario: sweep does not bypass the gate
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene sweep and the report contains confirm-tier entries
|
- **WHEN** the user runs /os-doc-hygiene:sweep and the report contains confirm-tier entries
|
||||||
- **THEN** the confirm gate runs identically to a standalone /hygiene clean
|
- **THEN** the confirm gate runs identically to a standalone /os-doc-hygiene:clean
|
||||||
|
|
||||||
### Requirement: Git-Safe Single Commit
|
### Requirement: Git-Safe Single Commit
|
||||||
|
|
||||||
|
|
@ -137,12 +137,12 @@ to the commit instant, not the run-start instant.
|
||||||
|
|
||||||
#### Scenario: Clean tree produces exactly one commit
|
#### Scenario: Clean tree produces exactly one commit
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene clean with a clean git tree
|
- **WHEN** the user runs /os-doc-hygiene:clean with a clean git tree
|
||||||
- **THEN** the run produces exactly one git commit containing all applied edits
|
- **THEN** the run produces exactly one git commit containing all applied edits
|
||||||
|
|
||||||
#### Scenario: Dirty tree gets a WIP checkpoint then one cleanup commit
|
#### Scenario: Dirty tree gets a WIP checkpoint then one cleanup commit
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene clean with unstaged changes in the working tree
|
- **WHEN** the user runs /os-doc-hygiene:clean with unstaged changes in the working tree
|
||||||
- **THEN** the skill auto-creates a WIP checkpoint commit of the user's work, then produces exactly one cleanup commit — two commits total, cleanup still exactly one
|
- **THEN** the skill auto-creates a WIP checkpoint commit of the user's work, then produces exactly one cleanup commit — two commits total, cleanup still exactly one
|
||||||
|
|
||||||
#### Scenario: All-skipped produces zero commits
|
#### Scenario: All-skipped produces zero commits
|
||||||
|
|
@ -167,8 +167,8 @@ to the commit instant, not the run-start instant.
|
||||||
|
|
||||||
### Requirement: Clean Skill Orchestration
|
### Requirement: Clean Skill Orchestration
|
||||||
|
|
||||||
The `hygiene-clean` skill SHALL load the current report via `StateStore.read_report`
|
The `clean` skill SHALL load the current report via `StateStore.read_report`
|
||||||
(if none, it SHALL tell the user to run `/hygiene check` and stop). It SHALL
|
(if none, it SHALL tell the user to run `/os-doc-hygiene:check` and stop). It SHALL
|
||||||
re-validate the loaded report via `validate_report.py` (if invalid, stop). It SHALL
|
re-validate the loaded report via `validate_report.py` (if invalid, stop). It SHALL
|
||||||
apply a scope/category filter to entries. It SHALL partition entries into
|
apply a scope/category filter to entries. It SHALL partition entries into
|
||||||
`auto+deterministic`, `confirm+deterministic` (i.e., `delete-range`), and
|
`auto+deterministic`, `confirm+deterministic` (i.e., `delete-range`), and
|
||||||
|
|
@ -183,8 +183,8 @@ SHA.
|
||||||
|
|
||||||
#### Scenario: No report — prompt to check first
|
#### Scenario: No report — prompt to check first
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene clean and no report exists in .dochygiene/
|
- **WHEN** the user runs /os-doc-hygiene:clean and no report exists in .dochygiene/
|
||||||
- **THEN** the skill tells the user to run /hygiene check first and stops without modifying anything
|
- **THEN** the skill tells the user to run /os-doc-hygiene:check first and stops without modifying anything
|
||||||
|
|
||||||
#### Scenario: Invalid report — stop
|
#### Scenario: Invalid report — stop
|
||||||
|
|
||||||
|
|
@ -228,22 +228,22 @@ be treated as `incompatible-ops-on-file` and skipped.
|
||||||
- **WHEN** a file has both a generative entry and a deterministic entry
|
- **WHEN** a file has both a generative entry and a deterministic entry
|
||||||
- **THEN** the applier (or skill) skips the file with reason incompatible-ops-on-file and recommends re-analysis
|
- **THEN** the applier (or skill) skips the file with reason incompatible-ops-on-file and recommends re-analysis
|
||||||
|
|
||||||
### Requirement: Sweep Composes Check Then Clean at Command Level
|
### Requirement: Sweep Composes Check Then Clean
|
||||||
|
|
||||||
`/hygiene sweep` SHALL invoke the `hygiene-check` skill followed by the
|
`/os-doc-hygiene:sweep` SHALL invoke the `check` skill followed by the
|
||||||
`hygiene-clean` skill, passing `--scope` and `--category` to both. The sweep SHALL
|
`clean` skill, passing `--scope` and `--category` to both. The sweep SHALL
|
||||||
NOT produce a double-commit: `check` writes only to the gitignored `.dochygiene/`
|
NOT produce a double-commit: `check` writes only to the gitignored `.dochygiene/`
|
||||||
directory and never commits; the single cleanup commit from `clean` is the only git
|
directory and never commits; the single cleanup commit from `clean` is the only git
|
||||||
commit the sweep produces. The sweep routing SHALL live in `commands/hygiene.md`,
|
commit the sweep produces. The sweep routing SHALL live in its own `sweep` skill
|
||||||
not in a third skill or by having the clean skill invoke the check skill internally.
|
(`skills/sweep/SKILL.md`), not by having the `clean` skill invoke `check` internally.
|
||||||
|
|
||||||
#### Scenario: Sweep routes through the command, not a third skill
|
#### Scenario: Sweep routes through its own skill, not by nesting clean inside check
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene sweep
|
- **WHEN** the user runs /os-doc-hygiene:sweep
|
||||||
- **THEN** commands/hygiene.md invokes hygiene-check then hygiene-clean sequentially, passing shared flags
|
- **THEN** the `sweep` skill invokes the `check` skill then the `clean` skill sequentially, passing shared flags
|
||||||
|
|
||||||
#### Scenario: Sweep produces at most one cleanup commit
|
#### Scenario: Sweep produces at most one cleanup commit
|
||||||
|
|
||||||
- **WHEN** the user runs /hygiene sweep on a clean tree
|
- **WHEN** the user runs /os-doc-hygiene:sweep on a clean tree
|
||||||
- **THEN** at most one git commit is produced (the cleanup commit from clean); check writes nothing to git
|
- **THEN** at most one git commit is produced (the cleanup commit from clean); check writes nothing to git
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,8 @@ class Reminder:
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# DEVIATION NOTE: the `session-reminder` spec requires the banner to "name the
|
# DEVIATION NOTE: the `session-reminder` spec requires the banner to "name the
|
||||||
# slash command the user runs". That command (`/hygiene check`) is not built in
|
# slash command the user runs". That command (`/os-doc-hygiene:check`) is not
|
||||||
# this change, so per the task we advertise that monitoring is active without
|
# built in this change, so per the task we advertise that monitoring is active without
|
||||||
# promising an unbuilt command. The staleness phrase IS retained (the spec also
|
# promising an unbuilt command. The staleness phrase IS retained (the spec also
|
||||||
# says the banner states "how stale the docs are"), keyed off `last_check`.
|
# says the banner states "how stale the docs are"), keyed off `last_check`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,20 @@
|
||||||
|
|
||||||
User-invoked skills for the doc-hygiene plugin. Skills own the multi-step
|
User-invoked skills for the doc-hygiene plugin. Skills own the multi-step
|
||||||
workflows that mix deterministic scripts (invariant #6 — no model) with the
|
workflows that mix deterministic scripts (invariant #6 — no model) with the
|
||||||
narrow model steps (classification, distillation). They are dispatched by the
|
narrow model steps (classification, distillation). They are invoked directly
|
||||||
`/hygiene` command, never by the `SessionStart` hook (invariant #1 — the hook
|
as slash commands (`/os-doc-hygiene:check`, `/os-doc-hygiene:clean`,
|
||||||
only reminds).
|
`/os-doc-hygiene:status`, `/os-doc-hygiene:sweep`) — never by the
|
||||||
|
`SessionStart` hook (invariant #1 — the hook only reminds).
|
||||||
|
|
||||||
## Contents
|
## Contents
|
||||||
|
|
||||||
| Path | Purpose |
|
| Path | Purpose |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `hygiene-check/SKILL.md` | The `check` orchestration: **scan → classify → finalize → validate → write → stamp**. (D) `scanner.py` produces the signal-bearing shortlist; candidates = the keys of `signals` (shortlist paths with zero signals are presumptively cleared, never read by the model). (M) ONE **Sonnet** subagent classifies all candidates via `workflows/classify-candidates.md`, returning slim per-file proposals (judgment only); single-file **Opus** escalation on low-confidence hard distinctions (stale-vs-bloat, delete-vs-rewrite). (logic) `--category` filter applied at the entry stage *after* classification. (D) `report_builder.py` finalizes — fills the four guardrail fields the model must not author (`expected_sha256`, `safety_tier`, `is_destructive`/`is_reversible`, `raw_tokens`) and emits a schema-valid machine report + human-report skeleton. (D) `validate_report.py` validates **on the scratch path BEFORE writing** (write_report is destructive-first; invariant #4). (D) `StateStore.write_report` does the rollover write and `set_last_check` stamps `last_check` = the validated report's own `generated_at`. All intermediates live in a session scratch dir; nothing touches `.dochygiene/` until the validated write. **LOOP GUARD:** the subagent prompt points to `workflows/classify-candidates.md`, NEVER to `SKILL.md`. **SUBAGENT AUTHORIZATION:** every subagent dispatch includes an explicit terminal-authorization directive (REPORT-AND-EXIT, never block). |
|
| `check/SKILL.md` | The `check` orchestration: **scan → classify → finalize → validate → write → stamp**. (D) `scanner.py` produces the signal-bearing shortlist; candidates = the keys of `signals` (shortlist paths with zero signals are presumptively cleared, never read by the model). (M) ONE **Sonnet** subagent classifies all candidates via `workflows/classify-candidates.md`, returning slim per-file proposals (judgment only); single-file **Opus** escalation on low-confidence hard distinctions (stale-vs-bloat, delete-vs-rewrite). (logic) `--category` filter applied at the entry stage *after* classification. (D) `report_builder.py` finalizes — fills the four guardrail fields the model must not author (`expected_sha256`, `safety_tier`, `is_destructive`/`is_reversible`, `raw_tokens`) and emits a schema-valid machine report + human-report skeleton. (D) `validate_report.py` validates **on the scratch path BEFORE writing** (write_report is destructive-first; invariant #4). (D) `StateStore.write_report` does the rollover write and `set_last_check` stamps `last_check` = the validated report's own `generated_at`. All intermediates live in a session scratch dir; nothing touches `.dochygiene/` until the validated write. **LOOP GUARD:** the subagent prompt points to `workflows/classify-candidates.md`, NEVER to `SKILL.md`. **SUBAGENT AUTHORIZATION:** every subagent dispatch includes an explicit terminal-authorization directive (REPORT-AND-EXIT, never block). |
|
||||||
| `hygiene-check/workflows/classify-candidates.md` | Self-contained subagent workflow for the classification step. Defines the slim proposal object (`path`, `category` {class, subtype}, pass-through `signals`, `op`, `op_type`, optional `exact_edit`/`reducible_range`, `gloss`, `confidence`, `escalate`), the closed enums, the situation→kind→tier decision table, and the per-kind required `exact_edit` fields. The subagent reads each file and returns judgment only — it never authors hashes, token counts, safety tiers, or reversibility. |
|
| `check/workflows/classify-candidates.md` | Self-contained subagent workflow for the classification step. Defines the slim proposal object (`path`, `category` {class, subtype}, pass-through `signals`, `op`, `op_type`, optional `exact_edit`/`reducible_range`, `gloss`, `confidence`, `escalate`), the closed enums, the situation→kind→tier decision table, and the per-kind required `exact_edit` fields. The subagent reads each file and returns judgment only — it never authors hashes, token counts, safety tiers, or reversibility. |
|
||||||
| `hygiene-clean/SKILL.md` | The `clean` orchestration: **load → validate → filter → gate → preflight → apply-deterministic → apply-generative → commit → stamp**. (D) `StateStore` loads and re-validates the machine report. (logic) Incompatible-pair detection (files with both generative + deterministic ops) and partition by `safety_tier`/`op_type`. (M-GATE) Confirm gate for `confirm`-tier entries; auto-tier entries apply silently. (D) Git preflight: record baseline, detect untracked files (which get skipped). (D) `patch_applier.py` applies deterministic entries mechanically; mtime-guarded, output include `applied`/`skipped`/`failed`. (M) Sonnet subagent distills each generative entry via `workflows/distill.md` (LOOP-GUARD + SUBAGENT AUTHORIZATION — terminal, REPORT-AND-EXIT). (D) `git-context commit-apply` produces exactly one cleanup commit. (D) `StateStore.set_last_clean` stamps the commit instant. Scoped by `--scope` (glob-or-path) and `--category` (class or subtype), both entry-stage filters. On failure (rollback-worthy): all intermediate mutations reverted to baseline. |
|
| `clean/SKILL.md` | The `clean` orchestration: **load → validate → filter → gate → preflight → apply-deterministic → apply-generative → commit → stamp**. (D) `StateStore` loads and re-validates the machine report. (logic) Incompatible-pair detection (files with both generative + deterministic ops) and partition by `safety_tier`/`op_type`. (M-GATE) Confirm gate for `confirm`-tier entries; auto-tier entries apply silently. (D) Git preflight: record baseline, detect untracked files (which get skipped). (D) `patch_applier.py` applies deterministic entries mechanically; mtime-guarded, output include `applied`/`skipped`/`failed`. (M) Sonnet subagent distills each generative entry via `workflows/distill.md` (LOOP-GUARD + SUBAGENT AUTHORIZATION — terminal, REPORT-AND-EXIT). (D) `git-context commit-apply` produces exactly one cleanup commit. (D) `StateStore.set_last_clean` stamps the commit instant. Scoped by `--scope` (glob-or-path) and `--category` (class or subtype), both entry-stage filters. On failure (rollback-worthy): all intermediate mutations reverted to baseline. |
|
||||||
| `hygiene-clean/workflows/distill.md` | Self-contained subagent workflow for generative distillation. Receives live file contents (not disk-read), category, op, and signals. Performs `distill` (condense in place, preserve frontmatter and structure, ~40–60% target length), `split` (extract to archive + pointer, archive path under `archive/`), or prose-rewrite ops (`provisional`, `contradicted`). Returns structured output (`DISTILL_RESULT_START`/`END` for single-file; `SPLIT_PRIMARY_START`/`END` + `SPLIT_ARCHIVE_DEST` + `SPLIT_ARCHIVE_START`/`END` for split). Never writes files or calls git; never re-reads disk. |
|
| `clean/workflows/distill.md` | Self-contained subagent workflow for generative distillation. Receives live file contents (not disk-read), category, op, and signals. Performs `distill` (condense in place, preserve frontmatter and structure, ~40–60% target length), `split` (extract to archive + pointer, archive path under `archive/`), or prose-rewrite ops (`provisional`, `contradicted`). Returns structured output (`DISTILL_RESULT_START`/`END` for single-file; `SPLIT_PRIMARY_START`/`END` + `SPLIT_ARCHIVE_DEST` + `SPLIT_ARCHIVE_START`/`END` for split). Never writes files or calls git; never re-reads disk. |
|
||||||
|
| `status/SKILL.md` | Read-only lifecycle-timestamp read (no model, no scan): `last_check`/`last_clean`/`last_reminded` + report presence, via `state_store.py`. |
|
||||||
|
| `sweep/SKILL.md` | Convenience wrapper: invokes `check` then `clean` in sequence, passing `--scope`/`--category` through to both. The confirm gate in `clean` still applies unchanged. |
|
||||||
|
|
||||||
## Planned additions (future changes)
|
## Planned additions (future changes)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
name: hygiene-check
|
name: check
|
||||||
description: Scan the project for stale and bloated documentation and write a hygiene report. Runs the deterministic scanner, dispatches a Sonnet subagent to classify only the signal-bearing candidates, finalizes/validates the machine report deterministically, then writes the report pair and stamps `last_check`. Invoked by `/hygiene check [--scope <glob-or-path>] [--category <class|subtype>]`.
|
description: Scan the project for stale and bloated documentation and write a hygiene report. Runs the deterministic scanner, dispatches a Sonnet subagent to classify only the signal-bearing candidates, finalizes/validates the machine report deterministically, then writes the report pair and stamps `last_check`. Invoked by `/os-doc-hygiene:check [--scope <glob-or-path>] [--category <class|subtype>]`.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Hygiene Check Skill
|
# Hygiene Check Skill
|
||||||
|
|
@ -26,7 +26,7 @@ resolved. Use the session scratchpad directory for all intermediate artifacts
|
||||||
|
|
||||||
## Arguments
|
## Arguments
|
||||||
|
|
||||||
Passed through from `/hygiene check`:
|
Passed through from `/os-doc-hygiene:check`:
|
||||||
|
|
||||||
- `--scope <glob-or-path>` — narrow the scan. A glob (contains `*`) maps to the
|
- `--scope <glob-or-path>` — narrow the scan. A glob (contains `*`) maps to the
|
||||||
scanner's `--globs`. A **bare path** does NOT map cleanly to a `--globs` value
|
scanner's `--globs`. A **bare path** does NOT map cleanly to a `--globs` value
|
||||||
|
|
@ -120,7 +120,7 @@ Agent tool parameters:
|
||||||
- description: "Classify doc-hygiene candidates"
|
- description: "Classify doc-hygiene candidates"
|
||||||
- prompt: |
|
- prompt: |
|
||||||
Read and follow the workflow at:
|
Read and follow the workflow at:
|
||||||
${CLAUDE_PLUGIN_ROOT}/skills/hygiene-check/workflows/classify-candidates.md
|
${CLAUDE_PLUGIN_ROOT}/skills/check/workflows/classify-candidates.md
|
||||||
|
|
||||||
Project root: <scan.project_root>
|
Project root: <scan.project_root>
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ Reports written:
|
||||||
<project-root>/.dochygiene/report.json
|
<project-root>/.dochygiene/report.json
|
||||||
<project-root>/.dochygiene/report.md
|
<project-root>/.dochygiene/report.md
|
||||||
|
|
||||||
Run /hygiene clean to act on these (Phase 4), or /hygiene status for timestamps.
|
Run /os-doc-hygiene:clean to act on these (Phase 4), or /os-doc-hygiene:status for timestamps.
|
||||||
```
|
```
|
||||||
|
|
||||||
The human report header renders `scope_globs` but has no category field (the
|
The human report header renders `scope_globs` but has no category field (the
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# hygiene-clean/
|
# clean/
|
||||||
|
|
||||||
The `clean` skill: documentation cleanup orchestrator. Loads the machine report
|
The `clean` skill: documentation cleanup orchestrator. Loads the machine report
|
||||||
from `/hygiene check`, gates confirm-tier entries, applies deterministic ops
|
from `/os-doc-hygiene:check`, gates confirm-tier entries, applies deterministic ops
|
||||||
via the patch applier, delegates generative distillation to a Sonnet subagent,
|
via the patch applier, delegates generative distillation to a Sonnet subagent,
|
||||||
produces exactly one cleanup commit, and stamps `last_clean`.
|
produces exactly one cleanup commit, and stamps `last_clean`.
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
name: hygiene-clean
|
name: clean
|
||||||
description: Apply documented hygiene findings to project docs. Loads the current machine report, gates confirm-tier entries, applies deterministic ops via the patch applier, dispatches generative ops to a Sonnet subagent, stages precisely, and produces exactly one git commit. Invoked by `/hygiene clean [--scope <glob-or-path>] [--category <class|subtype>]`.
|
description: Apply documented hygiene findings to project docs. Loads the current machine report, gates confirm-tier entries, applies deterministic ops via the patch applier, dispatches generative ops to a Sonnet subagent, stages precisely, and produces exactly one git commit. Invoked by `/os-doc-hygiene:clean [--scope <glob-or-path>] [--category <class|subtype>]`.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Hygiene Clean Skill
|
# Hygiene Clean Skill
|
||||||
|
|
@ -27,7 +27,7 @@ project directory (`cwd`).
|
||||||
|
|
||||||
## Arguments
|
## Arguments
|
||||||
|
|
||||||
Passed through from `/hygiene clean`:
|
Passed through from `/os-doc-hygiene:clean`:
|
||||||
|
|
||||||
- `--scope <glob-or-path>` — narrow which entries to act on. Applied at **Step 3**
|
- `--scope <glob-or-path>` — narrow which entries to act on. Applied at **Step 3**
|
||||||
(entry stage), same semantics as the check skill: a glob (contains `*`) matches
|
(entry stage), same semantics as the check skill: a glob (contains `*`) matches
|
||||||
|
|
@ -46,7 +46,7 @@ If no arguments are given, act on all entries in the report.
|
||||||
### Step 1 — (D) Load report via StateStore
|
### Step 1 — (D) Load report via StateStore
|
||||||
|
|
||||||
Resolve the project root and read the current report. If no report exists, stop
|
Resolve the project root and read the current report. If no report exists, stop
|
||||||
immediately and tell the user to run `/hygiene check` first.
|
immediately and tell the user to run `/os-doc-hygiene:check` first.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -c '
|
python3 -c '
|
||||||
|
|
@ -67,7 +67,7 @@ else:
|
||||||
```
|
```
|
||||||
|
|
||||||
- If `status == "no_report"` → tell the user: "No hygiene report found. Run
|
- If `status == "no_report"` → tell the user: "No hygiene report found. Run
|
||||||
`/hygiene check` first to generate one." **STOP.**
|
`/os-doc-hygiene:check` first to generate one." **STOP.**
|
||||||
- If `status == "ok"` → record `PROJECT_ROOT` and `REPORT_PATH` (the canonical
|
- If `status == "ok"` → record `PROJECT_ROOT` and `REPORT_PATH` (the canonical
|
||||||
`.dochygiene/report.json`) for use in subsequent steps.
|
`.dochygiene/report.json`) for use in subsequent steps.
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/scripts/validate_report.py" "$REPORT_PATH"
|
||||||
|
|
||||||
- Exit `0` → valid. Proceed to Step 3.
|
- Exit `0` → valid. Proceed to Step 3.
|
||||||
- Exit `1` → invalid. Show the violation list from stdout and stop: "The hygiene
|
- Exit `1` → invalid. Show the violation list from stdout and stop: "The hygiene
|
||||||
report is invalid. Re-run `/hygiene check` to regenerate it." **STOP.**
|
report is invalid. Re-run `/os-doc-hygiene:check` to regenerate it." **STOP.**
|
||||||
- Exit `2` → usage error (file missing after Step 1 succeeded = internal bug).
|
- Exit `2` → usage error (file missing after Step 1 succeeded = internal bug).
|
||||||
Stop and report.
|
Stop and report.
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ confirm_gen = [(i, e) for i, e in in_scope_clean
|
||||||
### Step 5 — (M-GATE) Confirm gate — BEFORE any mutation or git op
|
### Step 5 — (M-GATE) Confirm gate — BEFORE any mutation or git op
|
||||||
|
|
||||||
> **Invariant #7:** this gate must run before the first file write or git
|
> **Invariant #7:** this gate must run before the first file write or git
|
||||||
> operation. It runs identically under `/hygiene sweep`.
|
> operation. It runs identically under `/os-doc-hygiene:sweep`.
|
||||||
|
|
||||||
Only present the gate if `confirm_det` or `confirm_gen` is non-empty. If both
|
Only present the gate if `confirm_det` or `confirm_gen` is non-empty. If both
|
||||||
are empty (all entries are `auto`), skip directly to Step 6 — no prompt.
|
are empty (all entries are `auto`), skip directly to Step 6 — no prompt.
|
||||||
|
|
@ -371,7 +371,7 @@ For each approved generative entry (in order):
|
||||||
- description: "Distill doc-hygiene generative entry: <entry.path>"
|
- description: "Distill doc-hygiene generative entry: <entry.path>"
|
||||||
- prompt: |
|
- prompt: |
|
||||||
Read and follow the workflow at:
|
Read and follow the workflow at:
|
||||||
${CLAUDE_PLUGIN_ROOT}/skills/hygiene-clean/workflows/distill.md
|
${CLAUDE_PLUGIN_ROOT}/skills/clean/workflows/distill.md
|
||||||
|
|
||||||
File path (project-root-relative): <entry.path>
|
File path (project-root-relative): <entry.path>
|
||||||
Category: <entry.category.class> / <entry.category.subtype>
|
Category: <entry.category.class> / <entry.category.subtype>
|
||||||
|
|
@ -526,27 +526,27 @@ doc-hygiene clean complete (commit: <COMMIT_SHA>)
|
||||||
Confirmed (deterministic): <count>
|
Confirmed (deterministic): <count>
|
||||||
Confirmed (generative): <count>
|
Confirmed (generative): <count>
|
||||||
|
|
||||||
Skipped: <count> (re-analysis recommended — re-run /hygiene check)
|
Skipped: <count> (re-analysis recommended — re-run /os-doc-hygiene:check)
|
||||||
<for each skipped: path · kind · reason>
|
<for each skipped: path · kind · reason>
|
||||||
|
|
||||||
Incompatible-ops (skipped): <count>
|
Incompatible-ops (skipped): <count>
|
||||||
<for each: path — reason: generative+deterministic on same file>
|
<for each: path — reason: generative+deterministic on same file>
|
||||||
|
|
||||||
Untracked (skipped): <count>
|
Untracked (skipped): <count>
|
||||||
<for each: path — run `git add <path>` then re-run /hygiene check>
|
<for each: path — run `git add <path>` then re-run /os-doc-hygiene:check>
|
||||||
```
|
```
|
||||||
|
|
||||||
If a `move-to-archive` was applied, append:
|
If a `move-to-archive` was applied, append:
|
||||||
|
|
||||||
```
|
```
|
||||||
Note: move-to-archive ops create link orphans. The next /hygiene check will
|
Note: move-to-archive ops create link orphans. The next /os-doc-hygiene:check will
|
||||||
flag any new broken_reference signals in files that pointed to the moved doc.
|
flag any new broken_reference signals in files that pointed to the moved doc.
|
||||||
```
|
```
|
||||||
|
|
||||||
If entries were skipped, append:
|
If entries were skipped, append:
|
||||||
|
|
||||||
```
|
```
|
||||||
Run /hygiene check to refresh the report and pick up any remaining issues.
|
Run /os-doc-hygiene:check to refresh the report and pick up any remaining issues.
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -555,8 +555,8 @@ Run /hygiene check to refresh the report and pick up any remaining issues.
|
||||||
|
|
||||||
| Condition | Action |
|
| Condition | Action |
|
||||||
|-----------|--------|
|
|-----------|--------|
|
||||||
| No report (Step 1) | Tell user to run `/hygiene check`. STOP. No mutation. |
|
| No report (Step 1) | Tell user to run `/os-doc-hygiene:check`. STOP. No mutation. |
|
||||||
| Invalid report (Step 2) | Show violations. Tell user to re-run `/hygiene check`. STOP. |
|
| Invalid report (Step 2) | Show violations. Tell user to re-run `/os-doc-hygiene:check`. STOP. |
|
||||||
| Zero in-scope entries (Step 3) | Report no-op. STOP. No git ops. |
|
| Zero in-scope entries (Step 3) | Report no-op. STOP. No git ops. |
|
||||||
| Approved set empty (Step 5) | Report "nothing approved". STOP. No git ops. |
|
| Approved set empty (Step 5) | Report "nothing approved". STOP. No git ops. |
|
||||||
| Applier exit 2 (Step 7) | Rollback to baseline, abort with structured error. |
|
| Applier exit 2 (Step 7) | Rollback to baseline, abort with structured error. |
|
||||||
|
|
@ -590,7 +590,7 @@ echo "Rolled back to $(git rev-parse --short HEAD). No commit was created."
|
||||||
## LOOP GUARD
|
## LOOP GUARD
|
||||||
|
|
||||||
The generative subagent prompt MUST point to
|
The generative subagent prompt MUST point to
|
||||||
`skills/hygiene-clean/workflows/distill.md`, NEVER to this SKILL.md (prevents
|
`skills/clean/workflows/distill.md`, NEVER to this SKILL.md (prevents
|
||||||
recursive skill invocation).
|
recursive skill invocation).
|
||||||
|
|
||||||
**SUBAGENT AUTHORIZATION:** the distill subagent is the executor; it MUST NOT
|
**SUBAGENT AUTHORIZATION:** the distill subagent is the executor; it MUST NOT
|
||||||
|
|
@ -142,5 +142,5 @@ DISTILL_ERROR: <one-sentence reason why this entry cannot be processed>
|
||||||
6. **Be conservative.** When uncertain whether to delete or keep a passage,
|
6. **Be conservative.** When uncertain whether to delete or keep a passage,
|
||||||
keep it (distilled if possible). Deletions are harder to recover than
|
keep it (distilled if possible). Deletions are harder to recover than
|
||||||
over-cautious prose.
|
over-cautious prose.
|
||||||
7. **Do not re-invoke the parent skill** (`hygiene-clean`). This workflow is
|
7. **Do not re-invoke the parent skill** (`clean`). This workflow is
|
||||||
the final step; recursion would be incorrect.
|
the final step; recursion would be incorrect.
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
name: status
|
||||||
|
description: Show the doc-hygiene lifecycle state for the current project — last check/clean/reminded timestamps and whether a report exists. Read-only, no model, no scan. Invoked by `/os-doc-hygiene:status`.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Status Skill
|
||||||
|
|
||||||
|
Read-only. No model, no scan, no mutation. Reads the three lifecycle
|
||||||
|
timestamps plus report presence via `state_store.py` and reports them.
|
||||||
|
|
||||||
|
`state_store.py` is a module (no CLI), so call it via `python3 -c`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c '
|
||||||
|
import sys, os
|
||||||
|
sys.path.insert(0, os.environ["CLAUDE_PLUGIN_ROOT"] + "/scripts")
|
||||||
|
from state_store import StateStore, resolve_project_root
|
||||||
|
from pathlib import Path
|
||||||
|
s = StateStore(resolve_project_root(Path(os.getcwd())))
|
||||||
|
def fmt(dt): return dt.isoformat() if dt else "never"
|
||||||
|
print("last_check: " + fmt(s.get_last_check()))
|
||||||
|
print("last_clean: " + fmt(s.get_last_clean()))
|
||||||
|
print("last_reminded: " + fmt(s.get_last_reminded()))
|
||||||
|
print("report: " + ("present" if s.read_report() else "none"))
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
Present the output as a short human summary, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
doc-hygiene status for: <project-root>
|
||||||
|
|
||||||
|
last check 2026-06-20T14:03:11+00:00
|
||||||
|
last clean never
|
||||||
|
last reminded 2026-06-24T09:00:00+00:00
|
||||||
|
report present (run /os-doc-hygiene:check to refresh)
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not classify or distill anything — this is a timestamp read only.
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
name: sweep
|
||||||
|
description: Run doc-hygiene check then clean in sequence — a convenience wrapper. The confirm gate in `clean` still applies; sweep never auto-approves confirm-tier or generative entries. Invoked by `/os-doc-hygiene:sweep [--scope <glob-or-path>] [--category <class|subtype>]`.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sweep Skill
|
||||||
|
|
||||||
|
`sweep` is check-then-clean: a convenience that runs both skills in sequence,
|
||||||
|
passing the same `--scope` and `--category` through to each.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. **First**, invoke the **`check`** skill (Skill tool, `skill: "check"`),
|
||||||
|
passing `--scope` and `--category` verbatim. Surface the check summary to
|
||||||
|
the user.
|
||||||
|
|
||||||
|
2. **Then**, invoke the **`clean`** skill (Skill tool, `skill: "clean"`),
|
||||||
|
passing the same `--scope` and `--category` verbatim.
|
||||||
|
|
||||||
|
The confirm gate in `clean` applies identically under `sweep` — sweep does
|
||||||
|
**not** auto-approve any confirm-tier or generative entries (invariant #7).
|
||||||
|
The user will still be prompted to approve any entries that require it before
|
||||||
|
any file mutation occurs.
|
||||||
|
|
||||||
|
`sweep` produces at most one cleanup commit (the clean step); the check step
|
||||||
|
writes only to the gitignored `.dochygiene/` and does not commit.
|
||||||
|
|
@ -22,7 +22,7 @@ per the META-RULE). This suite asserts only the deterministic / stable parts:
|
||||||
- exact_edit.expected_sha256 == a fresh sha256 of the input/ file bytes
|
- exact_edit.expected_sha256 == a fresh sha256 of the input/ file bytes
|
||||||
(proves the golden's hashes track the fixtures).
|
(proves the golden's hashes track the fixtures).
|
||||||
|
|
||||||
The LIVE model-classification regression (actually running /hygiene check
|
The LIVE model-classification regression (actually running /os-doc-hygiene:check
|
||||||
against input/ and diffing the produced classification) lives OUTSIDE this suite
|
against input/ and diffing the produced classification) lives OUTSIDE this suite
|
||||||
— see examples/golden/classifier/README.md.
|
— see examples/golden/classifier/README.md.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue