Working memory for AI agents: digest-indexed episodes on a git shelf, recalled a section at a time.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Put your agent's memory on a shelf, hand it the index.
Long-running agent sessions burn tokens re-sending history and lose detail to lossy auto-compaction. memshelf applies the docshelf pattern β tiny index in context, bodies fetched on demand β to the agent's own working memory:
INDEX.md (kilobytes) + digests in context and
recalls exact sections via INDEX β episode β section slice over MCP.Positioning in one sentence: claude-mem's loop, git's substrate, docshelf's navigation β episodic memory you can grep, diff, review, and carry between hosts. Private and local by default: the standard storage mode is a local git repo with no remote configured. The tool is public; the memory never is.
One week of dogfooding on the live shelf β full numbers and methodology in
docs/demo.md:
| Measure | Result |
|---|---|
| Episodes on the shelf | 34 |
| Standing cost in every session (INDEX + digests) | ~8.6K tokens |
| Shelved mass those episodes replace | ~1.9M tokens β β220 : 1 |
| One question answered from memory | ~1.8K tokens (INDEX + one episode) |
| Recall test: fresh agent, INDEX path only | 5 / 5 β zero misses, zero over-fetch |
Tokens are counted as chars/4 everywhere, so the ratios are estimator-independent; absolute counts move with the tokenizer.
As an MCP server:
As a Claude Desktop extension β adapters/claude-desktop/:
an .mcpb bundle installed from Settings β Extensions, with a Default
shelf setting so calls need not repeat the path. Nothing has to be installed
alongside it β not even Python.
As a Claude Code plugin β adapters/claude-code/:
a /shelve skill plus SessionStart / SessionEnd / PreCompact hooks.
Or from the shell (pip install memshelf-mcp, Python β₯ 3.10) β the same
loop, no MCP:
One verb per job; the same names over MCP (memshelf_*) and in the CLI
(long-form descriptions: docs/tools.md):
| Tool | What it does |
|---|---|
init | Create (or top up) a memory shelf: docshelf layout, fixed categories |
shelve | Offload one closed topic as a durable, indexed episode; --amend rewrites in place |
lint_digest | Validate a digest against the contract without touching the shelf |
import | Retro-shelve a whole exported dialog without pulling it through context |
index | Return the shelf INDEX β the small recall entry point |
recall | Fetch an episode by id, or a single ## Section of it |
search | Grep the shelf; returns matching episodes |
stats | The shelf's token economy: standing cost vs shelved mass, claimed vs realized |
advise | What your context is made of and what you could put down β proposals only |
rebuild | Regenerate every derived file from the episodes |
rollup | Archive a period behind one digest-of-digests |
purge | Drop episodes past retain_until, then reindex β dry run by default |
resolve | Settle multi-writer conflicts: regenerate derived, union the recall log |
doctor | Diagnose: episode schema, digest contract at rest, secret shapes, index bloat |
prune-splits | CLI only β remove H2 split directories git never got (migration for #109) |
The digest is a contract, not a convention. It is the only thing read at
recall before fetching a body, so a weak one devalues the whole episode.
lint_digest runs the same validator as shelve with no side effects
(--strict turns warnings into failures); errors block a shelve, warnings do
not β a pure reference digest legitimately carries no decision marker. A
rejected digest is a feature: the tool prints exactly what to fix and writes
nothing.
--amend re-runs the whole pipeline β redaction, the digest contract,
composition β so an amended episode is exactly as guarded as a fresh one,
which a hand-edit of the file never is. Amending a slug that is not on the
shelf is an error, not a create.
The episode is the source; everything else is output. ledger.tsv,
INDEX.md, stats.svg and each category's .meta.json are derived:
shelve writes and commits the episode alone, rebuild renders the rest β
delete all four and rebuild restores them byte-identically. That is what
makes two sessions shelving in parallel a non-event: the merge is clean by
construction. On a shared shelf, let a bot own the derived files on main β
ready-to-copy workflows in adapters/shelf-repo/;
rebuild --adopt migrates an older shelf once, rebuild --check is the
CI guard.
Two consequences worth stating plainly, because getting them wrong costs a merge conflict:
doctor reports no-ledger-row and stale-index immediately after a
correct shelve β on every branch, main included. Nothing is broken:
the episode is written, the derived files are not rendered yet. They clear on
the next rebuild β the bot's run, on a shelf that has one.ledger.tsv/INDEX.md/stats.svg meets the bot's, and the merge stops
being clean by construction. Wait for the renderer; on a shelf without a bot,
run memshelf rebuild --shelf . as its own step.If those warnings persist for a day while episodes keep arriving, that is a
different state β the renderer is not lagging, it is stopped β and doctor
says so separately, as derived-stale at error severity. The day is counted
from when the renderer could first see the work, not from the ledger's last
commit: an episode pushed minutes ago onto a shelf whose ledger has not moved
since yesterday says nothing about the renderer, and saying otherwise sent
readers to a manual rebuild, which is the conflict this whole split exists
to avoid.
That arrival is read from this clone's reflog for the tracked upstream β the
one local record of when the ref moved here. A commit date is not a
substitute: it says when the episode was written, and Β«shelve now, push when
confirmedΒ» is a documented way to work, so the two can be a working day apart.
Where the reflog cannot say β a fresh clone starts an empty one, which is what
CI and ephemeral agent sessions run in β doctor reports
renderer-wait-unknown at the unknown level instead of picking a verdict:
from there, Β«stoppedΒ» and Β«handed the work a minute agoΒ» look the same, and
the renderer has to be judged where it can be observed, on its own job's run.
On a shelf with no upstream there is no renderer to be fair to, and the
ledger's own age stays the clock.
There was a third way to hold stale-index forever, and it is fixed rather
than documented: docshelf split any episode past 50 KiB into section files
beside it, shelve committed the episode alone, and from then on this working
copy rendered an INDEX no other checkout could produce β no rebuild could
clear it, and search answered with addresses that existed on one machine
(#109). shelve no longer splits. A shelf that already carries such
directories keeps reporting them as local-split-dir until
memshelf prune-splits --shelf . --apply removes them; the episode file holds
every section, so nothing is lost. It is a dry run without --apply, and a
split directory that is committed is reported and left alone.
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/memshelf-mcp)<a href="https://allmcps.com/mcp/memshelf-mcp"><img src="https://allmcps.com/api/badge/memshelf-mcp?style=directory" alt="Memshelf MCP on AllMCPs" /></a>