meta-dream-tree
Memory consolidation for the CURRENT project's knowledge tree, the way a brain reorganizes during
sleep. bitranox:meta-self-improve is the fast per-turn CAPTURE; this is the periodic batch
CONSOLIDATION: dedup, merge, re-level (PLACEMENT), normalize, prune - so memory gets smaller and
sharper, not bigger. If a pass would grow the store, it is wrong.
REQUIRED BACKGROUND: the storage spec (trees/anchors, store grammar, trigger-first hooks,
framed bodies, engine commands + fail-loud contract) is bitranox:meta-self-improve ->
references/memory-backend.md - Read it BEFORE the first engine call. This skill stays WITHIN the
current tree; cross-tree work is bitranox:meta-dream-crosstree.
Reference files
| Topic |
File |
| The SHARED DREAM CORE - scope ladder, mode knob, capture-first, backup+manifest, dedup semantics, THE routing prompt, verification contract, tier note (single source for nap/project/global) |
references/dream-core.md |
| The behavioral pass catalog - removal policy, contradiction/override, CLAUDE.md reconciliation, skill/hook pointing, filler words, model review, skill-gap, gate-coverage, durability/squash, backup reminder |
references/dream-passes.md |
| Acceptance harness - planted-fixture test that proves a dream run works |
tests/README-acceptance.md |
Tools shipped here, runnable outside a dream run too: dream_state.py (mode + due state),
store_manifest.py (backup and verify), dedup_scan.py (candidate pairs), statusrot.py (pointer
lines still asserting a STATUS that shipped and was never updated; a hit is a CANDIDATE to check
against its owner, and only a SELF-CONTRADICTION - a slug saying one thing under a hook saying
another - is a defect on its own and sets exit 1; its UNEXAMINED list is split into RE-SURFACED,
WRITTEN SINCE the sweep and NEVER CHECKED, and only the last is a backlog of unchecked claims -
read the count for that group, never the total; clear records an adjudication, which is what
stops an entry being re-reported until its hook changes, and takes
--slug <s> REPEATABLY - a bare clear certifies every candidate in scope, so name the ones you
actually checked, and a slug that is not a flagged candidate is refused rather than recorded) and
factedit.py (reword a fact's hook or body by recomposing it through memory_engine.py, since a
Write or Edit on a pointer block or a body is denied by the store-edit guard; show reports the
stored type, an amend PRESERVES it, and --type is the one deliberate way to re-classify, a
PINNED fact included - amend-pinned carries --type and is the only route to a pinned fact's
kind, since add refuses a pinned entry outright). The
last two moved here from a personal toolbox; the PreToolUse nudge names them on the chores they
answer, so they surface without this file being open.
Use the Read tool to load a referenced file when running its passes.
Mode
Read the mode first per references/dream-core.md (propose / auto / off - the knob semantics live
ONLY there).
When to run
Nudged when due (SessionStart), around compaction (PreCompact salvages, you dream), or manual
("dream", "/dream-tree"). Check dream_state.py due (the script lives in THIS skill's dir; launch
recipe in references/dream-core.md "Script homes"). A MANUAL dream ALWAYS captures -
not-due never suppresses capture. An absent store is the trigger to CREATE one (the first
engine add bootstraps it), never a reason to skip; routing a learning only into a CLAUDE.md is
NOT capture. Verify "nothing durable" - never assume it.
Procedure
Create one todo per step. Every engine call follows the fail-loud contract (strict env, require
the success line, abort-and-show on a miss).
0a. Deterministic scaffold + tree-wide integrity (scripts, no model).
memory_engine.py heal --proj "<cwd>" (via run-python.sh): creates every missing marker
CLAUDE.md + CLAUDE.local.md pointer block from the project up to the anchor, plus the central
store; normalizes drifted grammar. Require healed N file(s) across M level(s). heal is
CHAIN-scoped and only normalizes grammar, so FOLLOW it with
reconcile_memory_index.py --check-tree "<cwd>" (home: <plugin>/skills/meta-self-improve/) to
surface any cross-sibling DUPLICATE pointer / orphan / dangling body BEFORE consolidating - the
tree-uniqueness violations heal cannot see. Fix a duplicate deliberately (keep the better hook)
rather than with a blind move.
0b. Scope-descriptor synthesis (freshness-gated, parallel sonnet subagents). The per-level
descriptors are the PLACEMENT ROUTING KEY, so every level needs a meaningful one. LEVELS MEANS
THE WHOLE TREE: every pointer-block-bearing dir under the anchor - SIBLING projects and
departments included - not just the cwd's ancestor chain. Enumerate them with
find <anchor> -name CLAUDE.local.md -not -path '*/.venv*' -not -path '*/site-packages/*',
NEVER a bare grep -r (see "Level enumeration" in references/dream-core.md: the session
grep honors .gitignore and silently misses every gitignored store, while a bare find
OVER-counts a vendored plugin copy under a repo's .venv). Only synthesize levels whose descriptor is EMPTY,
INCOMPLETE (missing template keys), or whose CHILDREN list is stale vs the actual
subdirectories. Dispatch one sonnet subagent per stale
level, in parallel (bottom-up in two waves when a leaf and its parent are both stale, so the
parent can read fresh child descriptors). An upper level's subagent reads each child dir's
README/CLAUDE.md/docs headings + child descriptors; the project level's subagent reads the
project's OWN docs. Write via set-scope (require its success line). Fixed template, <= 120
words per level, ASCII, uppercase keys:
WHAT: <1-2 sentences: what this level IS>
STACK: <languages, frameworks, tools, key resources>
CHILDREN:
- <dir>/: <one clause>
PLACE-HERE: <knowledge true for THIS WHOLE subtree but NOT above>
PLACE-ELSEWHERE: <push child-specific down; push broader-than-subtree up>
After the fan-out, VERIFY from ground truth (see "Verify every parallel WRITE fan-out" in
references/dream-core.md): `set-scope` overwrites unconditionally, so a subagent that writes the
wrong `--proj` silently clobbers a sibling while reporting success on the right path. Re-run the
freshness check over ALL levels and diff each level's on-disk descriptor against what its own
agent RETURNED; keep each agent's returned text (the only restore source - the backup holds just
the stale version).
0c. Read the toolbox inventory (one command, and it belongs HERE, not at the end).
uv run ~/.claude/skills/toolbox/tools/toolbox.py list - the READ half of the toolbox pass per
references/dream-core.md "Toolbox pass"; skip only if that path does not exist. This is a
PREREQUISITE of steps 4, 5 and 7, whose scans a shipped tool has often already implemented and
calibrated: read the names now and check them before hand-rolling any scan below. The
CONSOLIDATE judgement is a separate half and stays at step 10b.
Capture first (unconditional on a manual dream). Enumerate this session's durable learnings
and capture via bitranox:meta-self-improve BEFORE consolidating, so the dream works on a
complete store. Read the ## Lessons for the next nap heading of every handover.md on the
chain as capture input too (repo roots under the anchor; git log -p -- handover.md reaches
ones already overwritten since the last dream): a work session RECORDS its lessons there and
does not capture them itself, so a dream that skips the heading drops them.
Back up + manifest. Run store_manifest.py backup (home: <plugin>/skills/meta-dream-tree/,
launch via hooks/run-python.sh) with --scope tree (a nap uses --scope chain):
store_manifest.py backup --from <anchor> --scope tree \
--out ~/.claude/self-improve-audit/backups/<key>-<ts>
It copies the anchor's .claude-memory/ AND each in-scope CLAUDE.local.md, and records the
ORDER-INDEPENDENT manifest of (level, slug, title, pin) tuples that step 8 re-derives. Do not
hand-roll the walk: a gitignore-aware grep -r SKIPS the pointer files, and an exact-match
prune of .venv misses .venv-win and venv-<user>, so vendored copies read as real levels.
An empty scope is a REFUSAL, because a manifest of nothing verifies clean against anything.
Then commit the store's git repo (Durability pass) so the pre-dream state is one git diff
away.
Load both tiers TREE-WIDE - every level's pointer block under the anchor (the cwd's chain
AND every sibling project/department; the central bodies are one store) plus the native raw
tier - and skim the session for uncaptured items. A dream that only reads the cwd's chain
misses exactly where duplicates and misplaced facts live: the siblings.
3b. De-double the tiers. A fact lives in exactly ONE tier. Per native entry: already curated
(by title/hook match) -> drop the native duplicate; native-only and
worthwhile -> PROMOTE via engine add; some-value -> leave in
native. There is NO "native-only backend" mode - an absent pointer block is the trigger to
create one, not evidence of one. The only reasons a worthwhile fact stays native: some-value,
or the SECRETS carve-out (curated stores are git-tracked; the native tier is not - never stage
credentials into a repo).
Dedup / merge ACROSS THE TREE. Get the candidate pairs from dedup_scan.py (home:
<plugin>/skills/meta-dream-tree/, launch via hooks/run-python.sh):
dedup_scan.py --from <anchor> --threshold 0.45
READ ITS CONTROL LINE FIRST. Every run plants a paraphrase of a real fact and scores it through
the same path; if that did not fire, the run is an INSTRUMENT FAILURE and its empty candidate
list means nothing - a scorer that cannot fire and a clean tree both report zero. Read the
printed DISTRIBUTION too: a pair just under the threshold is the one most worth a look, and a
threshold is otherwise a way of not looking.
The output is CANDIDATES, not duplicates - it scores words, so read BOTH bodies before folding
anything. Fold near-duplicates into one sharpened entry (engine add, same slug), comparing
across ALL levels, especially SIBLING projects (the classic duplicate is the same lesson
captured independently in two siblings; it merges at their common parent). Cross-link related
entries with [[slug]]. Dedup runs TWICE - here, and again in step 8, because placement
creates new overlap.
PLACEMENT (re-level every entry, pinned included; up AND down). Route each fact through
THE routing prompt in references/dream-core.md against the descriptor ladder (leaf -> anchor);
the tier note (inline judgment at opus-class or above; switch-model-or-continue) is in the
core too. Batch the high-confidence moves into ONE propose-diff (auto mode: apply); apply each
via engine
move --from-level A --to-level B --slug s and require its success line (! refused: aborts
that move - a down-move with inbound refs needs the refs re-pointed first, or stays). When the
citer blocking a down-move belongs at the target TOO, move them in ONE call by repeating
--slug: the guard then judges each member by where the WHOLE set lands, which is the only way
a mutually-citing pair goes down at all (no ordering releases it). Never reach for --force
there - it strands the ref. Low/UNSURE never moves. Tree-top promotion additionally passes the
corroboration gate (user-stated: eager;
model-inferred: >= 2 DISTINCT PROJECTS): record each model-inferred tree-top candidate with
dream_state.py saw-promotable <slug> <project the fact came from>, gate the promotion on
dream_state.py should-promote <slug> (promote/hold), and after an applied promotion run
dream_state.py promoted <slug> to clear every project's sighting. Repeat sightings from ONE
project count once, so re-running a dream over unchanged facts corroborates nothing. HOLD keeps
the fact at the project level until a SECOND project sights it. After moving, normalize
reference+delta
UPWARD-ONLY: the general lives once at its altitude, lower entries cite [[general]] + delta.
A pinned fact is out of reach for an ordinary write, not for placement. The engine REFUSES
an add targeting a pinned slug (PinnedEntry) before any write; the dream does not route
around that refusal with amend-pinned - that verb is for a human at the keyboard. Report a
pinned fact whose CONTENT you believe is wrong; do not rewrite it, and do not call
amend-pinned on its behalf. move carries the pin through unchanged and never refuses on it,
so re-leveling a pinned fact is ordinary placement work like any other entry - no exception, no
separate approval step.
Voice + firing check (maintenance). The engine lints new hooks at add-time; here, sweep the
whole store for residue with memory_engine.py lint --tree "<cwd>" (reports, tree-wide, hooks over
the 500-char HARD cap - add refuses one, so any that exist were hand-edited or arrived with a
legacy store, and each needs a rewrite - trigger-less hooks, and bodies missing the
**Why:**/**How to apply:** frame - a tracked backlog number, advisory). Then apply judgment on
top: a hook whose trigger does not actually name the situations its body applies to (the FIRING
check - would this line catch your attention at the right moment?). Do
NOT rewrite a hook merely for exceeding the 350 SOFT cap - a complete trigger-first hook may run up
to the hard cap, which the engine enforces by refusal. Queue offenders to a sonnet
rewrite (trigger-first, facts preserved, slug-stable via add --slug <the stored slug> aimed at
the level that OWNS the pointer - a title-derived slug mints a duplicate when the fact was
retitled, and any other level is refused as a collision), propose-diff, apply.
Bodies missing the frame or the Why:/How to apply: sections get the same treatment.
Prune (content-based only, tree-wide). Archive obsolete/superseded/task-state entries at
EVERY level of the tree (siblings included) per the removal policy in
references/dream-passes.md (propose-first; the backup makes it safe). Never
usage/age/size-based.
Two questions to ask of every entry reviewed, because an accumulated bad fact
survives longest here:
- Does this assert a tool does NOT work, without a version or date that makes
it re-testable? If so, re-test it or delete it. A stale negative claim is
worse than a missing fact: it actively steers away from something that works.
- Does this describe a session that never reached a working end state, without
labelling it unsolved? If so, relabel it as unsolved.
Re-dedup, then verify. Sweep the entries placement touched (a lifted general now overlaps
its origin and siblings) and normalize - re-run dedup_scan.py from step 4, whose control line
applies again. Then re-derive the manifest and diff against step 2 with
store_manifest.py verify --out <the same backup dir>: exit 0 is identical, exit 1 NAMES what
was added, removed, changed or moved. Only level may differ (reported as moved), plus
explicitly-decided merges/prunes/rewords; anything else is a loss to explain before finishing.
Then run
reconcile_memory_index.py --check <altitude chain, narrow->broad> (home:
<plugin>/skills/meta-self-improve/reconcile_memory_index.py) and require TOTAL problems: 0,
AND reconcile_memory_index.py --check-tree "<cwd>" for TOTAL tree problems: 0 (the cross-sibling
duplicate/orphan check the chain-only --check cannot make); fix integrity failures via the engine
(re-point a downward ref, resolve an orphan, dedup a duplicate pointer). Size warnings are advisory.
Behavioral passes. Run the catalog in references/dream-passes.md (each pass on its own
trigger): CLAUDE.md reconciliation (chain-gated - runs EVERY dream, rule-by-rule, both
directions), contradiction/override, skill/hook pointing, filler words, model review,
skill-gap review, gate-coverage audit, local skill/hook audit (this tree's .claude/skills,
--no-personal), durability/git + squash, backup reminder.
Skill-fit -> batched change. FIRST drain what is already pending: contrib_queue.py list
(home: <plugin>/skills/meta-self-improve/) shows the skill/hook contributions earlier sessions
judged shippable but never shipped - they are part of THIS batch. Then collect this dream's
generalizations that match or warrant a shipped skill, and QUEUE each one
(contrib_queue.py add --what ... --target skill:<name> --why ...) as you find it, so an
unshipped one survives this session. Then DELIVER them via the upstream loop
(bitranox:meta-self-improve -> references/upstream-propagation.md) as ONE structured change - a
REQUIRED end-of-dream action: verify each candidate against the CURRENT skill content first (some
may already be shipped -> drop, do not re-add), then propose -> self-PR; auto -> commit or
self-PR; off -> skip. Close each delivered one individually with contrib_queue.py ship --match <unique text> --note <where it landed>, and each disproven one with drop - --match not
--index, which shifts under the previous close, and never drain, which closes the WHOLE
queue and so fits only a sweep where every entry shipped. Leave one queued for next session
ONLY when it genuinely needs user input or the mode is off - a deliverable one left pending
evaporates the intent until a manual re-prompt.
10b. Toolbox pass, CONSOLIDATE half (PROPOSE-ONLY). Run the CONSOLIDATE delta per
references/dream-core.md "Toolbox pass" over the inventory step 0c already read - this half is
judgement about the tools, so it belongs at the end; the READ that the earlier passes depend on
does not, which is why it is not repeated here. PROPOSE merging near-duplicate tools and flagging
any stale/superseded one (no usage-based prune - forgetting-is-usage-based-only). Detect +
propose ONLY; the actual merge is a TDD change through bitranox:meta-self-improve's tool
endpoint, never edited here. Skip if the toolbox path does not exist.
- Done + report + /clear nudge.
dream_state.py done (records the fact signature). Report
counts + one line each: merges, placements (with direction), voice rewrites, prunes, skill
changes, toolbox proposals (merges/flags), pinned facts reported not rewritten. CLAUDE.md edits are
APPLIED, so the report is the only place the user sees them: per RULE, name every file touched,
the ANCESTOR covering home it now relies on, and the transformation (removed / rewritten in
place); a rule left alone for want of an ancestor is listed too, never silently skipped.
Nudge /clear (the consolidated store loads next session; not clearing loses nothing).
The tree, not "the global layer"
This dream is scoped to the CURRENT tree (cwd's anchor). A machine can carry several independent
trees; another tree is NEVER read or written here - ensure-all-trees/tree-top locate tops, and
cross-tree movement is only ever collect-knowledge's labeled copy or dream-global's job. Say "the
tree's top", not "the global layer".
Acceptance harness (prove the dream works)
tests/fixture_builder.py plants a deterministic two-tree fixture (dup pair, mis-placed high/low
facts, an obsolete entry, task-state, a trigger-less hook, a pinned decoy, an empty descriptor, an
untouched control tree); tests/fixture_asserter.py checks a post-dream run: HARD assertions
(control tree byte-identical, pinned entry untouched, slugs stable under voice rewrites, reconcile
0 problems, backups exist) and JUDGMENT assertions (dup merged at the parent, high fact moved
down, low fact moved up exactly one level, obsolete proposed for archive, task-state pruned,
descriptor synthesized). Run it after any substantive change to this skill (procedure in
tests/README-acceptance.md); the bar is all-hard + >= 5/6 judgment on two consecutive runs.
Boundaries
- The family Boundaries (memory, CLAUDE.md, skills/hooks, pinned entries, structural moves) live in
references/dream-core.md and apply here unchanged - read them there, they are not restated.
- Circle-breaker: consolidated twice and it keeps coming back -> escalate to a guard or the user.
Deliverables (a completed dream has ALL of these)
An ended run missing any box is not done - finish it or say plainly what was skipped and why.
Rationalizations (pressure-tested; these do not fly)
| Excuse |
Reality |
| "not-due / no store exists -> nothing to consolidate" |
not-due never suppresses capture; an absent store is the TRIGGER to create one. Two learnings uncaptured = work exists. |
| "Only N entries changed -> grep their keywords over CLAUDE.md" |
The named prohibited shortcut. Reconciliation is rule-by-rule, BOTH directions, every dream - pre-existing overlap is the point. |
| "auto mode + 'stop asking' covers the pinned entry" |
Auto mode changes nothing here: the engine REFUSES an ordinary add on a pinned slug regardless of mode, and the dream never calls amend-pinned (human-only) to push a change through anyway. |
| "I'm 90% sure, despite CONFIDENCE low" |
The router's confidence gates the move, not your certainty. Evidence beats wording; UNSURE stays put. |
| "Writing it into CLAUDE.md is faster than the engine" |
Routing into CLAUDE.md is not capture; the store is the system of record. |
| "The store is empty/unchanged, so the passes no-op" |
Only counter-gated passes no-op on emptiness; chain-gated passes (reconciliation, dedup, placement) run EVERY dream. |
| "No time for the full pass - I'll note it for next dream" |
Say it out loud in the report as INCOMPLETE and flagged; never silently downgrade a pass and call the dream done. |
Common mistakes
- Growing the store (a dream must net-shrink noise).
- Dreaming without capturing first.
- Consolidating only the cwd's ancestor CHAIN. The dream covers the WHOLE tree - sibling
projects and departments are where the dups, misplacements, and stale task-state live (a
chain-only run leaves them untouched and scores as a half-dream).
- Placement by wording instead of EVIDENCE, or moving a low-confidence fact.
- Rewriting a pinned entry's content via
add (the engine refuses, PinnedEntry), or reaching
for amend-pinned to push a dream-authored change through anyway (that verb is human-only; the
dream never calls it) - report a wrong pinned fact instead of touching it.
- Moving DOWN past inbound
[[refs]] without re-pointing them first (the engine refuses).
- Deduping only BEFORE placement (placement creates the overlap; step 8 exists for that).
- Reading a no-op off the wrong signal: chain-gated passes (CLAUDE.md reconciliation, dedup,
placement) run EVERY dream; only counter-gated passes no-op on emptiness.
- Running CLAUDE.md reconciliation as a keyword-grep of only the newly-written entries (misses all
pre-existing duplication; the pass is rule-by-rule over the entire chain, both directions).
- A downward or cross-tree
[[reference]] (dangles on deletion; cross-tree is always a copy).
- Forgetting
dream_state.py done, so the nudge keeps firing.
1---2name: meta-dream-tree3description: Use when the SessionStart nudge says a memory consolidation is due, when the store has grown or feels noisy/duplicated, before context compaction would lose detail, or on "dream", "dream tree", "/dream-tree", "consolidate memory", "tidy memory". Use AFTER per-turn capture (bitranox:meta-self-improve); for the cross-project / cross-tree scan use bitranox:meta-dream-crosstree instead. Honors an off/auto/propose mode. Formerly named meta-dream-project - answers to that name too.4---56# meta-dream-tree78Memory consolidation for the CURRENT project's knowledge tree, the way a brain reorganizes during9sleep. `bitranox:meta-self-improve` is the fast per-turn CAPTURE; this is the periodic batch10CONSOLIDATION: dedup, merge, re-level (PLACEMENT), normalize, prune - so memory gets smaller and11sharper, not bigger. **If a pass would grow the store, it is wrong.**1213**REQUIRED BACKGROUND:** the storage spec (trees/anchors, store grammar, trigger-first hooks,14framed bodies, engine commands + fail-loud contract) is `bitranox:meta-self-improve` ->15`references/memory-backend.md` - Read it BEFORE the first engine call. This skill stays WITHIN the16current tree; cross-tree work is `bitranox:meta-dream-crosstree`.1718## Reference files1920| Topic | File |21|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|22| The SHARED DREAM CORE - scope ladder, mode knob, capture-first, backup+manifest, dedup semantics, THE routing prompt, verification contract, tier note (single source for nap/project/global) | references/dream-core.md |23| The behavioral pass catalog - removal policy, contradiction/override, CLAUDE.md reconciliation, skill/hook pointing, filler words, model review, skill-gap, gate-coverage, durability/squash, backup reminder | references/dream-passes.md |24| Acceptance harness - planted-fixture test that proves a dream run works | tests/README-acceptance.md |2526Tools shipped here, runnable outside a dream run too: `dream_state.py` (mode + due state),27`store_manifest.py` (backup and verify), `dedup_scan.py` (candidate pairs), `statusrot.py` (pointer28lines still asserting a STATUS that shipped and was never updated; a hit is a CANDIDATE to check29against its owner, and only a SELF-CONTRADICTION - a slug saying one thing under a hook saying30another - is a defect on its own and sets exit 1; its UNEXAMINED list is split into RE-SURFACED,31WRITTEN SINCE the sweep and NEVER CHECKED, and only the last is a backlog of unchecked claims -32read the count for that group, never the total; `clear` records an adjudication, which is what33stops an entry being re-reported until its hook changes, and takes34`--slug <s>` REPEATABLY - a bare `clear` certifies every candidate in scope, so name the ones you35actually checked, and a slug that is not a flagged candidate is refused rather than recorded) and36`factedit.py` (reword a fact's hook or body by recomposing it through `memory_engine.py`, since a37Write or Edit on a pointer block or a body is denied by the store-edit guard; `show` reports the38stored `type`, an amend PRESERVES it, and `--type` is the one deliberate way to re-classify, a39PINNED fact included - `amend-pinned` carries `--type` and is the only route to a pinned fact's40kind, since `add` refuses a pinned entry outright). The41last two moved here from a personal toolbox; the PreToolUse nudge names them on the chores they42answer, so they surface without this file being open.4344Use the Read tool to load a referenced file when running its passes.4546## Mode4748Read the mode first per references/dream-core.md (propose / auto / off - the knob semantics live49ONLY there).5051## When to run5253Nudged when due (SessionStart), around compaction (PreCompact salvages, you dream), or manual54("dream", "/dream-tree"). Check `dream_state.py due` (the script lives in THIS skill's dir; launch55recipe in references/dream-core.md "Script homes"). **A MANUAL dream ALWAYS captures -56`not-due` never suppresses capture.** An absent store is the trigger to CREATE one (the first57engine `add` bootstraps it), never a reason to skip; routing a learning only into a CLAUDE.md is58NOT capture. Verify "nothing durable" - never assume it.5960## Procedure6162Create one todo per step. Every engine call follows the fail-loud contract (strict env, require63the success line, abort-and-show on a miss).64650a. **Deterministic scaffold + tree-wide integrity (scripts, no model).**66 `memory_engine.py heal --proj "<cwd>"` (via `run-python.sh`): creates every missing marker67 `CLAUDE.md` + `CLAUDE.local.md` pointer block from the project up to the anchor, plus the central68 store; normalizes drifted grammar. Require `healed N file(s) across M level(s)`. `heal` is69 CHAIN-scoped and only normalizes grammar, so FOLLOW it with70 `reconcile_memory_index.py --check-tree "<cwd>"` (home: `<plugin>/skills/meta-self-improve/`) to71 surface any cross-sibling DUPLICATE pointer / orphan / dangling body BEFORE consolidating - the72 tree-uniqueness violations `heal` cannot see. Fix a duplicate deliberately (keep the better hook)73 rather than with a blind `move`.74750b. **Scope-descriptor synthesis (freshness-gated, parallel sonnet subagents).** The per-level76 descriptors are the PLACEMENT ROUTING KEY, so every level needs a meaningful one. LEVELS MEANS77 THE WHOLE TREE: every pointer-block-bearing dir under the anchor - SIBLING projects and78 departments included - not just the cwd's ancestor chain. Enumerate them with79 `find <anchor> -name CLAUDE.local.md -not -path '*/.venv*' -not -path '*/site-packages/*'`,80 NEVER a bare `grep -r` (see "Level enumeration" in references/dream-core.md: the session81 `grep` honors `.gitignore` and silently misses every gitignored store, while a bare `find`82 OVER-counts a vendored plugin copy under a repo's `.venv`). Only synthesize levels whose descriptor is EMPTY,83 INCOMPLETE (missing template keys), or whose CHILDREN list is stale vs the actual84 subdirectories. Dispatch one `sonnet` subagent per stale85 level, in parallel (bottom-up in two waves when a leaf and its parent are both stale, so the86 parent can read fresh child descriptors). An upper level's subagent reads each child dir's87 README/CLAUDE.md/docs headings + child descriptors; the project level's subagent reads the88 project's OWN docs. Write via `set-scope` (require its success line). Fixed template, <= 12089 words per level, ASCII, uppercase keys:9091 WHAT: <1-2 sentences: what this level IS>92 STACK: <languages, frameworks, tools, key resources>93 CHILDREN:94 - <dir>/: <one clause>95 PLACE-HERE: <knowledge true for THIS WHOLE subtree but NOT above>96 PLACE-ELSEWHERE: <push child-specific down; push broader-than-subtree up>9798 After the fan-out, VERIFY from ground truth (see "Verify every parallel WRITE fan-out" in99 references/dream-core.md): `set-scope` overwrites unconditionally, so a subagent that writes the100 wrong `--proj` silently clobbers a sibling while reporting success on the right path. Re-run the101 freshness check over ALL levels and diff each level's on-disk descriptor against what its own102 agent RETURNED; keep each agent's returned text (the only restore source - the backup holds just103 the stale version).1041050c. **Read the toolbox inventory (one command, and it belongs HERE, not at the end).**106 `uv run ~/.claude/skills/toolbox/tools/toolbox.py list` - the READ half of the toolbox pass per107 references/dream-core.md "Toolbox pass"; skip only if that path does not exist. This is a108 PREREQUISITE of steps 4, 5 and 7, whose scans a shipped tool has often already implemented and109 calibrated: read the names now and check them before hand-rolling any scan below. The110 CONSOLIDATE judgement is a separate half and stays at step 10b.1111121. **Capture first (unconditional on a manual dream).** Enumerate this session's durable learnings113 and capture via `bitranox:meta-self-improve` BEFORE consolidating, so the dream works on a114 complete store. Read the `## Lessons for the next nap` heading of every `handover.md` on the115 chain as capture input too (repo roots under the anchor; `git log -p -- handover.md` reaches116 ones already overwritten since the last dream): a work session RECORDS its lessons there and117 does not capture them itself, so a dream that skips the heading drops them.1181192. **Back up + manifest.** Run `store_manifest.py backup` (home: `<plugin>/skills/meta-dream-tree/`,120 launch via `hooks/run-python.sh`) with `--scope tree` (a nap uses `--scope chain`):121122 store_manifest.py backup --from <anchor> --scope tree \123 --out ~/.claude/self-improve-audit/backups/<key>-<ts>124125 It copies the anchor's `.claude-memory/` AND each in-scope `CLAUDE.local.md`, and records the126 ORDER-INDEPENDENT manifest of (level, slug, title, pin) tuples that step 8 re-derives. Do not127 hand-roll the walk: a gitignore-aware `grep -r` SKIPS the pointer files, and an exact-match128 prune of `.venv` misses `.venv-win` and `venv-<user>`, so vendored copies read as real levels.129 An empty scope is a REFUSAL, because a manifest of nothing verifies clean against anything.130 Then commit the store's git repo (Durability pass) so the pre-dream state is one `git diff`131 away.1321333. **Load both tiers TREE-WIDE** - every level's pointer block under the anchor (the cwd's chain134 AND every sibling project/department; the central bodies are one store) plus the native raw135 tier - and skim the session for uncaptured items. A dream that only reads the cwd's chain136 misses exactly where duplicates and misplaced facts live: the siblings.1371383b. **De-double the tiers.** A fact lives in exactly ONE tier. Per native entry: already curated139 (by title/hook match) -> drop the native duplicate; native-only and140 worthwhile -> PROMOTE via engine `add`; some-value -> leave in141 native. There is NO "native-only backend" mode - an absent pointer block is the trigger to142 create one, not evidence of one. The only reasons a worthwhile fact stays native: some-value,143 or the SECRETS carve-out (curated stores are git-tracked; the native tier is not - never stage144 credentials into a repo).1451464. **Dedup / merge ACROSS THE TREE.** Get the candidate pairs from `dedup_scan.py` (home:147 `<plugin>/skills/meta-dream-tree/`, launch via `hooks/run-python.sh`):148149 dedup_scan.py --from <anchor> --threshold 0.45150151 READ ITS CONTROL LINE FIRST. Every run plants a paraphrase of a real fact and scores it through152 the same path; if that did not fire, the run is an INSTRUMENT FAILURE and its empty candidate153 list means nothing - a scorer that cannot fire and a clean tree both report zero. Read the154 printed DISTRIBUTION too: a pair just under the threshold is the one most worth a look, and a155 threshold is otherwise a way of not looking.156157 The output is CANDIDATES, not duplicates - it scores words, so read BOTH bodies before folding158 anything. Fold near-duplicates into one sharpened entry (engine `add`, same slug), comparing159 across ALL levels, especially SIBLING projects (the classic duplicate is the same lesson160 captured independently in two siblings; it merges at their common parent). Cross-link related161 entries with `[[slug]]`. Dedup runs TWICE - here, and again in step 8, because placement162 creates new overlap.1631645. **PLACEMENT (re-level every entry, pinned included; up AND down).** Route each fact through165 THE routing prompt in references/dream-core.md against the descriptor ladder (leaf -> anchor);166 the tier note (inline judgment at opus-class or above; switch-model-or-continue) is in the167 core too. Batch the high-confidence moves into ONE propose-diff (auto mode: apply); apply each168 via engine169 `move --from-level A --to-level B --slug s` and require its success line (`! refused:` aborts170 that move - a down-move with inbound refs needs the refs re-pointed first, or stays). When the171 citer blocking a down-move belongs at the target TOO, move them in ONE call by repeating172 `--slug`: the guard then judges each member by where the WHOLE set lands, which is the only way173 a mutually-citing pair goes down at all (no ordering releases it). Never reach for `--force`174 there - it strands the ref. Low/UNSURE never moves. Tree-top promotion additionally passes the175 corroboration gate (user-stated: eager;176 model-inferred: >= 2 DISTINCT PROJECTS): record each model-inferred tree-top candidate with177 `dream_state.py saw-promotable <slug> <project the fact came from>`, gate the promotion on178 `dream_state.py should-promote <slug>` (`promote`/`hold`), and after an applied promotion run179 `dream_state.py promoted <slug>` to clear every project's sighting. Repeat sightings from ONE180 project count once, so re-running a dream over unchanged facts corroborates nothing. HOLD keeps181 the fact at the project level until a SECOND project sights it. After moving, normalize182 reference+delta183 UPWARD-ONLY: the general lives once at its altitude, lower entries cite `[[general]]` + delta.184 **A pinned fact is out of reach for an ordinary write, not for placement.** The engine REFUSES185 an `add` targeting a pinned slug (`PinnedEntry`) before any write; the dream does not route186 around that refusal with `amend-pinned` - that verb is for a human at the keyboard. Report a187 pinned fact whose CONTENT you believe is wrong; do not rewrite it, and do not call188 `amend-pinned` on its behalf. `move` carries the pin through unchanged and never refuses on it,189 so re-leveling a pinned fact is ordinary placement work like any other entry - no exception, no190 separate approval step.1911926. **Voice + firing check (maintenance).** The engine lints new hooks at add-time; here, sweep the193 whole store for residue with `memory_engine.py lint --tree "<cwd>"` (reports, tree-wide, hooks over194 the 500-char HARD cap - `add` refuses one, so any that exist were hand-edited or arrived with a195 legacy store, and each needs a rewrite - trigger-less hooks, and bodies missing the196 `**Why:**`/`**How to apply:**` frame - a tracked backlog number, advisory). Then apply judgment on197 top: a hook whose trigger does not actually name the situations its body applies to (the FIRING198 check - would this line catch your attention at the right moment?). Do199 NOT rewrite a hook merely for exceeding the 350 SOFT cap - a complete trigger-first hook may run up200 to the hard cap, which the engine enforces by refusal. Queue offenders to a sonnet201 rewrite (trigger-first, facts preserved, slug-stable via `add --slug <the stored slug>` aimed at202 the level that OWNS the pointer - a title-derived slug mints a duplicate when the fact was203 retitled, and any other level is refused as a collision), propose-diff, apply.204 Bodies missing the frame or the **Why:**/**How to apply:** sections get the same treatment.2052067. **Prune (content-based only, tree-wide).** Archive obsolete/superseded/task-state entries at207 EVERY level of the tree (siblings included) per the removal policy in208 references/dream-passes.md (propose-first; the backup makes it safe). Never209 usage/age/size-based.210211 Two questions to ask of every entry reviewed, because an accumulated bad fact212 survives longest here:213214 1. Does this assert a tool does NOT work, without a version or date that makes215 it re-testable? If so, re-test it or delete it. A stale negative claim is216 worse than a missing fact: it actively steers away from something that works.217 2. Does this describe a session that never reached a working end state, without218 labelling it unsolved? If so, relabel it as unsolved.2192208. **Re-dedup, then verify.** Sweep the entries placement touched (a lifted general now overlaps221 its origin and siblings) and normalize - re-run `dedup_scan.py` from step 4, whose control line222 applies again. Then re-derive the manifest and diff against step 2 with223 `store_manifest.py verify --out <the same backup dir>`: exit 0 is identical, exit 1 NAMES what224 was added, removed, changed or moved. Only `level` may differ (reported as `moved`), plus225 explicitly-decided merges/prunes/rewords; anything else is a loss to explain before finishing.226 Then run227 `reconcile_memory_index.py --check <altitude chain, narrow->broad>` (home:228 `<plugin>/skills/meta-self-improve/reconcile_memory_index.py`) and require `TOTAL problems: 0`,229 AND `reconcile_memory_index.py --check-tree "<cwd>"` for `TOTAL tree problems: 0` (the cross-sibling230 duplicate/orphan check the chain-only `--check` cannot make); fix integrity failures via the engine231 (re-point a downward ref, resolve an orphan, dedup a duplicate pointer). Size warnings are advisory.2322339. **Behavioral passes.** Run the catalog in references/dream-passes.md (each pass on its own234 trigger): CLAUDE.md reconciliation (chain-gated - runs EVERY dream, rule-by-rule, both235 directions), contradiction/override, skill/hook pointing, filler words, model review,236 skill-gap review, gate-coverage audit, local skill/hook audit (this tree's `.claude/skills`,237 `--no-personal`), durability/git + squash, backup reminder.23823910. **Skill-fit -> batched change.** FIRST drain what is already pending: `contrib_queue.py list`240 (home: `<plugin>/skills/meta-self-improve/`) shows the skill/hook contributions earlier sessions241 judged shippable but never shipped - they are part of THIS batch. Then collect this dream's242 generalizations that match or warrant a shipped skill, and QUEUE each one243 (`contrib_queue.py add --what ... --target skill:<name> --why ...`) as you find it, so an244 unshipped one survives this session. Then DELIVER them via the upstream loop245 (`bitranox:meta-self-improve` -> references/upstream-propagation.md) as ONE structured change - a246 REQUIRED end-of-dream action: verify each candidate against the CURRENT skill content first (some247 may already be shipped -> drop, do not re-add), then `propose` -> self-PR; `auto` -> commit or248 self-PR; `off` -> skip. Close each delivered one individually with `contrib_queue.py ship --match249 <unique text> --note <where it landed>`, and each disproven one with `drop` - `--match` not250 `--index`, which shifts under the previous close, and never `drain`, which closes the WHOLE251 queue and so fits only a sweep where every entry shipped. Leave one queued for next session252 ONLY when it genuinely needs user input or the mode is `off` - a deliverable one left pending253 evaporates the intent until a manual re-prompt.25425510b. **Toolbox pass, CONSOLIDATE half (PROPOSE-ONLY).** Run the CONSOLIDATE delta per256 references/dream-core.md "Toolbox pass" over the inventory step 0c already read - this half is257 judgement about the tools, so it belongs at the end; the READ that the earlier passes depend on258 does not, which is why it is not repeated here. PROPOSE merging near-duplicate tools and flagging259 any stale/superseded one (no usage-based prune - `forgetting-is-usage-based-only`). Detect +260 propose ONLY; the actual merge is a TDD change through `bitranox:meta-self-improve`'s tool261 endpoint, never edited here. Skip if the toolbox path does not exist.26226311. **Done + report + /clear nudge.** `dream_state.py done` (records the fact signature). Report264 counts + one line each: merges, placements (with direction), voice rewrites, prunes, skill265 changes, toolbox proposals (merges/flags), pinned facts reported not rewritten. CLAUDE.md edits are266 APPLIED, so the report is the only place the user sees them: per RULE, name every file touched,267 the ANCESTOR covering home it now relies on, and the transformation (removed / rewritten in268 place); a rule left alone for want of an ancestor is listed too, never silently skipped.269 Nudge `/clear` (the consolidated store loads next session; not clearing loses nothing).270271## The tree, not "the global layer"272273This dream is scoped to the CURRENT tree (cwd's anchor). A machine can carry several independent274trees; another tree is NEVER read or written here - `ensure-all-trees`/`tree-top` locate tops, and275cross-tree movement is only ever collect-knowledge's labeled copy or dream-global's job. Say "the276tree's top", not "the global layer".277278## Acceptance harness (prove the dream works)279280`tests/fixture_builder.py` plants a deterministic two-tree fixture (dup pair, mis-placed high/low281facts, an obsolete entry, task-state, a trigger-less hook, a pinned decoy, an empty descriptor, an282untouched control tree); `tests/fixture_asserter.py` checks a post-dream run: HARD assertions283(control tree byte-identical, pinned entry untouched, slugs stable under voice rewrites, reconcile2840 problems, backups exist) and JUDGMENT assertions (dup merged at the parent, high fact moved285down, low fact moved up exactly one level, obsolete proposed for archive, task-state pruned,286descriptor synthesized). Run it after any substantive change to this skill (procedure in287tests/README-acceptance.md); the bar is all-hard + >= 5/6 judgment on two consecutive runs.288289## Boundaries290291- The family Boundaries (memory, CLAUDE.md, skills/hooks, pinned entries, structural moves) live in292 references/dream-core.md and apply here unchanged - read them there, they are not restated.293- Circle-breaker: consolidated twice and it keeps coming back -> escalate to a guard or the user.294295## Deliverables (a completed dream has ALL of these)296297- [ ] heal success line ("healed N file(s) across M level(s)").298- [ ] Scope descriptors fresh: every chain level carries the template keys (or was verified fresh).299- [ ] Capture ran BEFORE consolidation (or a verified "nothing durable" statement).300- [ ] Backup taken + the (level, slug, title, pin) manifest recorded pre-dream.301- [ ] Placement report: applied moves (with direction; pinned entries re-level like any other),302 kept UNSUREs.303- [ ] No pinned entry's content rewritten this run; any pinned fact believed wrong is reported, not304 amended via `add` or `amend-pinned`.305- [ ] Voice/firing residue swept (or "0 offenders" verified via the lint).306- [ ] Post-dream manifest diff clean (only `level` changed, plus explicitly-decided merges/prunes).307- [ ] `reconcile ... --check` printed `TOTAL problems: 0`.308- [ ] `reconcile ... --check-tree "<cwd>"` printed `TOTAL tree problems: 0` (the cross-sibling309 duplicate/orphan check the chain-only `--check` structurally cannot make).310- [ ] Each behavioral pass reported against ITS OWN trigger (ran / no-op with the verified reason).311- [ ] `dream_state.py done` ran; report + `/clear` nudge delivered.312313An ended run missing any box is not done - finish it or say plainly what was skipped and why.314315## Rationalizations (pressure-tested; these do not fly)316317| Excuse | Reality |318|----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|319| "not-due / no store exists -> nothing to consolidate" | not-due never suppresses capture; an absent store is the TRIGGER to create one. Two learnings uncaptured = work exists. |320| "Only N entries changed -> grep their keywords over CLAUDE.md" | The named prohibited shortcut. Reconciliation is rule-by-rule, BOTH directions, every dream - pre-existing overlap is the point. |321| "auto mode + 'stop asking' covers the pinned entry" | Auto mode changes nothing here: the engine REFUSES an ordinary `add` on a pinned slug regardless of mode, and the dream never calls `amend-pinned` (human-only) to push a change through anyway. |322| "I'm 90% sure, despite CONFIDENCE low" | The router's confidence gates the move, not your certainty. Evidence beats wording; UNSURE stays put. |323| "Writing it into CLAUDE.md is faster than the engine" | Routing into CLAUDE.md is not capture; the store is the system of record. |324| "The store is empty/unchanged, so the passes no-op" | Only counter-gated passes no-op on emptiness; chain-gated passes (reconciliation, dedup, placement) run EVERY dream. |325| "No time for the full pass - I'll note it for next dream" | Say it out loud in the report as INCOMPLETE and flagged; never silently downgrade a pass and call the dream done. |326327## Common mistakes328329- Growing the store (a dream must net-shrink noise).330- Dreaming without capturing first.331- Consolidating only the cwd's ancestor CHAIN. The dream covers the WHOLE tree - sibling332 projects and departments are where the dups, misplacements, and stale task-state live (a333 chain-only run leaves them untouched and scores as a half-dream).334- Placement by wording instead of EVIDENCE, or moving a low-confidence fact.335- Rewriting a pinned entry's content via `add` (the engine refuses, `PinnedEntry`), or reaching336 for `amend-pinned` to push a dream-authored change through anyway (that verb is human-only; the337 dream never calls it) - report a wrong pinned fact instead of touching it.338- Moving DOWN past inbound `[[refs]]` without re-pointing them first (the engine refuses).339- Deduping only BEFORE placement (placement creates the overlap; step 8 exists for that).340- Reading a no-op off the wrong signal: chain-gated passes (CLAUDE.md reconciliation, dedup,341 placement) run EVERY dream; only counter-gated passes no-op on emptiness.342- Running CLAUDE.md reconciliation as a keyword-grep of only the newly-written entries (misses all343 pre-existing duplication; the pass is rule-by-rule over the entire chain, both directions).344- A downward or cross-tree `[[reference]]` (dangles on deletion; cross-tree is always a copy).345- Forgetting `dream_state.py done`, so the nudge keeps firing.