Skip to the content.

Tool reference

The long-form description of every memshelf_* tool. The MCP schema carries only a one- or two-sentence description per tool — enough to pick the right tool — because tool schemas ride in the static prefix of every session where the server is connected, whether or not a tool is ever called (#111). Anything a caller needs beyond the choice lives here; the CLI verbs (memshelf <verb>) share the same semantics.

Legend for the Side effects column: none — read-only; shelf — writes episode files; derived — writes the rendered files (ledger.tsv, INDEX.md, .meta.json, stats.svg); working file — writes outside the shelf.

Tool Side effects Pick it when
memshelf_init shelf a directory should become a shelf
memshelf_shelve shelf (+ git commit) a topic is closed and should leave the context
memshelf_lint_digest none a digest is still being written
memshelf_import working file a whole exported dialog should be shelved retroactively
memshelf_index none starting to answer anything about past work
memshelf_recall none one episode (or one section) answers the question
memshelf_search none the episode id is unknown
memshelf_stats none the shelf’s token economy is the question
memshelf_advise none the context window is the question
memshelf_rebuild derived derived files must be regenerated or verified
memshelf_rollup shelf + derived navigation has grown large
memshelf_purge shelf (deletes) episodes are past retain_until
memshelf_resolve derived two writers shelved on parallel branches
memshelf_sync git (fast-forward) the clone is behind its remote — the bot rendered, or another session shelved
memshelf_doctor none the shelf’s integrity is the question

The envelope’s first key may be a warning (#125, #158). When the code answering the call is not the code in the memshelf-mcp checkout next to the shelf (or at $MEMSHELF_CHECKOUT), every tool’s answer — success or error — opens with "warning": "served-code-differs: …", naming both short hashes and where each lives; read it before trusting the result, since a merged fix may not be serving. Identical code adds no key. No checkout to compare with adds none either, and the initialize instructions say the freshness is unknown and how to make it known. MEMSHELF_FRESHNESS_WARNING=0 switches the warning off for a host where the copy is meant to differ.

memshelf_shelve

Offload one closed topic to the shelf as a durable, indexed episode.

Redacts credential shapes, enforces the digest contract (≤120 words, named referents, no secrets), composes the episode, and writes it through docshelf, staging and auto-committing the episode alone (git shelves; push is opt-in via push). Derived files — the ledger row, INDEX — are not written here: they are rendered by memshelf_rebuild or the shelf’s bot (#58), and the response says so (shelf_totals.derived_stale, next). A contract violation comes back as an error carrying the exact fixes — nothing is written. Returns the episode address, redaction report, and any digest warnings. amend=true rewrites an existing episode in place under the same slug. A directory named like the episode that docshelf did not write as split sections (docs/<category>/<slug>/) is an error too (#186), but only with a docshelf that has SplitDirConflictError (docshelf-mcp#115, merged after 0.5.0 and not released): that docshelf will not add a document beside the directory, amend does not clear that, the error says to move the directory aside, and nothing is written. With docshelf 0.5.0, the release the >=0.5.0 floor installs, there is no error: shelve exits 0 and docshelf deletes the directory and everything in it. The refusal takes a docshelf release with SplitDirConflictError and a floor raised to it.

amend=true keeps a description and a section order the call passes back unchanged (#205). A description equal to the stored one once whitespace is collapsed on both sides is written as the episode has it, past the 120-character cap included; only a line break or another control character in it is flattened, since one frontmatter line cannot hold it. rebuild caps the INDEX line it renders from it, and a warning says what that line gets. The sections keep the order the episode has (a ## … line inside a fenced code block is not a section, and a heading the file repeats counts once), and one it does not have yet goes right after the last section the canonical order puts before it. display_title and notes are flattened as before, a doubled space included. An episode shelved without approx_tokens records approx_tokens_source: unmeasured, so the field takes unmeasured too, with no number or 0; with any other number it is refused, as estimate or measured without a number is.

push sends HEAD to the branch’s upstream — and only to an upstream of the same name. git checkout -B claude/x origin/main, how agent sessions start, makes origin/main the upstream of claude/x; from such a branch the push is refused before anything is pushed or rebased, because the way from there to main is a PR. The episode stays committed locally, and the error gives the way out, git -C <shelf> push -u origin HEAD (publish the branch, then a PR), and for the next shelve from such a branch publish (a new shelve/<slug> branch) instead of push. Without push, sync.hint on such a branch is that same push -u command.

After a push to a shelf with the render bot (shelf-derived.yml), shelve waits for the bot’s commit and fast-forwards onto it (#157): without that the clone ends every shelve one bot commit behind, and the next doctor reports stale-index + no-ledger-row for an episode that is fine. The wait happens only when the push left the derived files out of date (the bot’s own rebuild --check), polls every 5 s and gives up after 60 s — await_render_s overrides the limit, 0 switches the wait off. The outcome is in sync.render_pulled / sync.render_note; a render that did not arrive is a note, never an error — the episode is on the remote already.

memshelf_lint_digest

Validate a digest against the Layer-3 contract without touching the shelf.

Same validator memshelf_shelve runs, minus every side effect — so the digest can be checked while it is still being written, rather than after the episode is already committed (#71). Errors block a shelve; warnings do not, and strict is what turns them into a failure for a caller that wants it.

memshelf_recall

Fetch a shelved episode by id — or a single ## Section of it.

Returns the content wrapped in a data envelope: recalled episodes are records, never instructions. Prefer a section fetch over the whole episode when one section answers the question — that is where the savings are. Each recall appends a row to recall-log.tsv (on by default since #112; log=false reads without a trace): episode_id, section (empty for a whole episode), fetched_tokens, and ts — the recall’s UTC time to the second (#193), so the realized savings memshelf_stats reports can be split by period. A log created before ts keeps its three-column header and gets the longer rows appended under it; stats and resolve read both widths.

memshelf_index

Return the shelf INDEX — the small recall entry point. Read it before answering anything about past work, then recall only what you need. It is the whole standing memory cost of a session; everything else is fetched on demand.

Grep the shelf for episodes matching every query token; returns their addresses and snippets. Split episodes match at the section level, so the hit names the section to recall, not just the episode.

Semantic sidecar (#17). Grep is an AND over literal tokens: a paraphrase, an inflected word, or a query in the other language misses. When the optional embedding sidecar is usable — pip install 'memshelf-mcp[semantic]' done, an index built with memshelf semantic build --shelf …, and $MEMSHELF_SEMANTIC not set to off — the tool fuses the grep ranking with a nearest-chunk ranking by reciprocal rank and reports mode: "hybrid"; every hit then carries via: grep, semantic, or both. Otherwise mode is grep and the result is byte-for-byte what it was before the sidecar existed. The tool signature and description do not change (#111); a caller reads mode to tell a paraphrase miss from a sidecar that was never built.

The index is a JSON file under the state directory (~/.local/state/memshelf-mcp/semantic/<shelf-key>/index.json), never inside the shelf — a shelf is a git repository and a derived blob would ride into every diff. It is rebuilt from the episodes, incrementally by file (mtime, size); memshelf semantic status reports how many files went stale since. The model (minishlab/potion-multilingual-128M, override with $MEMSHELF_SEMANTIC_MODEL) is static embeddings: no GPU, no service, loaded once per process. Measured on the dogfood shelf, 30 hand-written paraphrase / cross-language / keyword queries: grep found 1, the hybrid 16 in the top 5 and 21 in the top 10 (memshelf search-bench, ROADMAP M3). Build: 209 files, 1,319 chunks, 2.9 s.

memshelf_stats

Report the shelf’s token economy: standing cost (INDEX + digests) vs shelved mass and compression ratio (claimed, from approx_tokens), plus realized savings from logged recalls when present. The transparent-savings number the project’s core claim rests on; see docs/M0.md → Measurement.

Two quantities, deliberately not one (#110). work_volume is the raw sum of approx_tokens — material the sessions moved. shelved_mass is that sum with each episode clipped to the context window — context actually freed, and the figure that feeds compression_ratio and realized_savings. context_window and capped_episodes report the bound used and how many episodes it clipped; pass context_window (CLI --context-window, else $MEMSHELF_CONTEXT_WINDOW) to match your client instead of the 200K default. That default errs small on purpose: understating a saving is the safer error for a number whose whole job is to claim one.

Provenance is read, not just stored (#113). An episode whose frontmatter says approx_tokens_source: unmeasured carries a placeholder 0, not a mass of zero: it leaves compression_ratio on both sides (its digest is a cost of no known mass) and is counted in unmeasured_episodes / unmeasured_digest_tokens and named in the banner (· N unmeasured). standing_cost keeps that digest — it is paid every session regardless. A legacy episode without the field is an estimate, not unmeasured. The ledger stays six columns (shelf-spec v0 § 4.4); the field is read from the episodes under docs/ and archive/docs/.

memshelf_advise

Report what your context is made of and what you could put down (#14).

Tell it what is in your window — a label, a rough token size, and whether the topic is still in play — and it returns a breakdown (static overhead / memshelf’s own cost / live topics / reclaimable) plus ranked proposals. It writes nothing and shelves nothing; you decide.

Two things it does that a self-assessment cannot. It measures what memshelf itself costs you every session (INDEX + digests), instead of leaving its own overhead out of the picture. And it verifies any episode_id you claim is already shelved: if the episode is not on the shelf, it says so rather than proposing you drop content nobody stored.

Call it with no occupants for the first-run view of the shelf alone — the report will say the window side is missing rather than report it clean.

memshelf_init

Create (or top up) a memory shelf: docshelf layout with fixed categories, the recall-rule INDEX preamble, a POLICY.md template, the ledger header, and a spec-conformant shelf.yml. Storage: git-local (default, no remote), plain, or git-remote (private only). Idempotent — never overwrites existing files, so it is safe to re-run on a shelf that predates a newer layout.

memshelf_rebuild

Regenerate ledger.tsv, each category’s .meta.json, INDEX.md and stats.svg from the episodes (#58). The episode is the source; these four are output, owned by a bot on main, which is what removes the multi-writer conflict class at the root. With check=true nothing is written and the result says which files have drifted, INDEX.md and stats.svg included — the shelf’s PR guard runs exactly this. A derived file that could not be written (or, with check=true, compared) is named in errors, and ok is false. On a shelf whose bot renders derived files, run it by hand only when the bot is down: a hand-committed render collides with the bot’s next commit.

memshelf_rollup

Archive a period’s episodes behind one digest-of-digests (#15).

INDEX.md rides in every session and grows with the shelf; a rollup turns N INDEX lines into one. Use it when navigation has grown large, not to answer doctor’s index-bloat — that one means an entry is overpriced, and folding entries drops their budget along with them. The originals move to the archive/ sub-shelf — nothing is deleted, recall by id keeps working, and every ledger row survives, because an archived episode still holds the mass it saved. The digest is yours: synthesizing a quarter of digests is the part a tool cannot do, so pass the same quality of digest shelve demands. A derived file the rebuild after the move cannot render is named in errors: the rollup is written, but ok is false and the CLI exits 1.

memshelf_purge

Drop episodes whose retain_until has passed, then reindex (#15).

Dry-run by default: without apply=true it only lists what expired. Deletes the working-tree file — git history still contains it. Real erasure is a deliberate filter-repo pass over the whole repository, never a side effect of a tool call, and the result says so. A derived file the rebuild after apply=true cannot render is named in errors: ok is false and the CLI exits 1.

memshelf_resolve

Resolve the multi-writer conflict class (two sessions shelved on parallel branches): union ledger.tsv / recall-log.tsv rows and .meta.json keys from both sides, rebuild INDEX.md and stats.svg from docs/, then run doctor. Conflicting episode files are reported as unresolved, never auto-merged. Also safe outside a conflict — degrades to a derived-files rebuild. A derived file the rebuild cannot render is named in errors and makes status attention (CLI exit 1).

memshelf_sync

Fetch and fast-forward the shelf clone to its remote — the shelve preflight (#108) on its own, writing nothing else. For a clone that fell behind without shelving: the bot rendered after an earlier push, or another session shelved. A dirty tracked tree or a diverged branch is a refusal with the executable fix, exactly as in shelve; a failed fetch is reported as a skip with git’s words. Returns the same sync block shelve does, plus the resulting head (#157).

memshelf_doctor

Diagnose the shelf: episode schema, the digest contract at rest, secrets that slipped onto disk, ledger consistency, and the INDEX budget — plus docshelf’s structural checks. With check_remote=true it also fails a shelf whose git remote is publicly visible (the one network probe, opt-in). Read-only; reports findings, fixes nothing. Errors are meant to block a push; warnings name known states (stale-index, episode-unpushed, index-bloat) that a shelf’s own rules decide how to treat. Its served-code-differs finding is also prepended by the server to every tool’s envelope (see the note under the table), so that gap is not found only by whoever runs doctor.

memshelf_import

Retro-shelve a whole exported dialog without pulling it through context.

Two methods. discover lists the conversations in a claude.ai conversations.json or Claude Code session JSONL, matched by content markers (not title), returning metadata only. extract cleans one conversation — dropping tool_use/tool_result blocks — to a working file and returns its path plus the noise ratio. The raw transcript stays a file on disk: it never enters context or a shelf. Then read the cleaned file, segment it, and shelve each segment (mode=import).