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-progressoffers this at session end (it no longer sweeps inline);/good-morningsurfaces 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
AskUserQuestionoffer, and the actual file writes still prompt (Write/Editare 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-maintainedskills:/lists:stamps; the human-setconfig:knobs are never touched.
How each step works (the shared pattern)
Every step follows the same five-beat shape:
- Cadence-gate. Read the step's
last_*stamp from.meta/ledger.yamland its interval fromconfig.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.) - Offer. If due, present an
AskUserQuestionYes/No. Decline = skip, no change. - Act. Review / prune / drain / nudge.
- 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 toarchive/README.mdbefore appending. - Restamp. Update the ledger — the step's
last_*date plus a refreshedcountandaged_count(entries older thanconfig.aging_days) for the touched store, so the bookends can surface bloat/aging from the stamps without loading the store. Write onlyskills:/lists:— neverconfig:.
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_upband — a calm heads-up.warnband — a warning.firmband — 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 toarchive/bookmarks.md— there is no separatearchive/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.mdline), 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 catalog — staleness 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
### Doneinto 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 thanconfig.done_log.drain_age_daystoarchive/done-log.md, keeping theconfig.done_log.min_recentmost-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. Restampdone_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:
- Identify the seed change — the section/topic just worked on whose ripples we're tracing. If ambiguous, ask before scanning.
- 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. - Scan obvious non-manifest neighbors the change clearly implicates (the active
current-plan.mdsection, a siblingSKILL.md). The manifest is the floor, not the ceiling. - Summarize the drift to
working/hygiene.md(the drift scratchpad — survives/clear;/good-morningsurfaces it if items remain). Per item: doc + location, drift (quoted briefly), proposed fix (or "needs your call"), and class —status/wording(safe to fix on request) vssubstance(a decision/convention/architecture — flag, don't presume). If nothing drifted, write a dated "clean" line. - 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).