Accumulating-List Hygiene + Bookend Worktrees Plan

Goal: Build the accumulating-list-hygiene system for Yggdrasil and wire the session-bookend worktree lifecycle, as one cohesive build.

Approach: Three phases on a dependency chain. Phase A stands up the independent stores and migrations (ledger, backburner, history archive, in-plan list migrations, the /bookmarking evolution) — none of which touch the bookends. Phase B builds the /hygiene-check command that operates those stores. Phase C is the convergence: the combined /good-morning + /save-progress rewrites that fold in both the list-hygiene surfacing and the bookend worktree lifecycle, since both builds rewrite those same two commands.

Design source: working/2026-06-05-list-hygiene-design.md (primary) + the bookend-worktree design in working/current-plan.md → "Bookends — the active build (2026-06-08)" and "Git working-tree discipline — design-complete (2026-06-04)".

Scope: Yggdrasil only. The personal layer (bookmarks-only) and odin-codin (skeleton, no lists) are out of scope — personal-layer rollout is parked in ## Deferred.


Execution: isolation & resumption

Isolation. This plan is git-backed Yggdrasil work, so execute it on its own session branch under .worktrees/ (off main), merging back when the work checks out — never editing main directly without consent. This plan builds the bookend worktree lifecycle in Phase C, so until that lands the isolation is set up by hand, in two steps in order:

  • Step 0 — gitignore first (before any worktree exists): ensure .worktrees/ is in .gitignore and committed, so the bootstrap worktree never shows as untracked or gets committed into itself. (Normally a C1 concern, but it MUST precede the manual bootstrap — see C1, which just confirms it's committed.)
  • Step 1 — create the worktree: git worktree add .worktrees/session-2026-06-09 -b session-2026-06-09 HEAD (substitute today's date), then do all work inside it.

Resumption (the build spans /clear'd sessions). A fresh Claude reopening this plan mid-build learns "where am I" from disk state, not memory: every task's Confirm-by is an idempotent disk check, so a task is already done if its Confirm-by already passes, and re-running it is a no-op. To resume: walk from the top, skip any task whose Confirm-by already holds, do the first that doesn't. A phase is complete when all its tasks' Confirm-bys pass. The ## Progress checklist below is a quick where-am-I index, but a convenience layer only: a checked box claims the Confirm-by passed, yet the Confirm-by stays ground truth — re-verify on resume, since a box can drift from reality (e.g. work reverted in a discarded worktree). This is why every Confirm-by is written as a disk-state check, not "did I do it."


Phases & progress

  • Phase A — Independent migrations: A1–A7 (ledger, archive, backburner, in-plan migrations, /bookmarking, the ## Deferred section).
  • Phase B — The /hygiene-check command: B1–B4.
  • Phase C — The convergence: C1–C5 (/good-morning + /save-progress rewrites + worktree lifecycle + puppet fix + docs + final verification).

Progress checklist — a quick where-am-I index. A checked box claims the task's Confirm-by passed, but the Confirm-by stays ground truth (re-verify on resume — a box can drift if work was reverted/discarded). Check boxes as you go; commit them with the work.

  • A1 — Stand up backburner.md + migrate architectural bookmarks
  • A2 — Stand up the archive/ directory (+ README, verbatim header)
  • A3 — Stand up .meta/ledger.yaml (config + stamps; graduate notes; honest seed)
  • A4 — Flatten session lessons into dated entries (by pattern)
  • A5 — Date the catalog + delete the staging section
  • A6 — Evolve the /bookmarking skill
  • A7 — Stand up ## Deferred in current-plan.md (canonical Yggdrasil-wide store)
  • B1/hygiene-check skeleton + active-list curation steps
  • B2 — Knowledge-store review steps
  • B3 — Done-log hygiene step (+ one-time normalization)
  • B4 — Consistency-check step + retire /consistency-check
  • C1/good-morning rewrite (worktree lifecycle + ledger surfacing)
  • C2/save-progress rewrite (disposition + pin + offer /hygiene-check)
  • C3 — Puppet fix (decouple bootstrap from /good-morning)
  • C4 — Consolidated AGENTS.md / durable-docs update
  • C5 — Final verification pass (walk all Confirm-bys; reconcile the boxes)

Phase A — Independent migrations

Order note: A3 (ledger) runs after A1 and A2, so it can seed counts from stores that already exist. The others are order-independent.

Task A1: Stand up backburner.md + migrate architectural bookmarks

Touches: new backburner.md (Yggdrasil repo root); the ## Architectural bookmarks section in current-plan.md.

Create backburner.md as the per-scope cold-storage store (design §5.3: out-of-context, flat, optional bold lead, no soon tag). Open it with a short header naming it as Yggdrasil's backburner — cold/backburner items, reviewed on cadence, not loaded into context. Then move every entry from current-plan.md's ## Architectural bookmarks section (the five items: Agent teams · Self-hosted web UI / Hermes-style harness · LSB social-license conversation · Public release of Yggdrasil/Odin Codin' · creating-workflow-skills as the first "create things" skill) into it as dated prose bullets (- **YYYY-MM-DD** — …). Date each from git blame of its line (when it was added); if not readily determinable, stamp 2026-06-08 (the migration date). Preserve each item's full text. Finally, remove the ## Architectural bookmarks section from current-plan.md.

Done when: backburner.md exists holding all five architectural items as dated entries, and the ## Architectural bookmarks section is gone from current-plan.md. Confirm by: open backburner.md (five entries, all dated, text intact); grep current-plan.md for "Architectural bookmarks" (no section heading remains); eyeball that no item's content was dropped.

Task A2: Stand up the archive/ directory

Touches: new archive/ directory at Yggdrasil repo root, with four source files — archive/bookmarks.md, archive/session-lessons.md, archive/done-log.md, archive/catalog.md — plus the index archive/README.md.

Create the archive/ directory and the four per-source archive files (design §5.5: the append-only, out-of-context prune sinks — one file per source kind). Give each the standard archive header — this verbatim template (copy it literally so every archive file across every scope reads identically; <Source> / <source> are the only substitutions):

# Archive — <Source>

Append-only, out-of-context record of retired <source> items. Never pruned, reviewed, or
nagged. Entries are dated prose bullets, each the original + `**Archived YYYY-MM-DD** — reason`.

Bodies start empty — nothing has been pruned yet; these are the sinks Phase B's hygiene steps drain into. Also create archive/README.md, the index (design §5.5), seeded with one line per file describing what it holds (the four above). This verbatim header + the README line are the template the "adding a non-canonical archive file" convention copies when Phase B later adds archive/hygiene.md, and when descendent scopes stand up their own archive/.

Done when: archive/ holds the four source files (each with the standard header, empty body) and archive/README.md listing all four. Confirm by: list archive/ (four source files + README); open each source file (standard header, no entries yet); open README.md (four described entries).

Task A3: Stand up .meta/ledger.yaml

Touches: new .meta/ledger.yaml; retire .meta/learning-new-skills.yaml (leaving .meta/workflow.yaml untouched — it's the layer-identity manifest, not a hygiene stamp, so the ledger deliberately does not absorb it); the ## Session lessons section in current-plan.md (to receive the retired notes — see below).

Create .meta/ledger.yaml as the per-scope ledger (design §7), sectioned into config: (human-set, tunable knobs), skills:, and lists: (both machine-written stamps). Carry the existing last_run value out of .meta/learning-new-skills.yaml into skills.learning_new_skills.last_run. Before deleting it, graduate its notes: block (first-run findings: disable-model-invocation, the Stop-hook prompt-eval pattern, terminalSequence for Windows notifications, the skill-creator 500-line threshold) into the ## Session lessons list as a dated 2026-05-27 entry — they're session-lesson-shaped and mostly already echoed there, so merge rather than duplicate (A4 then flattens them with the rest). Then delete .meta/learning-new-skills.yaml (last_run absorbed, notes graduated — nothing lost). Seed the lists: section with one entry per existing Yggdrasil list — active_bookmarks, backburner, session_lessons, catalog, done_log — using the stamp shape from §7. Concrete seeding:

  • config: (the tunable hygiene knobs, read at runtime by /hygiene-check and /good-morning — see B1): bloat: { heads_up: 10, warn: 15, firm: 20 } · reacclimation_days: 7 · aging_days: 14 · cadence_days: { backburner: 7, session_lessons: 7, catalog: 7, done_drain: 7 } · done_log: { drain_age_days: 7, min_recent: 5 }. Seed each value with an inline YAML comment marking it a tunable first-guess, so the provenance lives in the file the future tuner opens — e.g. aging_days: 14 # first guess 2026-06-09; tunable, see bookmarks. (The aging_days value is what the aged_count seeds below key off; Phase B's ledger-restamp must preserve this config: section — see B1.)
  • active_bookmarks: count = the live count of entries in bookmarks.md, computed now — do not copy the design's example 18; it's ~39 today, already in the 20+ band. aged_count = entries older than config.aging_days. last_pruned = today. For count_band_since we genuinely can't reconstruct when the pile crossed 10+, so set it to today as an init — but B1 must treat an init-stamped count_band_since whose count is already in the 20+ band as immediately reacclimation-eligible, so the seed date doesn't suppress the "been a while" nudge (Skeptic-lens finding).
  • backburner: count: 5 (from A1); aged_count per the same ~14d rule; last_reviewed: 2026-06-08.
  • session_lessons, catalog: last_reviewed: 2026-06-08.
  • done_log: last_drained: 2026-06-08.

Done when: .meta/ledger.yaml exists with all three sections populated (config seeded with the tunable knobs; skills/lists stamped), the prior last_run is preserved under skills.learning_new_skills, and .meta/learning-new-skills.yaml is deleted. Confirm by: open ledger.yaml (all three sections; config values carry their inline-comment provenance); git status shows .meta/learning-new-skills.yaml deleted and .meta/workflow.yaml untouched; confirm the carried last_run matches the old file's value, the retired notes: now appear as a 2026-05-27 session-lessons entry, and active_bookmarks.count is the live count (~39), not the example 18.

Task A4: Flatten session lessons into dated entries

Touches: all ## Session lessons (from … session) blocks in current-plan.md — match them by pattern, not the frozen list of dates. The build spans days, so a block like (from 2026-06-09 session) may accrete after this plan was written; flatten whatever exists at run time, plus the 2026-05-27 notes A3 graduates in.

Convert the per-session blocks into a single ## Session lessons section holding individual dated prose bullets (design §5.2: flat, bold lead yes, dated-update yes). For every lesson bullet under each dated block, prefix it with that block's session date in the base format (- **YYYY-MM-DD** — …) and move it under the one ## Session lessons header, preserving chronological order and each lesson's full text (including its existing bold lead). Remove the now-empty per-session block sub-headers. No lesson content is dropped — this is a reshape, not a prune.

Done when: current-plan.md has one flat ## Session lessons section of dated entries, every prior lesson present, and all per-session block headers are gone (however many there were). Confirm by: grep for any remaining (from … session) header — none should match (this catches a block that accreted after planning, which a naive before/after count would miss); confirm a single ## Session lessons header remains; spot-read a few entries for intact text + correct dates.

Task A5: Date the catalog + delete the staging section

Touches: the ## Design decisions catalog section and the empty ## Bookmarks to fold into bookmarks.md section, both in current-plan.md.

Add a date to each catalog entry (design §5.2: the catalog keeps its ### topic grouping — the only descendant with subheads — so date at the ###-topic level). Derive each date from the decision date stated in the entry's own text where present (many read "reframed 2026-05-29," "sharpened 2026-06-03," etc.); otherwise from git blame; otherwise stamp 2026-06-08 with no false precision. Date every ### entry present at run time (including any added since this plan was written). Keep the topic grouping and all content intact — this adds dates only, it does not re-litigate settled entries. Separately, delete the ## Bookmarks to fold into bookmarks.md staging section (it's empty and live capture via /bookmarking supersedes it).

Done when: every catalog topic entry carries a date, the topic grouping is unchanged, and the staging section is gone. Confirm by: scan the catalog for any undated ### entry (none); grep current-plan.md for "Bookmarks to fold into" (absent); confirm no catalog content changed beyond added dates.

Task A6: Evolve the /bookmarking skill

Touches: skills/bookmarking/SKILL.md.

Evolve /bookmarking per design §6 — capture-only (all maintenance lives in /hygiene-check, built in Phase B), keeping the auto-firing skill lean:

  • Set allowed-tools: [Read, Glob, Grep] (Glob to locate the scope's store, Grep to dedupe-check before appending; Write/Edit stay out so the mutation still prompts).
  • Add scope-awareness: capture to the right layer's store (Yggdrasil → bookmarks.md; personal → personal/bookmarks.md; an adopted project → its store), detected from context rather than hardcoded.
  • Add an optional backburner hint — "backburner this" / "park for someday" captures straight to backburner.md instead of active bookmarks.
  • Strip any dead /bookmark command references (no such command exists).
  • Grow the description to carry trigger synonyms ("backburner this," "park for someday," "soon," …) so conversational invocation fires reliably.

Done when: skills/bookmarking/SKILL.md reflects all of the above and remains capture-only (no pruning/triage logic added). Confirm by: read the skill — frontmatter shows [Read, Glob, Grep]; description carries the trigger synonyms; scope-awareness and the backburner hint are described; no /bookmark references remain; no maintenance logic crept in.

Task A7: Stand up the ## Deferred section in current-plan.md

Touches: current-plan.md (new ## Deferred section).

The §5.6 Deferred section is the in-context hot parked-item store, and good-morning (C1) surfaces ripe deferrals from it — but current-plan.md has no ## Deferred section yet (only specific sub-plans like this one do). Stand one up as the canonical Yggdrasil-wide Deferred store that C1 scans. Create the ## Deferred section in the §5.6 shape (dated prose bullets with optional revival triggers); seed it with any clearly-deferred items easy to lift in, otherwise leave it lightly populated. Broad consolidation of the scattered "Open:" bits across current-plan.md's design sections is NOT in scope here — that's a later cleanup; this task just establishes the canonical section so C1 has a real place to read.

(Two-level note, self-contained: sub-plans like this list-hygiene plan keep their own ## Deferred for plan-scoped deferrals; those merge up to current-plan.md's section — or to bookmarks.md — when the sub-plan resolves. Whether good-morning ALSO scans the active sub-plan's Deferred mid-build is a deliberately-deferred v2 question; v1 = good-morning scans current-plan.md's section only.)

Done when: current-plan.md has a ## Deferred section in the §5.6 dated-bullet shape. Confirm by: grep current-plan.md for ## Deferred (heading exists); the section follows the dated-prose-bullet format.


Phase B — the /hygiene-check command

/hygiene-check is the standalone command that operates the stores Phase A stood up (design §8). It merges what would have been /sweep with /consistency-check into one command holding each housekeeping concern as a distinct, cadence-gated, offered step. The bookends don't embed it — /save-progress offers it and /good-morning surfaces what it produced (that wiring is Phase C).

The shared step pattern — every step below follows this:

  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.
  2. Offer — if due, present an AskUserQuestion Yes/No to run it (these are the gates that used to live inline in /save-progress). Decline = skip, no change.
  3. Act — do the step's work (review / prune / drain / nudge).
  4. Drain — pruned/retired items append to their archive/<source>.md (with the standard header + a README line per the §5.5 convention if the file is new), never deleted outright.
  5. Restamp — update the ledger: the step's last_* date, plus a refreshed count + aged_count for the touched store (so /good-morning surfaces bloat/aging from stamps without loading the store). The restamp writes only skills:/lists: — it never touches the human-set config: section.

Frontmatter: disable-model-invocation: true, allowed-tools: [Read, Glob, Grep] (reads pre-approved; the Yes/No offers authorize each mutation — whether to also pre-approve the store writes, to avoid a second prompt after the offer, is a build-time refinement).

Task B1: /hygiene-check skeleton + active-list curation steps

Touches: new commands/hygiene-check.md; reads/writes .meta/ledger.yaml, bookmarks.md, backburner.md, archive/.

Create commands/hygiene-check.md with the frontmatter and the shared step pattern above as the command's spine (this task establishes the machinery B2–B4 reuse), then implement the three active-list steps:

  • Bookmark prune + bloat-nudge. Count bookmarks.md entries; compare against config.bloat (<10 celebrate · 10+ heads-up · 15+ warn · 20+ firm > **Gate:**-style push to prune — softening of this 20+ vocabulary is parked in ## Deferred). If the count has sat in the 10+ band since count_band_since for ≥ config.reacclimation_days, add the "been a while" reacclimation note — and treat an init-stamped count_band_since whose count is already in the 20+ band as immediately eligible (the seed date must not suppress the nudge; per A3). Offer a prune pass — review entries, retire resolved/dead ones to archive/bookmarks.md. Restamp active_bookmarks (count, aged_count, last_pruned, count_band_since).
  • Active → backburner demotion. Offer moving cold / far-future active bookmarks to backburner.md — the pressure valve for chronically-deferred items. Restamp both stores' counts.
  • Backburner review. Cadence-gated on config.cadence_days.backburner. Offer a walk of backburner.md: revive → active bookmark · promote → a Target · archive. (Backburner is bookmark-lineage — cold bookmarks — so its archive exit drains to archive/bookmarks.md, not a separate archive/backburner.md. Settled design call.) Restamp backburner.last_reviewed + counts.

Done when: commands/hygiene-check.md exists with the shared pattern + the three active-list steps; a run cadence-gates each, offers via AskUserQuestion, drains accepted prunes to archive/, and restamps the ledger without touching config. Confirm by: invoke /hygiene-check against the current stores — a not-due step stays silent; a due step prompts; accepting a bookmark prune drains to archive/bookmarks.md and updates the active_bookmarks stamps while config is untouched. Present the before/after ledger diff.

Task B2: Knowledge-store review steps

Touches: commands/hygiene-check.md; the ## Session lessons + ## Design decisions catalog sections in current-plan.md; archive/session-lessons.md, archive/catalog.md.

Add two more steps (each following the shared pattern):

  • Session-lessons review + nags. Cadence-gated on config.cadence_days.session_lessons. Offer a staleness/graduation pass over the flat ## Session lessons list (from A4): graduate a proven lesson up to an AGENTS/CLAUDE convention, or archive a stale one to archive/session-lessons.md. Quantity nag if the list runs long. Restamp session_lessons.last_reviewed + count/aged.
  • Catalog review + nags. Cadence-gated on config.cadence_days.catalog. Offer a staleness/graduation pass over ## Design decisions catalog (dated in A5) — staleness and graduation only; settled ≠ re-litigation (§5.2). Archive superseded entries to archive/catalog.md. Restamp catalog.last_reviewed.

Done when: both steps run end-to-end under the shared pattern. Confirm by: trigger each with its cadence elapsed — the offer fires, a graduation moves an entry to the right Target, an archive drains to the right archive/ file, the ledger restamps.

Task B3: Done-log hygiene step

Touches: commands/hygiene-check.md; the ### Done / Done-log section in current-plan.md; archive/done-log.md.

Add the Done-log step (self-bounding — no review, no nags, per §5.4):

  • One-time normalization (setup — runs once, NOT cadence-gated; the two recurring steps below are the cadence-gated hygiene). Reshape the existing ### Done section into the §5.4 two-tier shape — closed phases collapsed to one-line summaries, active-phase work as individual dated granular bullets. The current section is close, so this is light. Where an entry is too terse or truncated to reshape confidently, leave it as-is and flag it passively (a brief (couldn't confidently reshape — left in place) marker) rather than blocking to interrogate the user mid-step. They can fill any in later if they choose; the step never stalls waiting on a human (no-demand). Once done, this normalization is a no-op.
  • Phase-compaction (recurring): collapse each newly-closed phase's granular bullets into a one-line summary that stays in place (the lightweight arc).
  • Age-drain (recurring): move granular Done bullets older than config.done_log.drain_age_days to archive/done-log.md, but keep the config.done_log.min_recent most-recent regardless of age (the floor so a dormant project still shows recent context).
  • Cadence-gated on config.cadence_days.done_drain; restamp done_log.last_drained.

Done when: the ### Done section is normalized to the two-tier shape, and the step thereafter compacts closed phases and drains aged granular bullets (respecting the min-recent floor) to archive/done-log.md, restamping last_drained. Confirm by: run it against the Done log — bullets older than the drain age (beyond the most-recent floor) moved to archive/done-log.md, the newest kept, closed phases compacted, done_log.last_drained updated.

Task B4: Consistency-check step + retire /consistency-check

Touches: commands/hygiene-check.md; working/hygiene.md (the scratchpad); new archive/hygiene.md; delete commands/consistency-check.md; AGENTS.md (the one-line commands-row delete).

Port the existing /consistency-check drift-detection logic (from commands/consistency-check.md) in as a /hygiene-check step. It is event-driven — run after durable-doc changes, not time-cadence-gated — so it gets no cadence_days entry; offer it when the session has touched durable docs (or on request). It writes outstanding drift to working/hygiene.md (the hygiene/drift scratchpad — renamed from consistency-check.md to the more generic hygiene.md, since it's now /hygiene-check's output, not a standalone command's; rename the existing file as part of this task).

  • Scratchpad drain — the first use of the §5.5 "non-canonical archive file" convention. When resolved runs accumulate, append them to archive/hygiene.mdcreating that file with the standard archive header and adding its archive/README.md line per the convention — then remove the resolved runs from the working scratchpad.
  • One-off: drain the existing resolved runs currently in working/hygiene.md into archive/hygiene.md, leaving only genuinely-open items in the scratchpad.
  • Retire /consistency-check: delete commands/consistency-check.md (its logic now lives in the step) and do the one-line AGENTS.md commands-row delete here (remove /consistency-check from the commands table), so AGENTS.md never advertises a command that no longer exists. (Only this factual row-delete moves up to B4; the richer AGENTS.md house-style additions still land in C4.)

Done when: the consistency-check step runs within /hygiene-check (event-driven, writes the scratchpad); resolved runs (including the existing backlog) drain to archive/hygiene.md, created per the convention; commands/consistency-check.md is deleted and AGENTS.md's commands row no longer lists it. Confirm by: run the step (drift lands in working/hygiene.md); confirm the existing resolved runs moved to archive/hygiene.md; confirm archive/README.md gained the hygiene.md line and the file carries the standard header; confirm commands/consistency-check.md is gone and AGENTS.md's commands row shows no /consistency-check.


Phase C — the convergence

Where the two designs merge: both the list-hygiene surfacing and the bookend worktree lifecycle land in the same two command rewrites. Full worktree mechanics live in the bookend design (current-plan.md → "Bookends — the active build (2026-06-08)" and "Git working-tree discipline — design-complete") — the tasks below name the behaviors and pull the fine step-by-step from there rather than re-deriving it. Order note: C3 (puppet) depends on C1 (its trigger is good-morning gaining worktree creation).

Task C1: /good-morning rewrite — the full startup sequence

Touches: commands/good-morning.md; .gitignore; reads .meta/ledger.yaml, current-plan.md, working/hygiene.md.

Prerequisite: .worktrees/ in .gitignore and committed — done at Execution Step 0; this task just confirms it's committed as a permanent entry (good-morning creates worktrees there on every run).

Rewrite good-morning into the startup sequence below — it composes the original orient-and-stand-ready behavior with the new worktree lifecycle + ledger surfacing. State it as git-by-default + worktree-always (not the planning skill's softer "or at least a branch" floor). The character shifts from "only reads and orients" → "reads, orients, and sets up / cleans the workspace" — but it still does not execute the plan's work. (This is the onboarding/bootstrap/startup chokepoint — the full sequence lives here.)

1. Parse & capture (entry). Parse the invocation: briefing preference + any loose note. Safe-capture a loose note first — if the user sat down to drop an idea, bookmark it immediately so it never rides only in conversation.

2. Locate & resume the session worktree (precedes orient — the pinned handoff can live on the session branch). git worktree list to detect session-* worktrees (branch-prefix detection; reserve xrepo-* and native worktree-* as not session-resumes — no active cross-repo logic, deferred). If a kept session-* exists, resume it (cd in) — that's where last session's pinned handoff lives if it was "kept." More than one → disambiguate via AskUserQuestion listing each with a derived per-session summary (from recent commits / the branch checkpoint) + last-commit date, plus "start fresh." If none exists, the handoff is on main and you create fresh in step 4.

3. Orient. Read current-plan.md from the resumed location (the freshest pinned handoff), in full. Explore what it points to — references, the active skill(s), source paths. Skim durable docs from the manifest if the session will touch architecture.

4. Finish workspace setup. Now that you've oriented: worktree-always — if step 2 found none, create a session-YYYY-MM-DD worktree under .worktrees/ branched from local HEAD (so worktree.baseRef is moot, no-remote-safe); "start fresh" while today's name exists → collision suffix (-2, -3). Necessity-only cleanup (offered, not silent): reuse a same-day empty silently; nuke an empty stale-dated worktree (clean, no commits beyond base) and tell the user; clear a broken/half-made one. cd settled into the worktree; target absolute worktree paths thereafter (raw git doesn't auto-relocate).

5. Surface — all from ledger stamps + in-context; never load the out-of-context stores (bookmarks.md / backburner.md / archive/):

  • Ledger (.meta/ledger.yaml): bookmark count + high-count flag (bloat bands from config.bloat), items aged past config.aging_days, and which cadence-gated reviews are due.
  • working/hygiene.md open items, if any (the hygiene/drift scratchpad — closes the standing bug where good-morning advertised surfacing it but had no step that read it).
  • Ripe deferrals from current-plan.md's ## Deferred (in-context, so reading it is fine): hard-trigger fired (by condition) or soft-trigger aged past config.aging_days (by age) — an informational offer to pick it up, never forced (§5.6). (A7 stands up that section; v1 scans current-plan.md's only — sub-plan Deferred scanning is a deferred v2.)
  • Active-build progress: if a sub-plan is in flight (a plan with unchecked ## Progress boxes), surface "you're at Task X of plan Y; next is …" — making good-morning the resume point for a /clear'd mid-build.

6. Brief & stand ready. Offer the briefing (unless declined on entry). State where you're picking up + the immediate next step; stand ready. No work execution.

Done when: good-morning runs the full sequence — locate/resume (or create) the session worktree with disambiguation + necessity-cleanup, orient from the freshest handoff, surface the four signal classes (ledger flags · working/hygiene.md open items · ripe deferrals · active-build progress) while respecting the out-of-context boundary, and stop at orientation without executing the plan's work; .worktrees/ is gitignored. Confirm by: run /good-morning in a clean repo — it creates .worktrees/session-<today> off main, orients, surfaces the four signal classes, and stops (git status clean — worktree ignored). Re-run with a kept session worktree → resumes it and reads the handoff from there; with two → disambiguation w/ summaries; with a stale empty → nuke + notify.

Task C2: /save-progress rewrite — disposition + pin + offer /hygiene-check

Touches: commands/save-progress.md.

Pin + disposition (the bookend half — full mechanics in the design's §(b)/(c)):

  • Pin the handoff (checkpoint write+commit) — self-housekeeping, auto-commit, no prompt — written once, to wherever /good-morning reads next (keep→branch, merge→main, discard→breadcrumb on main).
  • Disposition menuAskUserQuestion merge / keep / discard, always gated (deliberately outside the auto-commit exception), recommended option pre-pointed by the drafted checkpoint's "Next step" shape (verification read off it, not asked cold). All git via git -C / absolute paths, never cd:
    • merge = merge the session branch into main, re-confirm it still checks out on the combined state, remove the worktree, delete the branch.
    • keep = leave branch + worktree, frictionless; next /good-morning resumes.
    • discard = "Are you sure?" AskUserQuestion → write a fresh "abandoned X" breadcrumb to main's current-plan.md, remove the worktree, force-delete the branch (recoverable via reflog + breadcrumb).
  • Preserve save-progress's existing step 1(a) in-flight-design materialization guardrail through the rewrite.

Offer /hygiene-check (the list-hygiene half — design §8): shed the inline sweep; instead offer /hygiene-check (the AskUserQuestion gates moved there). save-progress offers it, never embeds it.

Done when: save-progress pins the checkpoint (auto), offers the gated merge/keep/discard disposition (pre-pointed by the checkpoint), offers /hygiene-check, and preserves step 1(a); the old inline sweep is gone. Confirm by: run /save-progress in a session worktree — the pin auto-commits to the right place; the disposition menu appears with the recommended option pre-pointed; merge cleanly combines + re-confirms + removes the worktree; keep leaves it; discard confirms + breadcrumbs; /hygiene-check is offered (not embedded); step 1(a) still fires.

Task C3: Puppet fix — decouple its bootstrap from /good-morning

Touches: commands/puppet.md. (Depends on C1.)

Per the [priority] bookmark, now due: puppet step 2 currently reads commands/good-morning.md as text and follows it — which, after C1, would make puppet inherit worktree-creation + a Yggdrasil pin, violating its own read-only gate ("No Yggdrasil checkpoint on the way in") and spinning a worktree during a read-only foreign adoption.

Replace the delegate-to-good-morning bootstrap with an inline minimal bootstrap keeping only what puppet needs (Brad wants the full Yggdrasil context bootstrap kept so puppet sessions ride the real toolkit and get logged):

  • Load working/current-plan.md (Yggdrasil's plan, for context/logging).
  • Skip the briefing; orient and stand ready.
  • Explicitly NO worktree creation and NO pin/checkpoint.
  • Do not inherit good-morning's ledger-surfacing/worktree machinery — puppet is a read-only foreign adoption.

Done when: puppet step 2 does its own inline bootstrap (load plan, skip briefing, orient — no worktree, no pin) and no longer reads/follows commands/good-morning.md. Confirm by: read puppet.md — step 2 is self-contained, references no good-morning delegation, creates no worktree and no pin; the read-only gate and "No Yggdrasil checkpoint" gate remain intact.

Task C4: Consolidated AGENTS.md / durable-docs update

Touches: AGENTS.md; .meta/durable-docs.md (confirmed to exist — reconcile it); personal/CLAUDE.md (the commit-convention cross-ref).

Land the house-style / convention entries this build accumulated (collected here to avoid scattering them across earlier tasks):

  • Archive-file convention (§5.5): kebab-name after source · standard header · archive/README.md line, whenever a non-canonical archive file is added (travels to descendent scopes).
  • ledger.config pointer: "the hygiene knobs — bloat / aging / cadence — are tunable in .meta/ledger.yamlconfig."
  • Disposition-is-prompted (Loose End 3): worktree disposition (merge/keep/discard) is always human-gated, outside the self-housekeeping auto-commit exception.
  • "commit" git-op-vs-convention house-style (the deferred bookmark): bare "commit" = the git op; lean on pin / disposition in worktree mechanics; write "the commit convention" when meaning the convention. Cross-ref personal/CLAUDE.md's commit convention.
  • Bloat-nudge concept reference (thresholds live in ledger.config).
  • Commands-row: confirm /consistency-check is already gone (deleted in B4) and add /hygiene-check to the commands table.
  • Worktree naming/location convention (session-* / reserved xrepo-*, .worktrees/, git-by-default) if not already captured.

Done when: AGENTS.md carries all the above; the commands row shows /hygiene-check and no /consistency-check; durable-docs references reconciled. Confirm by: read AGENTS.md (each convention present; commands row correct); then run /hygiene-check's consistency-check step — it flags no new drift against the durable docs (closing the loop: the build's own docs are now self-consistent).

Task C5: Final verification pass

Touches: all build artifacts (read-only verification); the ## Progress checklist.

The closing sign-off that the build is actually complete and coherent — catches a checkbox that lies and any cross-task inconsistency the per-task Confirm-bys miss individually:

  • Walk every task's Confirm-by against disk (A1–A7, B1–B4, C1–C4). Each must pass; a box that's checked but whose Confirm-by fails is the exact failure this catches — re-open that task. Reconcile the ## Progress boxes to the real results.
  • Re-run the Self-Review consistency check on the built artifacts (not the plan text): the config.* keys the commands read exist in the ledger; the archive/ files the steps drain to exist with the standard header; /hygiene-check and /good-morning reference the same working/hygiene.md and ledger fields; no dangling cross-reference between commands, ledger, and stores.
  • Plan-scoped cousin of the Phase-12 full-stack capstone; candidate to graduate into the planning skill as a standard closing step (captured in the planning-skill-improvements bookmark).

Done when: every task's Confirm-by passes against disk, every ## Progress box is honest, and the cross-artifact consistency check is clean. Confirm by: the walk yields a clean bill — no failing Confirm-by, no mismatched checkbox, no dangling cross-reference; if anything fails, it names the task to re-open.


Deferred

  • 2026-06-08 [priority]Roll the hygiene system out to the personal layer. Stand up the personal layer's mini version: a personal/.meta/ledger.yaml and bookmark hygiene for personal/bookmarks.md (no session-lessons/catalog/done-log there — it has none). Trigger: once this plan is written and worked through — it should be quick and easy on the back of the Yggdrasil build, which is why it's [priority] rather than open-ended. Pairs with the bookmarked "uniform repo-maintenance routine across all layer-repos" thread.
  • 2026-06-09Cross-repo (xrepo-*) worktree disposition — deferred to the uniform per-layer maintenance thread. Decision (Phase C scoping): this plan fully handles same-repo session-* worktrees; it reserves the xrepo-* prefix in the naming/detection scheme (so detection stays forward-correct — session-* are ours-to-resume, xrepo-* and native worktree-* are not) but builds no active cross-repo detection or disposition.
    • Why deferred: nothing in the current or planned system actually creates xrepo-* worktrees yet — cross-repo edits today land directly on the other repos' main branches (as this session's personal/ / odin-codin/ branch-renames did). So any cross-repo detection/warning logic would be inert until a reach-in mechanism exists. And the genuinely-hard part — disposing of worktrees across N repos at session end — is a design effort of its own: the parked "uniform repo-maintenance routine across all layer-repos" thread (bookmarks.md), which sprang from this same Loose End 2.
    • Intended usage in the hypothetical future world (recorded so the design isn't lost): a session has a primary repo with its session-* worktree; when work must touch another layer-repo, instead of editing that repo's main directly, the system creates an xrepo-* worktree in it — isolating the reach-in the same way the primary work is isolated. The prefix distinguishes "a reach-in worktree created from another repo's session" from "this repo's own primary session," because the two carry different disposition semantics. At session end, disposition becomes multi-repo: /save-progress (or the uniform-maintenance routine) walks each touched repo and offers merge/keep/discard per repo, not just the primary's. The pre-reach-in warning is the safety net: a later /good-morning that detects an unclosed xrepo-* worktree in some repo warns "repo X has an unclosed Claude-managed worktree — load it as main and close it out first," nudging the user to handle that repo in its own primary session rather than leaving orphaned cross-repo state.
    • Trigger: taken up with the uniform per-layer maintenance routine thread. Cross-ref: bookmarks.md (uniform-maintenance routine) + the bookend design's Loose End 2.
  • 2026-06-09/hygiene-check UX: prompt-grouping + softer 20+ nudge (lens-audit follow-on). Two calm-house-style refinements surfaced by the lens audit, parked together because both make the hygiene UX gentler:
    • Prompt-grouping. On a day many cadences are due, /hygiene-check can fire up to ~7 sequential Yes/No gates — each "offered," but the aggregate carries a demand character (worst on the low-spoon "been away" return). Idea: open with a single roll-up — "N things are due: all / pick one / none" — with a first-class "just one thing" path, so the default low-spoon route is one decision, not seven. (Brad: "maybe I'll nest some into groups" — not now.)
    • Softer 20+ nudge. The 20+ band uses > **Gate:**-style pressure-language (design §4 #3 + B1) — the one spot the calm/no-demand house style slips, pointed at the lowest-stakes pile. Soften to salient-but-calm: keep it visually prominent, drop the gate/blocking vocabulary.
    • Trigger: when Brad wants to tune the hygiene UX (soft — no spoons pressure). Source: lens audit, User-Advocate findings.