name hygiene-check
description Curate the active scope's accumulating lists — prune and bloat-nudge bookmarks, demote cold items to the backburner, and review the backburner — each step cadence-gated and offered (never forced), draining retired items to archive/ and restamping .meta/ledger.yaml. Use on demand, or when /save-progress offers it at session end.
allowed-tools Read · Glob · Grep

Hygiene Check

The accumulating-list housekeeping for this scope, gathered into one command so the session bookends stay lean. Each concern is a distinct, cadence-gated, offered step over the scope's stores — bookmarks.md, backburner.md, and the archive/ sinks — with state tracked in .meta/ledger.yaml.

Bookend ties: /save-progress offers this at session end (it no longer sweeps inline); /good-morning surfaces what it produced — due reviews, bloat, aged items — from the ledger stamps. This command does the actual curation; the bookends only point at it.

What it does NOT do

  • No silent mutations. Every change sits behind an explicit AskUserQuestion offer, and the actual file writes still prompt (Write/Edit are deliberately not pre-approved). Decline any offer and nothing changes.
  • No hard deletes. Retired items are appended to an archive/ sink, never deleted outright.
  • No config: edits. The ledger restamp writes only the machine-maintained skills: / lists: stamps; the human-set config: knobs are never touched.

How each step works (the shared pattern)

Every step follows the same five-beat shape:

  1. Cadence-gate. Read the step's last_* stamp from .meta/ledger.yaml and its interval from config.cadence_days; the step is due only if elapsed time ≥ the interval. If not due, stay silent and skip — no prompt. (The bookmark step is count-gated rather than time-gated — noted on it below.)
  2. Offer. If due, present an AskUserQuestion Yes/No. Decline = skip, no change.
  3. Act. Review / prune / drain / nudge.
  4. Drain. Retired items are appended to their archive/<source>.md. If that archive file doesn't exist yet, create it with the standard archive header and add a line for it to archive/README.md before appending.
  5. Restamp. Update the ledger — the step's last_* date plus a refreshed count and aged_count (entries older than config.aging_days) for the touched store, so the bookends can surface bloat/aging from the stamps without loading the store. Write only skills: / lists: — never config:.

Locate the scope's stores by context (Glob), not hardcoded paths — the same way /bookmarking does. Run the steps in order; a not-due step produces no output.

Steps

1. Bookmark prune + bloat-nudge

Count-gated, not time-gated — the bloat state is always worth surfacing, so this step has no cadence_days entry and runs whenever the command is invoked. Count bookmarks.md's entries and surface the band against config.bloat (each band = the count at or above that named threshold — read the numbers from the ledger, don't restate them here):

  • Below heads_up — celebrate (especially a prune that just dropped it back to single digits).
  • heads_up band — a calm heads-up.
  • warn band — a warning.
  • firm band — a firm > **Gate:**-style push to prune.

Reacclimation. If the count has sat in the heads_up band (or higher) since count_band_since for ≥ config.reacclimation_days, add a "been a while — here's where things stood" note (the review doubles as re-orientation after time away). An init-stamped count_band_since (seeded the day the ledger was created) whose count is already in the firm band counts as immediately eligible — the seed date must not suppress the nudge.

Prune (offered). Offer a prune pass: walk the entries with the user, retiring resolved or dead ones to archive/bookmarks.md (the drain beat). Then restamp active_bookmarks: count, aged_count, last_pruned = today, and count_band_since — set it when the count first enters the heads_up band, clear it when a prune drops the count below heads_up, and otherwise leave it unchanged.

2. Active → backburner demotion

The pressure valve for chronically-deferred bookmarks. Offer moving cold or far-future active bookmarks from bookmarks.md to backburner.md (the cold store). Accepted items move — append to backburner.md, remove from bookmarks.md. This is a move, not a prune, so nothing drains to archive/. Restamp both stores' count (and active_bookmarks.aged_count).

3. Backburner review

