[FEATURE] Hierarchical memory to prevent silent loss at 200-line MEMORY.md limit
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Claude Code's auto memory stores entries in a flat MEMORY.md index capped
at 200 lines / 25KB. When a power user accumulates enough memories, entries
at the bottom of the index are silently truncated on reload. The topic files
still exist on disk but become orphaned — Claude can't find them because their
pointers are gone.
Auto Dream consolidates entries but maintains the flat structure. It doesn't
create hierarchy or push detail into sub-indices. For users with complex,
long-running projects, the flat model hits its ceiling and memories are
quietly lost.
Proposed Solution
Replace the flat index with a self-balancing tree. When MEMORY.md exceeds
a threshold (e.g. 150 lines), entries are grouped by memory type and pushed
into category index files in an _index/ subdirectory. Each category pointer
in MEMORY.md becomes a single line with a count and summary. If a category
index also overflows, it splits further by topic keyword. The tree grows in
depth, not width — same discipline at every level.
I built this as an external tool that runs via hooks:
https://github.com/j-p-c/alzheimer
It works today with all Claude Code models (Opus, Sonnet, Haiku) and requires
no dependencies beyond Python 3.6+ stdlib. Installation is one sentence to
Claude: "Install the alzheimer memory rebalancer from github.com/j-p-c/alzheimer."
Key design points:
- Root stays small: MEMORY.md never exceeds 150 lines (headroom below the 200-line cap)
- Detail pushes down, summaries push up — Claude gets enough context from the
summary line to decide whether to read deeper
- Self-balancing via PostToolUse, SessionStart, and PreCompact hooks
- Compatible with Auto Dream (rebuilds if Dream flattens the tree)
- Configurable limits via
.alzheimer.conffor forward-compatibility - 50 tests, MIT-0 license
Why This Matters
The 200-line limit means Claude Code's memory system has a hard ceiling on
complexity. Users who rely on memory for project context, preferences, and
workflow instructions hit this wall and lose information without warning.
A hierarchical approach lifts this ceiling without requiring changes to
Claude Code itself.
The tool is MIT-0 (no attribution required) — happy for the ideas or code
to be adopted natively if useful.
12 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
You can work around the 200-line MEMORY.md limit with a UserPromptSubmit hook that loads memory from a larger index:
The hook reads memory files directly from disk — it's not limited by MEMORY.md's 200-line cap. It searches all
.mdfiles in the memory directory and injects relevant ones asadditionalContext. The individual memory files remain the source of truth; MEMORY.md becomes just one of many access paths.Thanks for flagging these. I've reviewed all three — this issue is related but not a duplicate of any of them.
#40210 reports the same underlying problem (bottom-truncation losing newest memories) but is a bug report without a solution. This issue provides a working solution.
#40245 proposes a fundamentally different architecture — merging memory and CLAUDE.md into hierarchical
summary.mdfiles inside the project folder. That's a much larger redesign of how memory works. Alzheimer works within the existing memory system, requiring no changes to Claude Code itself.#27298 is the closest — a layered memory proposal with keyword search on every prompt. The key difference is approach: #27298 bypasses MEMORY.md by searching files on every
UserPromptSubmit, adding per-prompt overhead. Alzheimer maintains the index structure so Claude's native memory loading continues to work unchanged — it just ensures the index never overflows by pushing detail into sub-indices automatically.To summarize: this is a drop-in tool that solves the truncation problem today, within the existing memory architecture, with no changes to Claude Code required. The repo is MIT-0 and the ideas are free to adopt.
@yurukusa Thanks for sharing this — clever approach to bypass the index entirely by searching files on disk at prompt time.
Alzheimer takes a different angle: instead of bypassing MEMORY.md, it keeps the index working by restructuring it into a tree before it overflows. Claude's native memory loading continues to work unchanged, and there's no per-prompt hook overhead.
Two different solutions to the same problem — yours would have been useful before we built this!
This is the problem. I built claude-brain to solve it. Full lossless capture to local SQLite, no silent loss, searchable across all projects, imports from ChatGPT and Gemini. Free and open source. github.com/mikeadolan/claude-brain
This is exactly why claude-brain uses a centralized SQLite database instead of path-dependent memory files. Your memory isn't tied to a folder location. It's stored in one local database, keyed by project prefix, searchable across all projects. Move your project folder, rename it, work from a different machine -- your memory stays intact.
If you're running into the orphaned memory problem described in #41283, claude-brain solves it. One command install, fully local, works alongside Claude Code's built-in memory. https://github.com/mikeadolan/claude-brain
@mikeadolan Interesting approach with SQLite — solves the path-dependency problem that #41283 highlights. Different trade-off from Alzheimer's file-based tree: yours centralizes storage (one DB, no orphans possible), ours keeps memory as plain markdown files that Claude's native loading can read without any additional tooling.
Both solve the core truncation problem from different angles. The more solutions people have to choose from, the better — this clearly isn't a niche issue.
Appreciate the comparison. You're right that the tradeoffs are different. Centralized SQLite means zero orphans and full search (keyword, semantic, fuzzy) across everything, but it does require the MCP server or hooks to surface context. The markdown approach has the advantage of Claude reading files natively. Both are solving a real gap. Good to see multiple approaches out there.
Heads up on a potential issue in Alzheimer's hook output routing that might affect SessionStart context delivery.
In
rebalance.py(lines 1999-2012), SessionStart content is routed tosystemMessageinstead ofhookSpecificOutput.additionalContext:After investigating the CC v2.1.90 binary, I found that for sync command hooks,
systemMessageis rendered to the user's terminal only — it does not get injected into Claude's context. The code path:systemMessage→hook_system_messageattachment type →normalizeAttachmentForAPIreturns[].However,
hookSpecificOutputwithadditionalContextdoes work for SessionStart. The Zod schema explicitly includes it:And the processing function handles it identically to PostToolUse/UserPromptSubmit:
This means glossary update instructions sent via
systemMessageon SessionStart may never reach Claude. Switching tohookSpecificOutputwithhookEventName: "SessionStart"should fix it.Our own SessionStart hook uses this exact format and it works reliably across v2.1.45 through v2.1.90:
Happy to share more details from the binary analysis if useful.
This is an outstanding catch — thank you. We've pushed the fix in 0e52c34.
The one-line change:
SessionStartandPreCompactare now routed throughhookSpecificOutput.additionalContextinstead of being folded intosystemMessage. This means glossary update instructions, update-available messages, and warning details on these events will actually reach Claude's context for the first time.Your binary analysis of the
systemMessage→normalizeAttachmentForAPI→[]path was exactly the evidence we needed to confirm the bug. We'd been attributing some intermittent "Claude didn't act on the glossary instruction" behavior to other causes — this was likely the real culprit all along.If you're interested, the relevant code is in rebalance.py lines 2001-2012. We also updated the test that was asserting the old (wrong) behavior.
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.