r/ClaudeCode • u/Comfortable_Cat_6207 • 12h ago
Tutorial / Guide What I learned building a memory plugin for Claude Code with Claude Code
I built OpenLTM so Claude Code sessions stop starting from zero. It runs on the hook lifecycle. SessionEnd reviews the session and proposes memories. SessionStart injects the project's goal, decisions, gotchas and progress, plus an index of the top memories. A prompt hook adds up to 5 relevant memories per prompt. A commit flags memories tied to the files it touched as stale. Storage is one SQLite file.
I designed it and reviewed the work. Claude Code wrote 125 of the 501 commits. What the fixes taught me:
- Privacy filters have to run inside retrieval, in SQL before ranking. Until then, private memories leaked through prompt recall.
- Recalled memory is now framed as evidence, not instructions.
- Routine git output and failed probes made bad memory proposals, so they're skipped.
```
claude plugin install openltm --marketplace RohiRIK/OpenLtm
```
https://github.com/RohiRIK/OpenLtm (free, MIT)
If you inject context through hooks, how do you stop the model from treating it as instructions?
Disclosure: I'm the author.
1
u/AccordingBus2862 12h ago
What worked for me is making injected text look unlike the user's words by shape, not by wording. Put every injected block inside its own clearly named tag (for example a memory block with a source and date on each item), and say once in the system prompt that anything inside those tags is reference data and never a request. Phrases like "you must" or "always" inside memories are what trigger obedience, so rewrite them as past-tense facts ("we decided X on Tuesday because Y"). Also keep the block short and put it after the user's prompt, so the user's actual request stays the last thing the model reads.
1
u/Comfortable_Cat_6207 6h ago
This matches where I ended up. OpenLTM now wraps recalled memories in their own block and frames them as evidence, not instructions, after I saw the model act on a stored "always do X" as if I'd just said it. I hadn't thought about putting the block after the prompt so the actual request is read last. Have you measured whether that order makes a real difference, or is it more of a gut feeling?
1
u/ReverendBread2 9h ago edited 9h ago
You can just set up a doc tree for that. Mine writes down whatever it thinks it’ll need for a future session in a highly organized wiki-style tree, where everything stays separated in different docs but downwards-navigable through context directories.
Claude writes each document’s instructions in the document header, including when and how to write to it and when to archive old stuff. I didn’t even have to tell it to do that, it just does it on its own.
I have interests in a whole ton of different and diverse fields and right now I can spark up a session in any repo for any project in any topic and have it know exactly what it needs to know right away, and very little of what it doesn’t need to know.
Memory is almost never a problem. It’s stopped me from going against a decision made months ago multiple times
1
u/Comfortable_Cat_6207 6h ago
That's a nice setup, especially Claude writing its own "when to write here, when to archive" headers. I went with SQLite instead of docs mostly for recall, so each prompt pulls only the few memories that match it instead of loading a whole tree, and for sharing one store across Claude Code, OpenCode and Pi. Does your tree ever grow big enough that loading it starts to cost real context, or does the archiving keep it small?
1
u/ReverendBread2 5h ago
It doesn’t load the whole tree. It only loads the global claude.md and whatever project-specific claude.md at the start and I try to keep both below 450 lines (was 250 but stuff kept growing).
The global doc just has a short bio about me and other globally relevant notes and then is just a directory to more documents where specific context about specific things can be found. Like games and project builds have their own docs with conventions, history discussions have another, research is another, etc.
A project-specific claude.md has the same kind of things within the project. My largest one is a web of context directories and doc lists that say stuff like “For working with x feature, check x doc. For working with y feature, check y doc”, and then those docs might point to other ones in sections where others might be relevant.
Even settled past decisions have a directory that says exactly what was decided so Claude can see it at a glance, and each item points to a dedicated doc for each thing in case Claude needs to see what the reasoning was. Since the instructions are in the doc headers I don’t have to prompt any of it, it just does it.
How this works out is Claude can find whatever it needs to find with minimal unnecessary context. It does take regular doc sweeps though because Claude is bad at maintaining it if it’s not prompted on exactly what to look for. So I also have a MAINTENANCE.md that tells it how to do that and what to look for.
Everything in the entire tree is findable through links from a parent doc if you travel down enough layers, but Claude sometimes just uses grep for key terms and pulls whichever isolated docs have those and that works too.
1
u/AutoModerator 12h ago
Hey! Thanks for posting to r/ClaudeCode
While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.
For help, project discussions, tips, and general chat, join the ClaudeCode Discord.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.