Status: v0.3. Curators: rot (content), merge + split + lint (structural).
Memory accumulates faster than humans review it. The only forcing functions are /end (hand-curated at session close, biased toward what's fresh in context) and /today (morning heartbeat, biased toward today's priorities). Neither catches:
- Rot — project memories stale within days ("X submitted, awaiting approval" → false a week later)
- Cross-session patterns — same friction hit 3+ times across sessions but only captured as a memory once
- Contradictions — two memory rules giving conflicting guidance, both still indexed
- Untapped patterns — recurring session-log themes that never got promoted to memory
- Adherence drift — sessions ignoring rules they should have followed
- Shape drift — files that bundle unrelated concerns, or several files that say the same thing
The shipped curators cover rot, merge, split, and lint. Pattern, standalone contradiction, untapped-work, and audit passes below are roadmap designs rather than current capabilities.
These are LLM-shaped tasks: comparing durable memory with current evidence, contradiction detection inside lint, and structural consolidation.
The bet: compounding pattern-capture over months beats waiting for the perfect memory product. Curator file shapes (markdown + JSON proposals) stay portable even if the runner gets thrown away.
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 1: Inputs (read-only) │
│ sessions/*.md state/*.md memory/*.md git log (14d) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 2: Curator pass (prompted) │
│ /dream {curator-name} │
│ Curator prompts live in scripts/dream/prompts/ │
│ {rot, merge, split, ...}.md │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LAYER 3: Proposal artifact (write to memory git) │
│ memory/.dreams/{ISO}/ │
│ REPORT.md — human-readable summary │
│ proposals.json — machine-readable per-item diff │
│ inputs.json — what was fed in (reproducibility) │
│ Committed to memory git on creation. │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ APPLY: separate command, gated on human review │
│ /dream-apply {ISO-timestamp} │
│ Walks proposals.json, asks accept/reject/edit per item, │
│ applies accepted to memory files, commits in memory git. │
└─────────────────────────────────────────────────────────────────┘
- No separate API key. The curator runs inside the existing Claude Code session — same model, same auth.
- Easier prompt iteration. Curator prompts are markdown files; tweak one, run again, no redeploy.
- Structured-tool access.
AskUserQuestionfor the apply step gives a real review UI rather than terminal Y/N.
Tradeoff: can't run truly unattended without a headless run. See Automation below.
Three load-bearing benefits once a curator writes proposal artifacts:
- Diff before/after. "What changed in this dream pass" is the most-asked question after every run.
- Revert path. A bad accept-all on
/dream-applyis onegit revertaway. - Migration insurance.
cp -r memory/ <new machine>+git logkeeps the full history.
Local-only repo. No remote. Memory often contains personal or confidential context. For backup, see Backup & recovery below — snapshot to a private location, do not add a hosted remote.
<configured-memory-directory>/
├── .git/ ← local-only repo
├── MEMORY.md ← index (cap 100 lines)
├── ARCHIVE.md ← tombstone rows, one per retired file
├── {topic}.md ← LIVE detail files only
├── archive/ ← retired files, moved here on archive
│ └── {topic}.md ← each stamped `archived: YYYY-MM-DD` in frontmatter
└── .dreams/ ← curator artifacts
└── {ISO-timestamp}/
├── REPORT.md ← human review surface
├── proposals.json ← machine apply surface
└── inputs.json ← reproducibility
Every proposal has id, action, reasoning, evidence (array, never empty), confidence. The rest varies by curator class:
- Content curators (
rot):target,current_excerpt,proposed_excerpt. Actions:modify,archive,add,flag. merge(structural):targets[],survivor,merged_body,index_changes,archive_tombstones,net_index_lines.split(structural):target,result_files[],original_index_line.
Apply step honors confidence: high defaults to accept, medium shows full diff, low requires explicit edit.
Curators fall into two classes:
- Content curators ask "is this memory still true?" — they compare memory against the world (state files, sessions, commits).
rot,pattern,contradiction,audit. - Structural curators ask "is this memory well-shaped?" — they examine the shape of the memory set itself (detail files + the
MEMORY.mdindex) and read no state or session files (lint adds only read-only existence probes and an optional work-repogit log).merge,split,lint.
Question: "For each project-type memory entry, does it still match the current state of the world?"
Inputs: memory/project_*.md + state/{decisions,blockers,current}.md + git log --since=14.days.ago.
Output actions: modify, archive, flag.
Why first: Easiest objective spec. Lowest false-positive cost ("no, this is still true" is cheap to dismiss). Runs against existing data, proves substrate value on day 1.
Questions: merge — "Do 2+ memories cover the same thing and always get recalled together?" split — "Has one file accreted 2+ unrelated concerns?"
Inputs: memory/*.md (live detail files only — memory/archive/** is excluded) + memory/MEMORY.md (index) + memory/ARCHIVE.md. No state/session inputs.
Output actions: merge (consolidate targets → survivor, write ARCHIVE tombstones, collapse index lines), split (divide target → result_files, expand index lines), flag (boundary is a judgment call).
Why second: MEMORY.md drifts over its 100-line / loaded-budget cap; merge is the direct pressure-relief, and split enforces one-fact-per-file. Structural ops touch many files at once, so they lean hard on the git-revert safety net and human review. Guiding principle: Focus Over Coverage — never produce vaguer files just to hit a number; merge and split are opposing forces and a good pass leaves the other nothing to undo.
Question: "Is the store well-formed and internally consistent — index and files in agreement, no duplicates, no contradictions, no half-finished archives?"
Inputs: memory/*.md + memory/MEMORY.md + memory/ARCHIVE.md (live root only — memory/archive/** excluded), plus cheap read-only existence checks (ls, test -e, git ls-files) for local paths memories name, and optionally git log --oneline -30 when run inside a work repo. No state/session inputs, no URL fetches — it runs standalone against any memory directory, which makes it the right first pass on an inherited or long-uncurated store.
Output actions: modify, archive, flag (content-curator proposal shape plus a check field naming which of its ten checks fired: index drift, unresolved links, pattern-level staleness, duplicates, contradictions, unverifiable references, type misfiles, index-only content, duplicate archive rows, build-log bloat).
Why third: rot compares memory against the world; lint catches the store drifting against itself — the class rot structurally cannot see. Sharpest case: a type misfile, where a project status filed as feedback escapes every rot pass because rot audits project/reference hardest. Ported from agent-memory-kit prompts/lint.md at 1bd9a14, where it was capability the publication node had and the core lacked.
Question: "What recurring frictions in the last 14 days of sessions don't have a memory entry yet?"
Output actions: add (new memory candidate). Required-evidence floor: must appear in 3+ sessions to propose.
Question: "Does memory contain rules that give conflicting guidance for the same situation?"
Output actions: flag (always — never auto-resolve a contradiction; surface to the user).
Question: "What recurring themes in session logs have never been raised into memory or a skill?"
Output actions: flag.
Question: "Did sessions in the last 7 days follow the rules in MEMORY.md?"
Risk: Memory rules aren't structured enough to mechanically check adherence. May produce noise. Hold until untapped ships.
- No skill generation. Skills stay manual via
/skill-creator(or your own equivalent). - No autonomous apply. Review gate stays. Maybe never removed for high-stakes scopes.
- No vector store / SQLite / FTS. Plain markdown + JSON. Smallest substrate that works.
The curator never auto-applies, so automating the propose step is safe; apply stays human-gated.
- Passive nudge. A
SessionStarthook that computes days since the last.dreams/artifact and prints a one-line reminder when memory is stale-curated. It surfaces; it never runs a curator (hooks can't invoke Claude). - Active unattended. Schedule a headless run on your platform's scheduler. Two non-obvious gotchas:
- Headless can't run slash commands.
claude -p "/dream rot"treats the slash command as literal text — print mode is non-interactive. Pass a plain prompt that points Claude at.claude/commands/dream.md(the command file is itself the step-by-step spec). - Permission posture. Run with
--permission-mode dontAskplus an--allowedToolsallowlist that includes theBashtool wholesale — the command issues compound shell commands (TS=$(date ...),git add && git commit) that prefix-pattern allowlists (Bash(git:*)) can't match, so a narrow list makes the run flail on denials.dontAskstill denies every non-shell tool. Never usebypassPermissionsfor an unattended loop.
- Collision guard. Gate the run so it doesn't fire while an interactive session is writing the same memory git (e.g. skip if another Claude process is running). A pass over a few dozen memories can take ~15 minutes.
- Headless can't run slash commands.
Three distinct failure modes; only one needs new infra.
-
Failure to forget (the inverse of the two below) — an
archivethat writes the tombstone row and stops. The file stays in the memory root, unstamped and unchanged, so every later session reads it as a live memory. Git backups do not help, because nothing was lost: the corpus is quietly asserting stale things as current. The tell is a curator proposing to archive something that was archived weeks ago — it has no way to see the earlier row.Fix it structurally, not by discipline: archiving is stamp + move to
archive/+ inbound-link rewrite, and the apply step refuses to re-archive a file already carrying anarchived:stamp. The refusal is the tripwire.Same root cause, adjacent gap: a
splitthat removes its target without writing a tombstone deletes a memory silently, and leaves any live file that linked the old slug pointing at nothing. -
Mistaken forgetting (a bad
merge/split/archivedrops a fact) — already covered by memory git. Every/dream-applycommits before it changes anything, and structural ops usegit rm(not destructive deletion), so absorbed/split-away content stays in history. Recovery isgit revert HEADorgit show HEAD~N:<file>. -
Machine loss — local git can't help; you need an off-machine copy. Keep the no-remote rule (memory may hold confidential context) and use a
git bundleinstead of a hosted remote:git bundle create memory-<date>.bundle --allproduces one restorable file (git clone <bundle> memory) you copy to private storage. Cadence: periodic, or after a large/dream-apply.
| Risk | Mitigation |
|---|---|
| Curator hallucinates rot that's actually current | Required evidence array — every claim cites a state-file line or commit. Apply rejects empty-evidence proposals. |
| Apply step accept-all destroys good memories | Git on memory dir → revert is one command. Apply shows full diff before each accept. Structural ops use git rm, never destructive delete. |
| Memory + state files drift apart over time | Curator reads both each pass; rot detector specifically cross-references them. |
Confidential memory leaks via accidental git push |
No remote configured. Optionally a pre-commit hook on memory git that refuses if any remote is added. |
- Should
state/decisions.mdever be a curator write target? Currently read-only. - Should the curator propose
CLAUDE.mdchanges when a feedback rule validates 3+ times? Promotion changes Claude's default behavior — high-leverage and high-risk. - Multi-repo curators? Same substrate could run against any project's
state/+memory/.
| Path | Role |
|---|---|
docs/dream-architecture.md |
This file. |
scripts/dream/README.md |
How to use, how to add curators. |
scripts/dream/prompts/rot.md |
Rot-detector prompt body (content class). |
scripts/dream/prompts/merge.md |
Merge curator prompt body (structural class). |
scripts/dream/prompts/split.md |
Split curator prompt body (structural class). |
.claude/commands/dream.md |
/dream {curator} slash command. Default: rot. |
.claude/commands/dream-apply.md |
/dream-apply {timestamp} slash command. |
<configured-memory-directory>/.git/ |
Local-only repo for memory dir. Run git init there on first use. |
<configured-memory-directory>/.dreams/ |
Per-pass artifacts. Tracked. |