Cadence-gated on config.cadence_days.backburner. If due, offer a walk of backburner.md, dispositioning each item:

  • revive → back to an active bookmark in bookmarks.md;
  • promote → a Target (a plan task or its own design thread);
  • archive → retire to archive/bookmarks.md. Backburner items are cold bookmarks, so their archive exit drains to archive/bookmarks.md — there is no separate archive/backburner.md.

Restamp backburner.last_reviewed = today and the count/aged_count of both stores touched.

4. Session-lessons review + graduation

Cadence-gated on config.cadence_days.session_lessons. If due, offer a staleness and graduation pass over the flat ## Session lessons list in current-plan.md:

  • graduate → a proven, broadly-true lesson moves up a layer into a durable convention (an AGENTS.md / CLAUDE.md line), then leaves the list;
  • archive → a stale or one-off lesson retires to archive/session-lessons.md.

If the list has grown long, add a quantity nag (same spirit as the bloat nudge — informational, not forced). Restamp session_lessons: last_reviewed = today plus a refreshed count / aged_count.

5. Catalog review + graduation

Cadence-gated on config.cadence_days.catalog. If due, offer a staleness and graduation pass over the ## Design decisions catalogstaleness and graduation only; a settled entry is not re-litigated. A superseded entry retires to archive/catalog.md; a graduated one moves up into the relevant durable doc. Restamp catalog.last_reviewed = today.

6. Done-log compaction + age-drain

Self-bounding — no review, no nags (§5.4). The Done log (### Done plus the active phase's dated Done YYYY-MM-DD blocks) is two-tier: closed phases as one-line summaries (the lightweight arc, kept forever) and the active phase's work as dated granular bullets.

  • One-time normalization (setup; not cadence-gated). Reshape ### Done into the two-tier shape if it isn't already. Where an entry is too terse or truncated to reshape confidently, leave it and flag it passively ((couldn't confidently reshape — left in place)) rather than blocking. Once done, a no-op.
  • Phase-compaction (recurring). When a phase closes, collapse its granular bullets into a one-line summary that stays in place (the arc).
  • Age-drain (recurring, cadence-gated on config.cadence_days.done_drain). Move granular Done bullets older than config.done_log.drain_age_days to archive/done-log.md, keeping the config.done_log.min_recent most-recent regardless of age. Report a callout of exactly what rotated out — each drained entry by date and a short content hint (a phrase or two of substance, not just the date), so the one automatic exit stays legible. Restamp done_log.last_drained. Age-drain is Done-log-only — every other list reaches the archive via review/prune, not by aging out.

7. Consistency check (drift between durable docs)

Event-driven, not cadence-gated — there's no cadence_days entry; offer it when the session has touched durable docs (or on request), since drift follows edits, not the clock. Ported from the retired /consistency-check:

  1. Identify the seed change — the section/topic just worked on whose ripples we're tracing. If ambiguous, ask before scanning.
  2. Walk the durable-docs manifest (.meta/durable-docs.md) — for each doc, does the seed change leave it stale, contradictory, or incomplete? Read from source, don't infer. A relevance filter, not a mandate to touch every file.
  3. Scan obvious non-manifest neighbors the change clearly implicates (the active current-plan.md section, a sibling SKILL.md). The manifest is the floor, not the ceiling.
  4. Summarize the drift to working/hygiene.md (the drift scratchpad — survives /clear; /good-morning surfaces it if items remain). Per item: doc + location, drift (quoted briefly), proposed fix (or "needs your call"), and classstatus/wording (safe to fix on request) vs substance (a decision/convention/architecture — flag, don't presume). If nothing drifted, write a dated "clean" line.
  5. Report inline, say the list is saved, then stop. Offer to apply the status/wording fixes now or leave them. Fixing and committing are separate, user-authorized steps.

Scratchpad drain (the §5.5 non-canonical-archive convention). When resolved runs accumulate in working/hygiene.md, append them to archive/hygiene.md — creating that file with the standard archive header + an archive/README.md line if it's new — then remove the resolved runs, leaving only genuinely-open items. No ledger stamp (this step is event-driven, not cadence-gated).