Solving the Memory Problem
Claude remembers, but not the way multi-repo work
Claude Code already has memory. That is not the issue. The issue is that real product work rarely stays inside one neat repository. A feature may start in repo1, spill into repo2, touch an API contract in repo3, and then come back to repo1 for the actual fix. Sometimes we know this upfront. Most of the time, we do not, unless we built the product from the ground up.
Claude Code’s native memory is useful, but it is mostly organised around the current project (cwd) or repository. That works well when your work is repo-shaped. It breaks when your work is feature-shaped.
And most meaningful software work is feature-shaped. That is the gap I am trying to solve with layered-memory.
What Claude Code already gives you
Before building anything new, it is worth being clear about what already exists. Claude Code has three different mechanisms that get grouped under “memory”.
CLAUDE.md
This is the memory file you author. It is plain markdown. You can keep instructions, project conventions, commands, architectural notes and working preferences in it. Claude loads it into context when you start a session.
The important point is this: CLAUDE.md is not really learning. It is configuration. You write it. You maintain it. It is authoritative and always loaded.
Auto Memory
Claude Code also has Auto Memory. It can record learnings by itself: build commands, debugging notes, conventions and other facts it discovers while working. This is much closer to actual memory. The useful design choice is progressive disclosure. Claude does not load every detail at startup. It keeps a lightweight index and loads detailed topic files only when needed. That part is good.
The limitation is where things get interesting: Auto Memory is organised per project (cwd) or repository. If your feature spans multiple repos, the memory gets split across multiple silos.
Transcripts / context
Every Claude Code session is saved as a transcript you can resume, but the conversation history lives only within that session. As the context window fills, response quality degrades ("context rot"), so Claude Code auto-compacts — summarising turns to free up space. That summary is lossy, and some details and decisions can get dropped along the way.
The clean mental model is:
CLAUDE.md → rules; you author
Auto Memory → facts Claude learns, mostly per repo
Transcript → session level history
Useful? Yes. Enough for multi-repo product work? Not for me.
Where it breaks
Here is the actual situation we run into regularly at work. We work on a product that spans multiple repositories. Each repo has a specific role. But features do not care about repo boundaries.
One feature may involve:
repo1 + repo2
repo1 + repo2 + repo3
repo1 only
repo2 first, then repo1 later
repo1, repo2 and a Kafka pipeline which I discover while exploring
But Claude’s native memory does not naturally think in terms of features. It thinks in terms of the current project derived from current working directory.
So the same feature ends up fragmented like this: (here read repo as cwd)
~/.claude/projects/repo1/memory/
~/.claude/projects/repo2/memory/
~/.claude/projects/repo3/memory/
We may have solved half the problem yesterday in repo2, but when we open repo1 today, that knowledge is not naturally available in the same feature context.
The memory exists. It is just in the wrong place.
There is a workaround. You can point multiple repos to one shared memory directory, or work from the base folder containing all repos. We do this when we already know a problem is going to involve multiple repositories.But that creates a different problem. Everything collapses into one shared heap. Now memories from unrelated features sit together in one flat space. You have avoided fragmentation, but created mush.
That is the core gap:
Claude Code gives you repo memory or shared memory. What I wanted was feature memory. Cross-repo, feature-organised, progressively loaded memory.
layered-memory is my attempt to solve this.
What I am building: layered-memory
Instead of keying memory only by repository, it reads what actually happened across Claude Code sessions and organises the useful parts by a theme.
A theme is a durable topic. In practice, the theme is usually a feature, a subsystem, a long-running bug, a design decision, or a recurring workflow.
The storage is deliberately boring:
~/.claude/memory/
├── index.md # lightweight (always loaded at session start)
└── themes/
├── <slug>.md # one file per theme (loaded on demand)
└── ...
Plain markdown. Readable. Editable.Portable. No mystery database. No hidden vector store. No black box.
The system has three parts:
Build — read transcripts and extract durable memory.
Reconcile — merge duplicates and clean overlaps.
Recall — load the right theme when it is useful.
Build: mine the history, not just the current repo
The build step walks through Claude Code session transcripts across repositories. It reads the actual history of work: what was tried, what broke, what got fixed, what decisions were made, which files mattered and what conventions emerged. Each transcript is distilled into durable facts and grouped by theme. This matters because a lot of useful memory does not get written down in the moment.
It appears across the shape of the whole session:
the first assumption that turned out wrong
the actual root cause
the final working fix
the file that mattered but was not obvious
the command that became reliable
the convention discovered after three failed attempts
Native memory may capture some of this. But layered-memory looks back at the full transcript after the fact and asks:
- What should survive this session?
That is the difference. It is not just jotting notes.... It is mining history....
Reconcile: keep memory coherent
Once you start building memory from many sessions, another problem appears.
Themes overlap. You get things like:
foo-plugin
foo-plugin-setup
foo-plugin-debugging
foo-plugin-tuning
They may all be the same real topic.
So layered-memory has a reconcile step.It looks across the full set of themes and merges duplicates or near-duplicates. It preserves distinct facts, removes true redundancy and keeps the theme focused.
The goal is simple:
Memory should not become a junk drawer. It should become sharper over time.
Recall: load only what matters
The final part is recall. This is where the system becomes useful inside a real Claude Code session.
At startup, Claude sees only a small index:
theme name
one-line summary
keywords
That gives Claude awareness of what memory exists without stuffing the whole past into context. When the current task matches a theme, the recall skill loads the full theme file on demand. So if I am working on an authorisation issue, Claude can load the authorisation theme. It does not need to load memories about governance workflows, plugin setup, release automation, or some old debugging session from another feature.
That is the point:
Index always. Detail only when relevant.
This mirrors the best part of Claude’s native memory, but applies it across repositories and themes rather than keeping it trapped inside repo boundaries.
What this gives me
With layered-memory, the unit of memory becomes the work itself. Not the repo. Not the folder. Not the current shell location. The work.
That means:
a feature spanning three repos can have one coherent memory
old debugging lessons can resurface in the right context
related sessions can consolidate into a single theme
memory can stay readable as markdown
context stays lean because only the relevant theme is loaded
It does not replace Claude Code’s native memory.It adds another layer on top. That is why I called it layered-memory.
What is coming next
This is just the beginning. I have already hit and solved several issues while building layered-memory. Some are still open. Some I probably have not discovered yet.
The next entries will go issue by issue.
Not theory. Actual problems from the build: what broke, what I tried, what worked, what failed and how the system improved.
This first post is the map. The rest of the series is the build log.
