series part 1 / 3 · dated 2026-08-26
Vibrating Memory, Part 1 — Giving a Claude Agent Real Memory, Without a Database
The problem everyone runs into
If you've built a conversational agent with the Claude API — or any LLM — you've probably hit the same wall: how do you give it a memory that outlasts a single session's context window, without blowing up cost or latency?
The most common answer usually comes down to two techniques: a static system prompt, and context files reread as needed. That's a decent start, but it leaves some very concrete questions unanswered. How do you manage multiple projects and multiple clients in parallel without mixing them up? How do you avoid paying full price on every call for context that barely ever changes? How do you let the agent fetch a specific piece of information without handing it everything, all the time?
Here's the architecture built to answer those questions, inside a personal project-management assistant that tracks about fifty active files across several clients. It's called Vibrating Memory.
An origin spread across several months
The core principle — using an LLM's cache mechanism to cut the cost of rereading context — comes from earlier ground: live conversational video avatars (LiveKit, prefix caching on Groq), work that's been running since March 2026. That's where the base intuition comes from: separate what almost never changes from what changes every turn.
Turning that intuition into a unified, named architecture — designed specifically around the Claude API's explicit cache mechanism, with its cards, its letters, its maintenance rules — dates to August 26, 2026. That's the documented starting point of Vibrating Memory as a coherent system, built and versioned session after session since, entirely in text files (Markdown), with no database and no vector infrastructure.
This first part covers the foundation: the first six cards, the ones that map directly onto the Claude API's cache. Later parts will cover the broader factual cards (portrait, self-awareness, other agents, tasks, skills...) and then the system's most experimental piece: sensory and temporal memory.
Three deliberate constraints, not limitations
Before getting into the architecture, three choices deserve to be named clearly — because they're what makes the system genuinely accessible, not just elegant on paper.
No database engine. No Postgres, no vectors, no Pinecone or Chroma. All of Vibrating Memory lives in plain text files — Markdown for the cards, JSONL for event logs, raw logs for technical monitoring. This isn't a shortcut taken for lack of time — it's a deliberate choice. A text file can be read with your own eyes, fixed by hand, versioned with any tool, and above all requires no infrastructure to run, monitor, or pay for. No database server to maintain, no schema to migrate, no driver to install.
It works with popular, off-the-shelf LLMs, as long as they can follow instructions. The system depends on no exotic or proprietary capability — no fine-tuning, no purpose-built model. It rests entirely on a capability already widespread across current models: reading rules written in plain language and following them consistently. If an LLM can follow instructions, it can carry Vibrating Memory.
Everything is in natural language — no code required to run the memory itself. The cards aren't data structures for a custom parser to interpret — they're text an LLM reads and understands directly, the same way it would understand notes written by a colleague. Code only shows up at the edges — reading a file, writing one, handling the API cache — never to encode the memory logic itself.
Together, these three choices mean something simple: anyone with access to an LLM API and some file storage can reproduce this system. No need to be a multinational, no need for a data engineering team.
The core principle: separating the "engine" from the "memory"
The first distinction, and the most structural one, comes from a difference in kind between what makes the agent capable of acting intelligently — its identity, its behavior rules, the tools it has access to — and the content it operates on — facts, history, past decisions.
The first category is called A + B:
- A (Persona) — who the agent is, how it should behave, who it works with. Unlike a single generic system prompt, this block is client-specific: the agent handling client X's files doesn't have quite the same persona as the one handling client Y, even though they share a common base.
- B (Rules) — the technical rules of the memory system itself: which tools the agent has available (read a card, write one, search history), how and when to use them. This block is identical regardless of client.
A and B rarely change — which makes them excellent candidates for the Claude API's prompt caching (cache_control), which cuts read cost by roughly 90% and reduces latency as long as the content stays identical.
The second category — memory itself — breaks down into four layers, each with a different rhythm of change:
- I (Index) — a living list of what exists in the active client's long-term memory (which files, which sections within each), so the agent knows where to look without guessing. Changes occasionally.
- S (Synthesis) — a compact summary of recent activity, regenerated periodically (every 30 exchanges, for instance), capturing the essentials without accumulating raw conversational noise.
- C (Chat) — the recent conversation history, as-is. Changes every turn.
- E (Long-term memory) — detailed cards, one per project or file, never automatically injected into the prompt. The agent reaches them via a tool call, only when the topic warrants it.
Why separate I from the A+B block
A natural question: why not just fold the list of active files into the rules block (B), since B is already cached?
The answer comes down to cache mechanics: if I — which changes occasionally — were merged with B — which almost never changes — every small index update would invalidate the cache for the whole block, including the part that hadn't actually changed. By keeping them as separate cache checkpoints, a change in I doesn't affect the validity of the A+B cache.
Why I is necessary — not just "on-demand" tools
One might ask why not simply give the agent generic tools ("list the files", "search this card") and let it explore freely, with no pre-built index — which is roughly what tools like Cursor do with their rule files and code indexing.
The difference comes down to session continuity. In an environment where the conversation stays open for a long time, an earlier tool call remains visible for the rest of the session: the agent "remembers" what it discovered earlier, simply because that's part of its current context. But in an architecture where each new session can start with no guaranteed continuity from the previous one — the cache expiring after a few minutes of inactivity, for instance — an agent with no starting index is completely blind at launch: it doesn't even know a piece of information exists somewhere until it's already searched to find it. A classic chicken-and-egg problem.
The index (I) solves this: it gives the agent a map detailed enough — section titles, keywords, short summaries — to decide intelligently what to go fetch, from the very first message of a new session.
Who keeps the index up to date?
A design decision with more impact than it might seem: when the agent writes new information into a long-term memory card (E), who updates the corresponding entry in the index (I)?
Two options seem reasonable at first glance: a separate server-side process that scans the content afterward and derives an index entry, or the agent itself, which supplies the index entry in the same call that writes the content.
The second option turns out to be clearly superior, for a simple reason: at the moment the agent writes a memory section, it already has, right there in its immediate context, everything needed to summarize it correctly — the content it just wrote, the relevant keywords, why it matters. An external process scanning the text afterward would need a second call to the model to produce a summary of comparable quality — a redundant round trip, since the information was already available for free in the first call.
Concretely, that means the long-term memory write tool takes an extra parameter for the index entry, filled in by the agent itself in the same call:
write_memory_card(
project: "...",
old_text: "...", # for a targeted edit, never a full rewrite
new_text: "...",
index_entry: { # supplied by the agent, in the same call
section_id: "...",
keywords: [...],
summary: "..."
}
)
The server persisting this data doesn't need to "understand" the content or its importance — it's file-writing mechanics, nothing more.
Surgical edits, not full rewrites
Another choice with a real impact on cost and reliability: when the agent modifies a memory card, it never returns the full file. It targets a precise portion to replace — the same principle as code-editing tools (str_replace), applied to memory itself.
This avoids two problems: the growing cost of resending a file that expands over time with every small update, and the risk that a full rewrite accidentally "forgets" an existing section.
Observability: measuring what's actually being sent
A point often overlooked in tutorials: without instrumentation, it's very hard to know concretely how much each memory layer costs, on every call. A poorly understood cache system can give the illusion of being economical while silently reloading everything every time — expired cache, or a badly placed checkpoint.
The practice adopted here: log, on every response, the token count attributable to each layer separately (A, B, I, S, C, E — not one aggregated total), combining the API's native usage fields (input_tokens, cache_creation_input_tokens, cache_read_input_tokens) with a record of which tools were called during the exchange. This makes it quick to spot patterns like "the cache expires too often" or "the agent is rereading a full card every time when the index should have been enough."
In summary
| Layer | Role | Rhythm | Cached |
|---|---|---|---|
| A — Persona | Agent identity, per client | Almost never | Yes |
| B — Rules | Available tools, usage rules | Never | Yes, with A |
| I — Index | Map of available long-term memory | Occasional | Yes, separate |
| S — Synthesis | Periodic summary of activity | Periodic | No |
| C — Chat | Recent conversation history | Every turn | No |
| E — Long-term memory | Detailed cards per subject | On demand | Outside prompt |
This architecture doesn't invent a new paradigm — it sits within an already active body of research on LLM agent memory (MemGPT, Mem0, and other hierarchical memory systems). What it contributes is a concrete, proven application of the Claude API's specific cache mechanism, in a real multi-client project-management use case — not a demo prototype, a tool used daily.
And above all: no database engine, no proprietary model, no code carrying the memory logic itself — just text files and an LLM capable of following rules. That's the difference between an article explaining a concept and a system you can start building tomorrow morning.
Vibrating Memory doesn't stop at these six cards. Part 2 covers the factual cards that give the agent a portrait of who it's working with, a trace of its own learning, and a memory of the other tools and agents it interacts with. Part 3 tackles the system's most experimental ground: a sensory memory made of instant perceptions rather than accumulated facts — the concept that gives the whole system its name.
This architecture was co-designed in collaboration with Claude (Anthropic) across several working sessions, documented and versioned since its formalization on August 26, 2026.