Accumulating-List Hygiene — Design

Status: Design complete (session 2026-06-05); extended 2026-06-08 with the plan-deferral descendant (§5.6), the out-of-context bookmark revision (§5.1 / §8), and the per-item aging anti-rot primitive (§4 #8). Pending final section-by-section review. Build not yet started.

Context: This is the full scope of the parked-items / bookmark-unification thread (see current-plan.md), expanded to swallow session lessons, the Done log, the design catalog, and the archive idea. It supersedes the scattered fragments — the parked-items design section, the session-lessons-as-bookmarks bookmark, and the pruned-items archive/ directory idea — which collapse into the one system described here.


1. Purpose

The project keeps re-inventing the same mechanism — a dated list that accumulates, needs pruning, and risks bloat — for bookmarks, session lessons, architectural bookmarks, the Done log, the design catalog. Each has been hand-managed differently. This design unifies them under one type system, one base format, one set of shared primitives, and one housekeeping ledger, so every list/doc is maintained the same way and nothing grows unbounded or silently rots.


2. Type vocabulary

Four types. (The word "tier" is retired — it had been pointed at two different axes and is too overloaded to keep.)

  • List — a live backlog things flow through: capture → triage → exit. Three axes describe any List:
    • Scope — which layer owns it: personal / Yggdrasil / Odin Codin' / a specific project. Determines where the store physically lives.
    • State — how live an item is: hot (plan-deferral) → active → cold (backburner).
    • Context-load — whether the store is routinely loaded into context (in-context) or deliberately kept out (out-of-context, a separate file).
  • Target — a graduation sink: where a promoted item lands and stays active / in-context (the Done log, the design catalog, an AGENTS/CLAUDE convention).
  • Archive — a prune sink: the append-only, out-of-context record where retired items go. The "never gets deleted" log.
  • Scratchpad — transient work-state with a delete-when-done lifecycle (e.g. working/hygiene.md). Not a parked item (no triage, graduation, or archive) — named here only to draw the boundary. Its hygiene is a deliberate scope-out, deferred to a bookmarked follow-on (see §10).

Core model: a List has exactly two exits — promote to a Target or prune to an Archive. Graduation can be multi-hop (bookmark → catalog → AGENTS/CLAUDE convention).


3. Base format primitive — a dated prose bullet

Every entry in every list/doc/archive inherits this parent:

- **YYYY-MM-DD** — <freeform prose content>
  • Date (mandatory). All hygiene keys off dates — age-drain, the 7-day "been-a-while" trigger, review cadence. One ledger can drive every list only because every entry is dated.
  • Content (freeform prose). Notes-to-self register; markdown allowed; multi-line fine.
  • Deliberately NOT fielded. No why / depends-on / status form — same design value as the planning skill's verifiable-outcome anchor over a fixed schema. A rigid schema, if ever wanted, belongs to a domain-driven toolkit one layer up, not the base. The "why" lives inside the prose.

Optional shared kit (any descendant may opt in):

  • Bold lead**Punchline.** opening the content; a scannable title before the elaboration. Earns its keep on longer entries.
  • Dated-update append**Update YYYY-MM-DD:** … to evolve an entry without losing the original. Archiving reuses this: an archived entry = original + **Archived YYYY-MM-DD** — reason.
  • Inline tags — lightweight square-brace markers riding on the prose line, e.g. [soon] (not YAML — markdown list items can't carry frontmatter).

4. Shared primitives

The reusable pieces every descendant draws on:

  1. Entry format — §3.
  2. Ledger (.meta/ledger.yaml) — §7.
  3. Bloat nudge — tiered count thresholds (<10 celebrate · 10+ heads-up · 15+ warn · 20+ firm > **Gate:**-style push) + a 7-day "been-a-while" reacclimation trigger when a count has sat in the 10+ band.
  4. Cadence-gated review — a hygiene sub-pass that fires only when the ledger says it's due; offered (Yes/No), never forced; silent when not due.
  5. List lifecycle — capture → triage → exits (graduate up / archive / demote-to-cold).
  6. Scope-routing — per-layer ownership; each layer owns its own stores.
  7. Capture — the /bookmarking skill (§6).
  8. Item-aging (anti-rot) (added 2026-06-08) — the per-item complement to the count-based bloat nudge (#3). #3 is anti-bloat (keep the pile small); #8 is anti-rot (keep the pile from silently going stale). Every entry is already date-stamped (§3), so the bookends / hygiene pass surface items left untouched past ~14 days (uniform threshold, 2026-06-08) as an informational signal — "these have aged; want a look?" — offered, never a forced review (the demand-free 'tism principle applied to hygiene itself). The action on an aged item varies by descendant (revive / promote / demote / graduate / archive / prune); the Done log's existing age-drain (§5.4) is the prototype. Re-touching an item (e.g. re-deferring, a **Update YYYY-MM-DD:**) updates its date and resets the clock — alive but never pushed. Net: every live list gets anti-bloat (#3) + anti-rot (#8) baked in.
    • Applies to: Deferred (§5.6), active bookmarks (§5.1), backburner (§5.3), session lessons + catalog (§5.2). The Done log already has it (§5.4 drain). The Archive (§5.5, pure sink) and Scratchpads are exempt.
    • Surfaced from the ledger, not by loading: for out-of-context stores the hygiene pass stamps a small per-list aged summary (§7) so the bookends can flag aged items without loading the store. The ~14d threshold is a first guess — bookmarked (yggdrasil/bookmarks.md) to revisit after real use.

5. The descendants

Each list/doc specced as a descendant of the base format (§3).

5.1 Active bookmarks

  • Kit: bold lead (optional) · dated-update (yes) · tags (soon).
  • Grouping: none — flat under a single # Bookmarks header.
  • Scope / load: per-layer <repo>/bookmarks.md; out-of-context, on-demand (revised 2026-06-08). Not auto-loaded into context — read only when explicitly reached for (asking "what's in bookmarks?", working a specific topic, or opting into a ledger-flagged review). Rationale: context economy — quick sessions never pay for bookmarks they don't need. Anti-rot does not depend on loading: the bookends flag count + aged items from the ledger stamps (§7), and the human opts in to reading the file. (Revises §5.1's original "in-context" classification; same out-of-context boundary §5.3/§5.5 already use.)
  • Hygiene: bloat nudge counting active + soon (kept — active bookmarks still want curation discipline, unlike the cold backburner which relaxes it; surfaced via the ledger now that the store is out-of-context); item-aging (§4 #8) surfaces stale bookmarks for revive / demote / prune; demote far-future → backburner. Cadence-gated, ledger-stamped.
  • Exits: graduate (task / convention / catalog) · archive · demote → backburner.
  • Capture: /bookmarking — scope-aware, default-active, optional soon hint.
  • Note: soon is active-only (means do-next priority; meaningless elsewhere). No "resolved" tag — resolution → prune → archive.

5.2 Knowledge stores — Session lessons + Design decisions catalog

Near-twins; treat the catalog like session lessons.

  • Shared: in-context · bold lead (yes) · dated-update (yes) · optional graduation marker · cadence-gated review + quantity nags, ledger-stamped · exits = graduate up (→ AGENTS/CLAUDE convention) / archive.
  • Session lessons — flat; at ## Session lessons. Migration: convert per-session blocks → individual dated entries.
  • Catalog — keeps topic ### grouping (the only descendant with subheads); at ## Design decisions catalog. Migration: add dates (currently undated). Review = staleness/graduation only; settled ≠ re-litigation.

5.3 Cold storage — Backburner

  • Out-of-context, separate file backburner.md per scope · flat · bold lead optional · no soon tag.
  • Hygiene: no tight count-nag (not loaded → bloat is cheap); a ~weekly review in the hygiene pass (revive / promote / archive), ledger-stamped. The review is the hygiene.
  • Fed by: demotion from active (primary) + optional direct /bookmarking "backburner this" hint.
  • Exits: revive → active · graduate → target · archive. Absorbs the old architectural bookmarks as plain entries.

5.4 Completion log — Done log

  • In-context · phase-grouped, two-tier · bold topic on granular entries · no dated-update · no tags.
  • Hygiene (self-bounding; no review, no nags): inner phase-compaction (closed phase → one-line summary, stays) + age-drain (granular bullets

    7d → archive, but keep the 5 most-recent entries regardless of age — a tunable floor so a dormant project still shows recent context). Ledger-stamped for the drain cadence. (Age-drain, and thus the floor, is Done-log-only — every other descendant reaches the archive via review/prune, not by aging out.)

  • Exits: age-drain → archive (granular bullets). Phase one-liners stay as the lightweight arc. No graduate exit — terminal for executed work.

5.5 Archive (the sink)

  • Terminal sink, not a triage list. Inherits the dated prose bullet; archived entry = original + **Archived YYYY-MM-DD** — [reason if meaningful] (aged-out Done entries need no reason; their own date tells it).
  • Home: per-scope archive/ directory, one file per sourcearchive/bookmarks.md, archive/session-lessons.md, archive/done-log.md, archive/catalog.md. A scope only gets files for the lists it actually has (the personal layer's archive/ would just hold bookmarks.md). (Directory named archive/ — renamed from history/ 2026-06-08 to match the Archive type name, so the type and its home are name-aligned.)
  • Index — archive/README.md (added 2026-06-08). A human-browsable manifest co-located in the directory: one line per archive file naming what it holds. Keeps archive/ self-documenting once it grows past the four list-archives, whose names self- explain only because they mirror the known lists — a stray hygiene.md would otherwise be off the map. Out-of-context; browsed on demand. Co-located (not in the ledger) per §7: it's human-browsable, so it co-locates with the files rather than consolidating into the machine ledger.
  • Standard header (added 2026-06-08). Every archive file — the four canonical and any added later — opens with the same header shape: a # Archive — <Source> title plus a line stating it's the append-only, out-of-context record for that source (never pruned; entries are dated prose bullets, original + **Archived YYYY-MM-DD** — reason). One shape so all archive docs read alike.
  • Adding a non-canonical archive file (the convention) (added 2026-06-08). When the hygiene pass drains a source that isn't one of the four list-archives (a scratchpad like the hygiene/drift store, or the research-reports cousin), it does three things: (1) names the file kebab-case after its source (hygiene.md); (2) gives it the standard header above; (3) adds its line to archive/README.md. This small recurring upkeep is what keeps the archive findable as it accretes arbitrary sources. Also stated as an AGENTS.md house-style line, and it travels to descendent scopes when the system is reproduced there (the deferred per-layer rollout).
  • Grouping: chronological append (optional year subheads only if it ever gets huge).
  • Context-load: out-of-context; read only on explicit request.
  • Hygiene: none on content — strictly append-only, never pruned/reviewed/nagged. (The only upkeep is creation-time: when a new archive file is first created, add its line to archive/README.md — see the convention below.)
  • Ledger: none (pure sink; sources own their drain cadence).
  • Fed by: the hygiene pass, whenever it prunes/drains any live list.
  • Per-source over combined: machine-read state consolidates (nothing browses it); human-browsable records separate by kind, for retrieval.

5.6 Plan-deferral — the Deferred section

(Added 2026-06-08.) Logically the hottest List — it would sit ahead of 5.1; placed last only to avoid renumbering. This is the descendant §2 pointed at ("hot (plan-deferral)") but never specced, because its home is a plan — so it belongs to the planning skill. Designed alongside that skill's §10 No-Placeholders carve-out; the two are the same artifact.

  • Home / load: a dedicated ## Deferred section inside the plan doc — the one parked-item store that's in-context, because heat ↔ context-load: the hottest items live with the active work they may promote into.
  • Kit: bold lead (optional) · dated-update (yes — re-deferring appends **Update YYYY-MM-DD:** and resets the age clock) · no soon tag (the section is already the do-ish-soon end).
  • Notation: the base dated-prose bullet carrying a revival trigger in the prose — encouraged, never required. The trigger is forward-looking ("what brings this back"): a dependency, an external event, a judgment call, or an honest soft one ("didn't feel like it today" / "no spoons for this right now"). The skill recommends a sharper trigger when none is given but never pushes (calm house style; demand-free per the 'tism principle).
  • What makes an item "tracked" (the No-Placeholders carve-out): placement in the Deferred section is the tracking — dated, in a known, reviewed place — not the trigger's quality. The planning skill's Self-Review enforces only this: every entry in the active task list is either fully spelled out or moved here. It catches the masquerade (a vague "TBD" posing as an actionable task), never the motivation for a deliberate deferral. A soft trigger is fine; an untracked TBD hiding in a task body is not.
  • Hygiene: bloat nudge (an in-context List — counts toward the 10/15/20 thresholds) · item-aging (§4 #8): hard-trigger deferrals resurface by condition (did the trigger fire?), soft-trigger ones by age (~14d), both as informational offers. Cadence-gated, ledger-stamped.
  • Exits: promote → active task (trigger fired / ready to detail — moves up into the task list; heats + loads) · demote → bookmarks.md (turns out bigger-than-this-plan or not really this plan's job — an offered, never forced "want to cool this out to bookmarks?" that cools + unloads; the pressure-valve for chronically re-deferred items) · prune → archive (decided against).
  • Flow position: the hot middle of project-bookmark → plan-deferral → task — promote moves an item one notch hotter (and into context), demote one notch cooler (and out of context).

6. Capture — the /bookmarking skill evolution

Already a live, auto-invocable skill (no disable-model-invocation; allowed-tools: [Read]). Evolve, don't replace. Capture-only — all maintenance lives in the hygiene pass (§8), keeping the auto-firing skill lean.

  • Strip the dead /bookmark command references (no such command exists).
  • allowed-tools: [Read, Glob, Grep] — Glob to locate the scope store, Grep to dedupe-check before appending. Write/Edit stay out → the mutation still prompts.
  • Add scope-awareness (capture to the right layer's store).
  • Add an optional backburner hint ("backburner this").
  • Grow the description to carry trigger synonyms per state ("backburner this," "park for someday," "soon," …) — load-bearing for conversational invocation.

7. The ledger — .meta/ledger.yaml

One per-scope, machine-maintained (bookend-written) file consolidating all the small date-stamps/counters. Governing principle: co-locate human-maintained metadata; consolidate machine-maintained metadata — the commands keep it in sync atomically, so the usual separate-file sync-seam objection doesn't apply.

skills:
  learning_new_skills: { last_run: 2026-06-01 }
lists:
  active_bookmarks: { last_pruned: 2026-06-05, count_band_since: 2026-06-04, count: 18, aged_count: 3 }
  backburner:       { last_reviewed: 2026-05-20, count: 6, aged_count: 6 }
  session_lessons:  { last_reviewed: 2026-06-04 }
  catalog:          { last_reviewed: 2026-06-04 }
  done_log:         { last_drained: 2026-06-05 }

Sectioned by concern (skills vs lists). Absorbs the existing .meta/learning-new-skills.yaml (retired into this file). The Archive needs no entry (pure sink).

Aged-summary stamps (added 2026-06-08). For out-of-context stores, the hygiene pass refreshes a small per-list count + aged_count (items untouched past the ~14d threshold, §4 #8) when it runs, so the bookends can surface bloat/aging signals from the ledger alone, without loading the store. Best-effort — the numbers are as fresh as the last hygiene pass; that's fine for an informational nudge. In-context lists (the Deferred section) don't need the stamp — they're read live anyway.


8. Command structure / wiring (flagged this session — own follow-on)

All the hygiene above bloats /save-progress. Proposal (2026-06-05): merge /sweep + /consistency-check into a single /hygiene-check (name TBD) holding all the housekeeping as distinct, cadence-gated steps, and move the AskUserQuestion "do you want to do this" gates out of /save-progress into it. /save-progress then offers /hygiene-check rather than embedding it; /good-morning surfaces what it produces. This supersedes the earlier "extract /sweep as its own sibling command" bookmark (bookends cluster) — going further, to one consolidated hygiene command.

Steps it would hold (each cadence-gated, ledger-stamped, offered):

  • active-bookmark prune + bloat-nudge
  • active → backburner demotion
  • backburner review
  • session-lessons review + nags
  • catalog review + nags
  • Done-log age-drain
  • consistency-check (drift between durable docs)

/good-morning bootup loading. On session start /good-morning must actively load the list state it needs. Today it reads current-plan.md + the manifest docs, but the manifest deliberately excludes bookmarks.md, so bookmarks are never surfaced. Under this system it reads .meta/ledger.yaml to learn which cadence-gated reviews are due (and flag them) and to surface the bookmark count + a high-count flag (bloat nudge) plus any items aged past the threshold (anti-rot, §4 #8) — all from the ledger stamps, without loading the stores themselves (revised 2026-06-08: bookmarks are now out-of-context; the human opts in to reading the file). It respects the context-load boundary: out-of-context stores (bookmarks.md, backburner.md, archive/) are not loaded — good-morning reads only their ledger stamps to flag a review or aged items as due. This also closes the standing gap where /good-morning advertises surfacing working/hygiene.md but has no step that reads it (bookends-cluster bookmark).

Design this command properly as its own follow-on — it's build-wiring, not part of the list type-system.


9. Migrations (for build)

  • Evolve /bookmarking (§6).
  • Stand up .meta/ledger.yaml; retire .meta/learning-new-skills.yaml into it.
  • Stand up backburner.md per scope; move architectural bookmarks into it.
  • Stand up per-scope archive/ files.
  • Flatten ## Session lessons blocks → dated entries.
  • Add dates to ## Design decisions catalog.
  • Wire the Done-log age-drain.
  • Nuke the ## Bookmarks to fold into bookmarks.md staging section (live capture supersedes it).
  • Build/merge /hygiene-check (§8).
  • Update /good-morning to load/surface list state on bootup — bookmarks count + high-count flag, ledger-driven review-due signals, the consistency-check scratchpad — while respecting the out-of-context boundary (don't load backburner.md / archive/; flag from ledger stamps only). See §8.

10. Open / deferred

  • soon flag — notation settled as [soon] (§3); only trivial build-time details remain (line placement, auto-clear on handling). Tiny convenience.
  • /hygiene-check command — §8; its own follow-on design.
  • Anti-rot threshold (~14d, §4 #8) — a first guess; revisit after real use (whether it nags too often or lets things rot; possibly tier by list heat). Bookmarked in yggdrasil/bookmarks.md (2026-06-08).
  • Scratchpad hygiene (deferred follow-on; bookmark "soon"). Scratchpads aren't parked items (delete-when-done), so their cleanliness mechanism is scoped out of this design and rides with the /hygiene-check build. Recorded lean: on resolution, delete the scratchpad — git history already preserves it, and resolved drift-checks aren't browse-worthy like completed work or retired ideas (vs. draining to archive/). Instances: consistency-check scratchpad (already partly covered by the bookends-cluster bookmark) · research reports (dated-file cousin).

11. Decision log

  • Retire "tier"; use Scope + State + context-load. It was pointed at two axes.
  • Base format = freeform dated prose, not fielded. Same value as the planning verifiable-outcome anchor; rigid schemas belong to domain-driven toolkits a layer up.
  • State as separate stores, not one flagged store — driven by context-economy (cold = separate file = not loaded). The only flag is soon.
  • Architectural bookmarks merged into backburner — they were just cold items; "architectural" was altitude, not a lifecycle.
  • Catalog + session lessons share one hygiene profile — settled ≠ frozen; periodic staleness/graduation review, not re-litigation.
  • Done log: incremental age-drain, not whole-doc rotation — rotation was described but never fired (doc at 903 lines); per-entry drain with a min-recent floor is strictly better.
  • Archive: per-source files in archive/, append-only, zero hygiene — separate human-browsable records by kind; consolidation logic applies only to machine-read state (the ledger).
  • Ledger: one consolidated per-scope file. The stamps are machine-written (by the bookend / hygiene commands), so one shared ledger is safe — there's no "human forgot to update it" sync seam. (The rule behind it: co-locate human-maintained metadata with its file; consolidate machine-maintained metadata — the ledger is the machine-maintained half.)
  • /bookmarking: evolve, capture-only — maintenance lives in the hygiene command; the skill stays lean and auto-invocable.
  • Tracked-deferral = the plan-deferral descendant (§5.6), homed in the plan doc (2026-06-08). What makes a deferral tracked is placement in the Deferred section, not the trigger's quality; the No-Placeholders check catches only a vague TBD masquerading as an active task, never the motivation for a deliberate deferral. Triggers are encouraged-not-required; soft ones ("didn't feel like it") are first-class.
  • Bookmarks → out-of-context, on-demand (§5.1) (2026-06-08, revises the 2026-06-05 in-context call). Context economy: quick sessions never load bookmarks. Anti-bloat (count-nudge, kept) and anti-rot (aging) both survive via the ledger — the bookends flag from stamps; the human opts in to reading. Also supersedes the 2026-06-03 single-doc "fold bookmarks into the plan" call — a separate bookmarks.md stands, no migration needed.
  • Per-item aging (§4 #8) added as anti-rot across all live lists (2026-06-08). The count-nudge is anti-bloat; aging is anti-rot — surface items untouched past ~14d, informationally, never a forced review. Near-zero cost (entries already dated). The Done-log drain is the prototype; the action varies per list.
  • Heat ↔ context-load alignment (2026-06-08). At the plan↔bookmark boundary, State and context-load move together: promoting heats-and-loads, demoting cools-and-unloads. The Deferred section is the one in-context parked store (hottest); bookmarks/backburner/archive are out-of-context. Demote-to-cooler is the bloat pressure-valve — offered, never forced.
  • Inform-don't-demand is a load-bearing design constraint, not just tone (2026-06-08). Triggers optional, reviews offered, the aging signal informational, demote an offer — all flow from the autonomy/PDA + variable-spoons accommodation now standing in personal/CLAUDE.md → "Design without a demand character." Captured as a 2026-06-08 session lesson.
  • Human-set config: lives inside the machine ledger — a sanctioned bend of §7 (2026-06-09). §7 says consolidate machine-maintained metadata, co-locate human-maintained metadata; the tunable knobs (bloat, reacclimation_days, aging_days, cadence_days, done_log) are human-set, so by the letter they'd co-locate, not sit in the ledger. We put them there anyway, in a demarcated config: section separate from the machine-written skills:/lists: stamps. Why: (1) the knobs are read together with the counters they govern (the bloat nudge compares count vs bloat; aging vs aging_days), so co-locating with those counters is the natural read; (2) single-source-at-runtime — both /hygiene-check and /good-morning read them from one file, so tuning is a one-field edit both honor, with no per-command drift. Safety (preserves §7's real concern): the hygiene restamp writes only skills:/lists:, never config: — the machine never clobbers the human's knobs, and there's no reverse "human forgot to update" sync seam. Rejected: a separate .meta/hygiene-config.yaml — keeps §7 unbent but splits the knobs from the counters they're compared against, and adds a second file to load. Chose cohesion. Propagation: recorded as an AGENTS.md tunable-knobs pointer (plan C4) and travels to descendent scopes — a sanctioned convention, not an accident. Surfaced by the Constraint-Guardian lens (the bend was real but unlogged); this entry logs it.