This is the full developer documentation for memtomem # Installation > Detailed installation guide for memtomem and memtomem-stm. ## Requirements [Section titled “Requirements”](#requirements) * **Python 3.12+** * **pip**, **uv**, or **pipx** * An embedding provider for semantic search — pick one during `mm init` (see [Embedding Providers](#embedding-providers) below). Fine to skip at first: memtomem works keyword-only until you choose. ## LTM Server (memtomem) [Section titled “LTM Server (memtomem)”](#ltm-server-memtomem) * uv (recommended) ```bash uv tool install 'memtomem[all]' ``` * pipx ```bash pipx install 'memtomem[all]' ``` * pip ```bash pip install 'memtomem[all]' ``` `[all]` is the recommended first install because it matches the main docs: ONNX dense embeddings, Korean tokenizer, Ollama / OpenAI providers, code chunking, the Web UI, Langfuse tracing, and LangGraph Store adapters. For a leaner footprint, drop the extras for a BM25-only install: ```bash uv tool install memtomem # no extras — dense search, Web UI, Korean tokenizer unavailable until added ``` Opt into features later with e.g. `uv tool install --reinstall 'memtomem[onnx,web]'`. After installing, verify the binary and upgrade with refreshed package metadata if the version looks stale: ```bash mm --version uv tool install 'memtomem[all]' --refresh ``` ### Optional extras [Section titled “Optional extras”](#optional-extras) The extras below are what `[all]` bundles — install them individually when you want a narrower footprint. | Extra | Description | Command | | ----------- | ------------------------------------------------ | --------------------------------- | | `onnx` | fastembed local embeddings (recommended default) | `pip install memtomem[onnx]` | | `ollama` | Ollama provider client | `pip install memtomem[ollama]` | | `openai` | OpenAI provider client | `pip install memtomem[openai]` | | `korean` | kiwipiepy Korean morphological analysis | `pip install memtomem[korean]` | | `code` | tree-sitter AST chunking (Python / JS / TS) | `pip install memtomem[code]` | | `web` | FastAPI + uvicorn Web UI | `pip install memtomem[web]` | | `langfuse` | Langfuse observability tracing | `pip install memtomem[langfuse]` | | `langgraph` | `MemtomemStore` and `MemtomemBaseStore` adapters | `pip install memtomem[langgraph]` | | `all` | Everything | `pip install memtomem[all]` | ### `mm` CLI [Section titled “mm CLI”](#mm-cli) After installation, the commands you’ll reach for most often: | Command | Purpose | | ----------------------------- | ------------------------------------------------- | | `mm init` | Interactive setup wizard | | `mm status` | Post-install DB / config / embedding health check | | `mm search ` | Search the knowledge base | | `mm add ` | Add a memory entry | | `mm web` | Launch Web UI dashboard () | | `mm --version` · `mm version` | Print installed version | Full command list (including `ingest`, `session`, `context`, `wiki`, `watchdog`, `schedule`, `tags`, `upgrade`, `uninstall`): see the [CLI Reference](/ltm/cli/). The MCP server itself ships as the `memtomem-server` console script. You don’t run it by hand — your MCP client (Claude Desktop, Claude Code, Cursor, etc.) launches it automatically once `memtomem` is registered in the client’s MCP config. For copy-paste `mcpServers` JSON per client, see [Quick Start → Connect Your MCP Client](/guides/quickstart/#4-connect-your-mcp-client). ### File locations [Section titled “File locations”](#file-locations) memtomem keeps everything under your home directory — nothing leaves the machine: | Path | What | | -------------------------- | -------------------------------------- | | `~/.memtomem/memtomem.db` | SQLite store (chunks + vectors) | | `~/.memtomem/config.json` | LTM configuration written by `mm init` | | `~/.memtomem/logs/web.log` | Web UI log (from `mm web -b`) | Override the config directory with the `MEMTOMEM_*` env vars (see [Configuration](/reference/configuration/)). ## STM Proxy (memtomem-stm) [Section titled “STM Proxy (memtomem-stm)”](#stm-proxy-memtomem-stm) STM is optional. Install it after the LTM quick-start flow works if you want proactive memory surfacing (presenting relevant memories) or tool-response compression. * uv (recommended) ```bash uv tool install memtomem-stm ``` * pipx ```bash pipx install memtomem-stm ``` * pip ```bash pip install memtomem-stm ``` * uvx (no install) ```bash uvx memtomem-stm --help ``` For ad-hoc execution only — use `uv tool install` or another tab for a permanent install with client registration. ### Optional extras [Section titled “Optional extras”](#optional-extras-1) | Extra | Description | Command | | ----------- | ------------------------------ | ------------------------------------- | | `langfuse` | Langfuse observability tracing | `pip install memtomem-stm[langfuse]` | | `langchain` | LangChain agent integration | `pip install memtomem-stm[langchain]` | ### `mms` CLI [Section titled “mms CLI”](#mms-cli) After installation, the following commands are available: | Command | Purpose | | -------------------------------- | ---------------------------------------------------------------------------- | | `mms init --mcp claude` | First-time setup + auto-register with Claude Code | | `mms add --command ` | Register an upstream MCP server | | `mms add --from-clients` | Bulk-import upstreams from existing MCP client configs | | `mms eject ` | Restore an imported server to its original client and unregister it from STM | | `mms list` | List registered servers (with a SURFACING column) | | `mms status` | Config summary — enabled flag and server count | | `mms health` | Probe upstream connectivity + LTM surfacing readiness | | `mms --version` | Print installed version | The STM proxy itself ships as the `memtomem-stm` console script. As with LTM, you don’t launch it by hand — once STM is registered with your MCP client (via `mms init --mcp claude`, `mms register`, or a `.mcp.json` entry), the client starts it automatically. STM writes its proxy config to `~/.memtomem/stm_proxy.json`; `mms add` / `mms init` manage it for you, so you rarely hand-edit it. ## Embedding Providers [Section titled “Embedding Providers”](#embedding-providers) | Provider | Setup | GPU | Cost | | -------------------- | ------------------------------ | ------------ | ---- | | **ONNX** (fastembed) | Built-in | Not required | Free | | **Ollama** | `ollama pull nomic-embed-text` | Not required | Free | | **OpenAI** | API key required | — | Paid | **Not sure which to pick?** Start with **ONNX** — it’s fully local, free, and needs no extra daemon or API key. You can always switch later by re-running `mm init` or setting `MEMTOMEM_EMBEDDING__PROVIDER` (note the double underscore — nested pydantic-settings keys use `__` as delimiter). ## Tech Stack [Section titled “Tech Stack”](#tech-stack) | Category | Technology | | ------------- | ---------------------------------------------------------- | | MCP | FastMCP (stdio, SSE, Streamable HTTP) | | Framework | Pydantic v2, Click (CLI), FastAPI (Web UI) | | Database | SQLite (FTS5 full-text search), sqlite-vec (vector search) | | Code parsing | tree-sitter (Python, JS, TS AST) | | Korean | kiwipiepy morphological analyzer (optional) | | Observability | Langfuse (optional) | # Memory Persistence Across Sessions > Store a memory in one session and recall it in the next — the core memtomem flow, in under 5 minutes. AI agents lose all context the moment you close a session. With memtomem connected, anything you tell your agent to remember is **persisted to disk** and retrievable from any future session — or any other MCP-connected agent. This tutorial walks through that flow end-to-end. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) Complete [Quick Start](/guides/quickstart/) so `memtomem` is installed, initialized, and registered with your MCP client (Claude Code, Cursor, Claude Desktop, …). ## Session A: Save a Memory [Section titled “Session A: Save a Memory”](#session-a-save-a-memory) In your first agent session, say in plain language: > **“Remember this: our team paused the migration this quarter. Reason: waiting on legal review.”** The agent calls `mem_add` under the hood and returns a confirmation with the namespace and memory ID. To verify from the CLI: ```bash mm search "migration paused" ``` The entry you just saved should appear at the top. You can also run `mm web` to browse the dashboard visually. ## End the Session [Section titled “End the Session”](#end-the-session) Close the agent completely. For Claude Code, exit the terminal; for Claude Desktop, quit the app. The memtomem server itself re-launches automatically on the next tool call — no manual restart needed. ## Session B: Recall the Memory [Section titled “Session B: Recall the Memory”](#session-b-recall-the-memory) Start a fresh session and ask: > **“What’s our team’s migration status? I think we discussed it in an earlier session.”** Guided by the MCP tool descriptions, the agent calls `mem_search` and surfaces the entry from Session A — including the “waiting on legal review” reason. ## What Just Happened [Section titled “What Just Happened”](#what-just-happened) ```plaintext Session A: agent → mem_add("migration paused, legal review") → SQLite (BM25 FTS5 index + vector index written together) Session B: agent → mem_search("migration status") → hybrid search → same chunk ranked at top ``` Storage and retrieval both run against your local SQLite — no cross-session sync step is required. For how the search engine ranks results, see [Hybrid Search](/ltm/hybrid-search/). ## Common Pitfalls [Section titled “Common Pitfalls”](#common-pitfalls) * **Agent doesn’t call `mem_search`.** Phrase the question so it’s clearly about past context — “earlier”, “previously saved”, “you remembered that …” — to nudge the tool call. * **Empty results.** Run `mm status` to confirm the server connection and namespace list. Session A and Session B may be using different namespaces; the default is whatever `mm init` set. ## Next Steps [Section titled “Next Steps”](#next-steps) * [Hybrid Search](/ltm/hybrid-search/) — how to tune search when results don’t land * [STM Overview](/stm/overview/) — if you want memories injected without even having to ask, add the STM proxy. Adopting it is reversible (`mms eject` restores your original host MCP config). * [Multi-Agent Collaboration](/ltm/multi-agent/) — namespace design for sharing memory across several agents # Local-First & Privacy > How memtomem keeps your data on your machine and protects secrets — fully local, 0600 file permissions, automatic secret detection, and query privacy. By default, memtomem sends your memory data nowhere. Storage, embedding, search, and reranking all run on your machine, and content that looks like a secret is filtered out automatically at the cache, index, and share boundaries. ## Fully Local [Section titled “Fully Local”](#fully-local) * **Storage** — The default store is local SQLite (`~/.memtomem/`). No network port is exposed. * **Embeddings** — Embeddings run locally via the built-in ONNX (fastembed) provider. No GPU, no external API, no cloud, and no cost. (Ollama and OpenAI providers are optional.) * **Reranking** — When you enable reranking, the default provider is local ONNX (fastembed) — no external API required. * **STM proxy** — STM speaks stdio to your AI client; the proxy server itself opens no network port. Persisted stores — the response cache, metrics, and feedback — are all local-only SQLite files under `~/.memtomem/`, never remote or shared across hosts. * **No account** — It works without any login or sign-up. * **The one exception** — Content leaves your machine only if you opt into an external provider: OpenAI/Ollama embeddings or reranking, or an external LLM compression/extraction path in STM. On STM’s external-LLM path, `privacy_scan_enabled` (default on) scans for credentials before the outbound call and skips it on a hit; turning it off sends raw responses unscanned (the server logs a startup warning). ## Filesystem Protection [Section titled “Filesystem Protection”](#filesystem-protection) The data directory (`~/.memtomem/`) is created with `0o700` permissions and its files are written `0o600` (owner read/write only). Separately, the runtime directory that holds the server’s pid/lock files (`$XDG_RUNTIME_DIR/memtomem`, or `/tmp/memtomem-`) is created `0o700` and startup refuses it if group/other access has been left open. ## Secret Protection [Section titled “Secret Protection”](#secret-protection) memtomem blocks credential-, token-, and key-shaped content from flowing into your stores or wider scopes at several points. * **STM sensitive-content detection** — Responses containing patterns that look like secrets (e.g. `sk-…`, `ghp_…`, AWS `AKIA…`, JWTs, `BEGIN … PRIVATE KEY`) are excluded from the response cache and from being indexed into LTM. * **Indexing credential exclusion** — LTM indexing applies a built-in credential denylist (`oauth_creds.json`, `credentials*`, `id_rsa*`, `*.pem`, `*.key`, `.ssh/**`, …). A user `!negation` pattern cannot re-enable these built-in patterns. * **Re-scan on share** — When `mem_agent_share` copies a memory into a wider namespace, the redaction guard re-scans it, and secret-looking content is blocked at share time. * **Context Gateway** — Writing or moving to the `project_shared` tier (git-tracked) hard-refuses on a detected secret, with no `--force` valve (git history is permanent). The `user` and `project_local` tiers allow an override after review. ## Query Privacy (STM Surfacing) [Section titled “Query Privacy (STM Surfacing)”](#query-privacy-stm-surfacing) STM surfacing extracts a query from each tool call to search LTM. You control how that query text is retained. * `MEMTOMEM_STM_SURFACING__PERSIST_QUERY_TEXT=false` — Store a `sha256:<16-hex>` digest instead of the raw text. * `MEMTOMEM_STM_SURFACING__QUERY_RETENTION_DAYS` (default `30`) — Clear raw query text retained in the feedback DB after the given number of days. * Sensitive content (credentials, PII) is always hashed before persistence, regardless of the setting. * **Write-tool skip** — Surfacing is automatically disabled for upstream tools that mutate state. ## No Lock-In [Section titled “No Lock-In”](#no-lock-in) STM imports your existing MCP servers and proxies them in front — but the move is reversible. `mms eject` restores an imported server to its original host MCP client config, and only removes the STM entry once the restore is verified. ## Trust Boundary & Best Practices [Section titled “Trust Boundary & Best Practices”](#trust-boundary--best-practices) * STM trusts your local AI client and the upstream MCP servers you configure. **Only proxy upstreams you trust.** * The optional surfacing daemon binds to loopback (`127.0.0.1`) and authenticates with a per-start random token. Do not point `MEMTOMEM_STM_DAEMON__HOST` at a non-loopback address. * The LTM web UI (`mm web`) binds to `127.0.0.1` by default. * Report vulnerabilities via [GitHub security advisory](https://github.com/memtomem/memtomem/security/advisories/new) or — not public issues. ## Related [Section titled “Related”](#related) * [Environment Variables](/reference/configuration/) — full privacy-related settings * [Proactive Surfacing](/stm/surfacing/) — query privacy and gating * [Context Gateway](/ltm/context-gateway/) — per-tier secret blocking * [Multi-Agent Collaboration](/ltm/multi-agent/) — redaction on share # Quick Start > Install memtomem and verify a searchable memory before connecting an MCP client. This path gets one thing working first: install the LTM server, run setup, save one memory, and find it again from the CLI. That proof needs neither an existing notes directory nor a connected editor. Connect an MCP client and index existing files only after the basic memory loop works. STM is optional. ## 1. Install [Section titled “1. Install”](#1-install) ```bash uv tool install 'memtomem[all]' # or: pipx install 'memtomem[all]' mm --version ``` `[all]` includes the Web UI, local ONNX embeddings, code chunking, Korean tokenizer support, Ollama / OpenAI clients, Langfuse, and LangGraph adapters. For a smaller BM25-only install, see [Installation](/guides/installation/#ltm-server-memtomem). If `mm --version` prints an older version right after install, upgrade with refreshed package metadata: ```bash uv tool install 'memtomem[all]' --refresh ``` If the shell can’t find `mm` at all (`command not found`), run `uv tool update-shell` and reopen the terminal — see [Troubleshooting](/guides/troubleshooting/). ## 2. Run Setup [Section titled “2. Run Setup”](#2-run-setup) ```bash mm init ``` The `mm init` wizard starts with a preset picker: | Preset | Best for | What it does | | ------- | ---------------------------------- | --------------------------------------------------- | | Minimal | First smoke test, smallest install | BM25 keyword search only | | English | Most English projects | Local ONNX embeddings + English reranker | | Korean | Korean or multilingual notes | Multilingual embeddings, reranker, Korean tokenizer | Choose **Minimal** for the fastest no-model-download first proof. You can rerun `mm init` later to add semantic search. For scripts or CI: ```bash mm init --non-interactive # minimal preset, no prompts mm init --preset english --non-interactive # English preset, no prompts mm init --preset korean --non-interactive # Korean preset, no prompts mm init --advanced # full wizard ``` During setup you can also register existing AI-agent memory folders for watching, such as Claude Code memories, Claude plans, or Codex CLI memories. Registration only sets them up for future watching; seed existing files once with `mm index`. At the end, the `mm init` wizard offers to auto-register memtomem with your MCP client (e.g. Claude Code). Accept it and Step 4 is already done — you’ll only need the manual steps below if you skip this prompt. []() ## 3. Verify a Memory Round Trip [Section titled “3. Verify a Memory Round Trip”](#3-verify-a-memory-round-trip) First confirm the CLI can open the config and database: ```bash mm status ``` Zero chunks is normal. Now create and find one controlled memory without depending on an existing folder or agent: ```bash mm add "Deployment checklist uses blue-green rollout" --tags ops mm search "blue-green" ``` The search should return the sentence you just added. `mm add` writes to the configured user memory directory and indexes the entry immediately. ## 4. Connect Your MCP Client [Section titled “4. Connect Your MCP Client”](#4-connect-your-mcp-client) * Claude Code If you picked “auto-register with Claude Code” in the `mm init` wizard, LTM (`memtomem-server`) is already registered — no extra LTM command needed. For a manual registration (skipped the wizard prompt, or moved to a new machine): ```bash claude mcp add memtomem -s user -- memtomem-server ``` * Cursor Add the server to `~/.cursor/mcp.json`: ```json { "mcpServers": { "memtomem": { "command": "uvx", "args": ["--from", "memtomem", "memtomem-server"] } } } ``` The command must be `memtomem-server` — plain `memtomem` is the CLI and will not start the MCP server. * Windsurf Add the server to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "memtomem": { "command": "uvx", "args": ["--from", "memtomem", "memtomem-server"] } } } ``` The command must be `memtomem-server` — plain `memtomem` is the CLI and will not start the MCP server. * Claude Desktop Add the server to your config file (macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows `%APPDATA%\Claude\claude_desktop_config.json`), then restart Claude Desktop: ```json { "mcpServers": { "memtomem": { "command": "uvx", "args": ["--from", "memtomem", "memtomem-server"] } } } ``` For other clients and the full option matrix, see [MCP Client Setup](https://github.com/memtomem/memtomem/blob/main/docs/guides/mcp-clients.md). Ask your agent to “call `mem_status`” after registration. That verifies the MCP client is launching the same server your terminal sees. If the agent reports no memtomem tools, see [Troubleshooting](/guides/troubleshooting/). []() ## 5. Index Existing Notes [Section titled “5. Index Existing Notes”](#5-index-existing-notes) Once the controlled round trip works, index a directory that actually exists: ```bash mm index ~/notes mm index ~/projects/my-app/docs ``` Replace these examples with your real paths, then search for a phrase you already know appears in those files. After that, use natural language in your MCP client: | Tell your agent | Tool usually called | Result | | --------------------------------- | ------------------- | -------------------------------- | | ”Check memtomem status” | `mem_status` | Connection and index summary | | ”Remember this decision…” | `mem_add` | New memory stored in markdown | | ”Index this docs folder” | `mem_index` | Existing files become searchable | | ”Search for the deploy checklist” | `mem_search` | Ranked snippets from your memory | ## 6. Open the Web UI [Section titled “6. Open the Web UI”](#6-open-the-web-ui) ```bash mm web --open ``` The default Web UI is the user-facing surface for search, sources, tags, timeline, settings, and Context Gateway. `mm web --dev` adds maintainer-oriented pages that most users do not need. ## Optional: Add STM Later [Section titled “Optional: Add STM Later”](#optional-add-stm-later) `memtomem-stm` is a separate proxy for proactive memory surfacing and response compression. Add it after the LTM flow above works: ```bash uv tool install memtomem-stm mms init --mcp claude # prompts for one upstream server, then registers STM with Claude Code ``` `mms init` walks you through adding one upstream MCP server (name, prefix, command) and then offers a 3-way client registration (Claude Code / write `.mcp.json` / skip). After it finishes, confirm the setup with three read commands: ```bash mms list # the upstreams you've registered (and their SURFACING column) mms status # config summary — is the proxy enabled and pointed at the right file? mms health # probe upstream connectivity and LTM surfacing readiness ``` For a non–Claude-Code client, register STM manually with a one-line command block: ```json { "mcpServers": { "mms": { "command": "mms" } } } ``` STM’s proxied tools surface as `__`. If a proxied tool goes missing after registration, it’s almost always the composed `mcp______` name exceeding MCP’s 64-char limit — see [Troubleshooting](/guides/troubleshooting/) for the fix (a shorter prefix, or registering STM under a short client name). Moving a server behind the proxy is reversible — if STM isn’t a fit, `mms eject` restores each server to the host config it came from. See [STM Overview](/stm/overview/) when you want tool-response compression or automatic memory injection. ## Next [Section titled “Next”](#next) * [Memory Persistence](/guides/memory-persistence/) — save in one session, recall in another * [Hybrid Search](/ltm/hybrid-search/) — BM25 + vector + RRF fusion * [MCP Tools](/ltm/mcp-tools/) — `core`, `standard`, and `full` tool modes * [Context Gateway](/ltm/context-gateway/) — sync agents, skills, and commands across runtimes, move or copy them between projects, and sync many projects at once * [Troubleshooting](/guides/troubleshooting/) — fixes for `command not found`, missing tools, and surfacing that isn’t firing # Troubleshooting > Fixes for the common install, MCP-connection, and STM proxy/surfacing problems. The symptoms first-time users hit most often, with the fix for each — ordered roughly by how common they are. ## Installation [Section titled “Installation”](#installation) ### `mm: command not found` / `mms: command not found` [Section titled “mm: command not found / mms: command not found”](#mm-command-not-found--mms-command-not-found) The install succeeded but your shell can’t find the command, because `~/.local/bin` — where `uv` puts the executable shim — isn’t on your `PATH`. Run this, then reopen your terminal: ```bash uv tool update-shell ``` If you installed with `pipx`, `pipx ensurepath` does the same thing. ### `mm --version` prints an old version [Section titled “mm --version prints an old version”](#mm---version-prints-an-old-version) Right after install, cached package metadata can pin an older release. Reinstall with refreshed metadata: ```bash uv tool install 'memtomem[all]' --refresh ``` ## LTM connection check [Section titled “LTM connection check”](#ltm-connection-check) ### What `mm status` should show [Section titled “What mm status should show”](#what-mm-status-should-show) `mm status` is the first post-install check. Storage path, embedding provider, and a chunk-count summary mean it’s healthy. **Zero chunks is normal before you run `mm index`** — index a folder and check again to see the count rise. For scripting, `mm status --json` returns machine-readable output. ### The agent can’t see memtomem tools [Section titled “The agent can’t see memtomem tools”](#the-agent-cant-see-memtomem-tools) If you ask the agent to “call `mem_status`” and it reports no such tool, it’s almost always the command in the MCP config. * The command must be `memtomem-server` — plain `memtomem` is the CLI and does not start the MCP server. * On Claude Code, check registration with `claude mcp list`; on other clients, check the `mcpServers` block in the config file (see [Quick Start → Connect Your MCP Client](/guides/quickstart/#4-connect-your-mcp-client)). * Restart the client after editing the config so the new server launches. ## STM proxy [Section titled “STM proxy”](#stm-proxy) ### Proxied tools go missing (64-char name limit) [Section titled “Proxied tools go missing (64-char name limit)”](#proxied-tools-go-missing-64-char-name-limit) STM’s proxied tools surface as `__`, and your client composes them into `mcp______`. If that composed name exceeds **64 characters, the tool is silently dropped.** Two fixes: * Give the upstream a shorter `--prefix` (e.g. `filesystem` → `fs`). * Register STM under the short client name `mms` **and** export `MMS_CLIENT_SERVER_NAME=mms`. `mms init --mcp claude` registers under the longer name `memtomem-stm` by default, so it doesn’t give you the 3-char headroom automatically. Run `mms health` to see the discovered / advertised tool counts and diagnose what was withheld. ### The proxy does nothing [Section titled “The proxy does nothing”](#the-proxy-does-nothing) STM’s `proxy.enabled` defaults to `false`; it’s turned on when `mms add` or `mms init` writes the config. Check: ```bash mms status # is the proxy enabled and pointed at the right config file? mms health # does it actually reach the upstreams? ``` ### Surfacing (auto memory injection) isn’t firing [Section titled “Surfacing (auto memory injection) isn’t firing”](#surfacing-auto-memory-injection-isnt-firing) STM injects relevant memories in its SURFACE stage by querying LTM. That link has to be ready, and `mms health` must report LTM as `connected`. * The LTM server must advertise `mem_search` to count as `connected` — it’s the tool the surfacing adapter needs. * The default LTM launch command is `ltm_mcp_command=memtomem-server`. If you run LTM another way, match it with `MEMTOMEM_STM_SURFACING__LTM_MCP_COMMAND`. ## Where the logs are [Section titled “Where the logs are”](#where-the-logs-are) * **MCP server logs** (LTM `memtomem-server`, STM `mms`) go to **stderr** by default, captured or dropped by the MCP client that launched them. Tune verbosity with `MEMTOMEM_LOG_LEVEL`. * **STM file logging** is opt-in: set `MEMTOMEM_STM_LOG_FILE` for a rotating log file (hardened in 0.1.32). * **Web UI logs** live at `~/.memtomem/logs/web.log` (when run in the background via `mm web -b`) — that’s the Web UI log, not the MCP-server log. ## File locations at a glance [Section titled “File locations at a glance”](#file-locations-at-a-glance) | Path | What | | ---------------------------- | ----------------------------------- | | `~/.memtomem/memtomem.db` | LTM SQLite store (chunks + vectors) | | `~/.memtomem/config.json` | LTM configuration | | `~/.memtomem/stm_proxy.json` | STM proxy configuration | | `~/.memtomem/logs/web.log` | Web UI log | For the full set of configuration keys, see [Environment Variables](/reference/configuration/). # Use These Docs > How to make memtomem's docs readable by AI agents — via llms.txt and a local MCP server (mcpdoc). memtomem’s docs can be read directly by AI agents in two ways. Both work with no hosted server. ## llms.txt [Section titled “llms.txt”](#llmstxt) LLM-friendly documentation indexes, generated statically at build time. | File | Purpose | | -------------------------------------------------------- | ------------------------------------------ | | [`/llms.txt`](https://memtomem.com/llms.txt) | Index — lists the available doc sets | | [`/llms-full.txt`](https://memtomem.com/llms-full.txt) | The entire documentation in one file | | [`/llms-small.txt`](https://memtomem.com/llms-small.txt) | Abridged version for small context windows | Most tools — Claude, ChatGPT, Cursor — can fetch these URLs directly. ## Local MCP server (mcpdoc) [Section titled “Local MCP server (mcpdoc)”](#local-mcp-server-mcpdoc) [`mcpdoc`](https://github.com/langchain-ai/mcpdoc) is an open-source MCP server that exposes llms.txt as MCP tools. It **runs on your machine** — no hosting required — and your agent searches the memtomem docs through its `list_doc_sources` and `fetch_docs` tools. ### Prerequisite [Section titled “Prerequisite”](#prerequisite) ```bash # install uv (skip if you already have it) curl -LsSf https://astral.sh/uv/install.sh | sh ``` ### Run [Section titled “Run”](#run) ```bash uvx --from mcpdoc mcpdoc --urls "memtomem:https://memtomem.com/llms.txt" --transport stdio ``` ### Connect Claude Code [Section titled “Connect Claude Code”](#connect-claude-code) ```bash claude mcp add memtomem-docs -s user -- \ uvx --from mcpdoc mcpdoc --urls "memtomem:https://memtomem.com/llms.txt" --transport stdio ``` ### Cursor · Windsurf · Antigravity · other MCP clients [Section titled “Cursor · Windsurf · Antigravity · other MCP clients”](#cursor--windsurf--antigravity--other-mcp-clients) Add it to your MCP config file. ```json { "mcpServers": { "memtomem-docs": { "command": "uvx", "args": ["--from", "mcpdoc", "mcpdoc", "--urls", "memtomem:https://memtomem.com/llms.txt", "--transport", "stdio"] } } } ``` Codex CLI and other stdio MCP clients register the same `command` / `args`. ### Tell your agent to use it [Section titled “Tell your agent to use it”](#tell-your-agent-to-use-it) If your agent doesn’t reach for the tools automatically, add a line to its rules / system prompt: > For memtomem questions, use the `memtomem-docs` MCP server — call `list_doc_sources` first, then `fetch_docs` to read the relevant pages. Allowed domains When you point mcpdoc at a remote llms.txt URL, it auto-allows only that domain (`memtomem.com`). To use local files, specify domains explicitly with `--allowed-domains`. ## Or remember it with memtomem [Section titled “Or remember it with memtomem”](#or-remember-it-with-memtomem) memtomem is itself a memory MCP server, so you can index the docs and run hybrid search over them: ```bash curl -sL https://memtomem.com/llms-full.txt -o memtomem-docs.md mm index ./memtomem-docs.md ``` Your agent then finds answers with `mem_search`. See [Hybrid Search](/ltm/hybrid-search/). ## Related [Section titled “Related”](#related) * [Quick Start](/guides/quickstart/) * [Hybrid Search](/ltm/hybrid-search/) # CLI Reference > mm CLI commands for memtomem LTM server management. The `mm` command is installed with the `memtomem` package. It provides setup, search, indexing, session tracking, and cross-project context sync. Run `mm --help` for the full command list or `mm --version` to print the installed version (the `mm version` subcommand also works). > This page targets memtomem v0.3.10. Commands are grouped by function, but it’s a single reference — scan top to bottom. ## Setup [Section titled “Setup”](#setup) ### `mm init` [Section titled “mm init”](#mm-init) Run the interactive setup wizard. Configures embedding provider, database path, tokenizer, reranker, and default namespace. At startup, the setup wizard offers a **preset picker** (Minimal / English / Korean) that applies a curated bundle of embedding, reranker, tokenizer, and namespace defaults. Pass `--preset ` to pick one non-interactively, or `--advanced` to force the full 10-step wizard. ```bash mm init # interactive setup with preset picker mm init --non-interactive # auto-accept; behaves as `--preset minimal --non-interactive` mm init --preset korean # apply Korean preset non-interactively mm init --preset english --non-interactive # English preset, no prompts mm init --advanced # skip picker, run full 10-step wizard mm init --fresh # bulk-clean accumulated config, then re-run wizard ``` On a reinstall path, `mm init` compares the embedding provider / model / dimension stored in the existing `~/.memtomem/memtomem.db` against the new preset. On mismatch, the interactive wizard offers an in-place rebuild of the vector index (`chunks_vec`); under `--non-interactive`, it prints a recovery hint pointing at `mm embedding-reset --mode apply-current`. The chunks table itself is preserved, so re-running `mm index ` afterwards restores the working set. `--fresh` drops every wizard-untouched config key whose value differs from the built-in default, then re-runs the wizard. A safe cleanup option when the config has accumulated leftovers from older versions; the previous `config.json` is backed up to `config.json.bak-` before rewriting. ### Running the MCP server [Section titled “Running the MCP server”](#running-the-mcp-server) memtomem’s MCP server ships as the `memtomem-server` console script. You normally don’t launch it by hand — your MCP client (Claude Desktop, Claude Code, Cursor, etc.) starts it automatically from its config file. See [Quick Start](/guides/quickstart/) for the config snippets. To filter which tools the server advertises, set `MEMTOMEM_TOOL_MODE` (`core` / `standard` / `full`) in the client’s MCP config. The default is `core` (8 core tools + the `mem_do` router, 9 total); `full` exposes 96 current tools plus one deprecated alias. See the [MCP Tools](/ltm/mcp-tools/) page for modes and tool catalogs. Since v0.1.25, an MCP handshake alone no longer creates `~/.memtomem/memtomem.db` — the DB opens on the first tool call, and the server pid/flock file moved to `$XDG_RUNTIME_DIR/memtomem/server.pid` (or `$TMPDIR/memtomem-$UID/` on platforms without one). A client that connects but never calls a tool leaves the home directory untouched. ### `mm config show / set / unset` [Section titled “mm config show / set / unset”](#mm-config-show--set--unset) `mm config show` displays the current configuration with API keys masked. `--json` (or `--format json`) emits the full config as machine-readable JSON. `mm config set ` writes a user override on top of built-in defaults; `mm config unset ` removes those overrides so the field reverts to its built-in default (or whatever a `config.d/*.json` fragment resolves to). ```bash mm config show # human-readable table mm config show --json # JSON for scripting mm config set search.default_top_k 20 mm config set rerank.model bge-reranker-base mm config unset indexing.memory_dirs mm config unset rerank.model search.default_top_k ``` `mm config unset` is idempotent — removing a key that isn’t there is a silent no-op. Useful for clearing stale cross-machine paths in `indexing.memory_dirs`, or a single field that’s shadowing a `config.d` fragment. ## Search & Recall [Section titled “Search & Recall”](#search--recall) ### `mm search ` [Section titled “mm search \”](#mm-search-query) Search the knowledge base from the command line. ```bash mm search "how does the auth middleware work" mm search "deployment config" --namespace project-x --top-k 5 ``` `--top-k` / `-k` caps results (default 10). Other filters: `--source-filter` / `-s`, `--tag-filter` / `-t`, `--namespace` / `-n`, `--as-of` (point-in-time bound, `YYYY-MM-DD` / `YYYY-QN`), and `--format` (`table` / `json` / `plain` / `context` / `smart`). ### `mm tags list / rename / delete / merge` [Section titled “mm tags list / rename / delete / merge”](#mm-tags-list--rename--delete--merge) Curate the tags on your chunks — the CLI equivalent of the Web UI Tags tab. Every mutating subcommand is a dry-run by default; pass `--apply` to actually write. ```bash mm tags list # tags in use and how often mm tags rename ops infra # dry-run preview mm tags rename ops infra --apply # perform the rename mm tags delete deprecated --apply # drop a tag (chunks stay indexed) mm tags merge py python --into python --apply # fold several tags into one ``` Without `--apply`, each command first shows the affected chunk count and samples. `delete` only strips the tag — the chunks themselves stay in the index. ### `mm recall` [Section titled “mm recall”](#mm-recall) Browse recent memory chunks chronologically. Unlike `mm search`, no query needed — filter by date range, source path, or namespace instead. ```bash mm recall # most recent 20 chunks (default table) mm recall --since 2026-04 --limit 50 mm recall --source-filter "postmortems/" --format json mm recall --namespace project-x --format plain ``` `--format` picks `table` (default, human), `json` (scripting), or `plain` (text pipe). Date arguments accept `YYYY`, `YYYY-MM`, `YYYY-MM-DD`, and ISO datetimes. ### `mm web` [Section titled “mm web”](#mm-web) Launch the Web UI dashboard for browser-based search and memory management. On launch, `mm web` opens the dashboard at `http://127.0.0.1:8080` with these tabs: **Home · Search · Sources · Index · Tags · Timeline · More**. The **More** tab holds Settings, Dedup, Age-out, Export/Import, and Reset Database. The Context Gateway tab opens in a **Simple view** by default — for each artifact kind (skills / commands / subagents) it shows a one-line status (“already in your AI tools” or “still needs to be pushed out”) and, on any row that needs action, a single button: **Sync** or **Import**. The full control grid is one click away as **Advanced**. Pass `--dev` (or set `MEMTOMEM_WEB__MODE=dev`) to unlock maintainer pages: **Namespaces, Sessions, Working Memory, Health Report**. Most users won’t need these. ```bash mm web # default: http://localhost:8080 (prod tier) mm web --port 9000 mm web --open # also open the URL in your default browser mm web --dev # shortcut for --mode dev mm web --mode dev # expose opt-in maintainer pages ``` ### `mm shell` [Section titled “mm shell”](#mm-shell) Start an interactive REPL — search, add, recall, tag counts, and index stats all from a single prompt. Handy for browsing memory from a terminal without an MCP client, or for a quick post-install feel-check of the DB. ```bash mm shell mm> search deployment checklist mm> ask summarize last week's migration rollback decision mm> add "new fact I just learned" mm> stats mm> quit ``` Bare text (no command) is treated as an implicit `search`. Exit with Ctrl+D or `quit` / `exit` / `q`. ## Adding & Indexing [Section titled “Adding & Indexing”](#adding--indexing) ### `mm add` [Section titled “mm add”](#mm-add) Add a memory entry and index it. Without `--file`, the content is appended to `~/.memtomem/memories/.md`. ```bash mm add "apply tree-sitter AST parser to hallway-door PR" mm add "API timeout policy" --title "API timeout" --tags "ops,api" mm add "postmortem summary" --file postmortems/2026-04-auth.md ``` Tags passed via `--tags` are merged onto the appended file’s chunk metadata right after indexing — the chunker doesn’t parse tag text from the body, so the merge is explicit. `--file` only accepts paths relative to `~/.memtomem/memories/` and rejects `..` components. ### `mm index ` [Section titled “mm index \”](#mm-index-path) One-shot command that **seeds** the index with files already on disk. Re-runs are safe — chunks are content-hashed, so unchanged files are skipped. ```bash mm index . # index current directory mm index ~/docs/architecture # index a specific directory mm index README.md # index a single file ``` Paths listed in `indexing.memory_dirs` are additionally watched by the file watcher that `mm server` starts — but the watcher is **reactive only**. It reindexes on modify/create/move events that fire after it starts, so **pre-existing files at boot time are not auto-scanned**. The normal flow is to seed once with `mm index ` (or `mem_index(path="")`) and then let the watcher handle further edits. This is why the `mm init` wizard prints `mm index {memory_dir}` as step 1 of its `Next steps`. ### `mm ingest` [Section titled “mm ingest”](#mm-ingest) Consolidate memories from other AI tools into memtomem. The `--source` path is required; re-runs are incremental via content-hash matching. ```bash mm ingest claude-memory --source ~/.claude/projects/ # import Claude Code memories mm ingest gemini-memory --source ~/.gemini/GEMINI.md # import Antigravity CLI GEMINI.md mm ingest codex-memory --source ~/.codex/memories/ # import Codex CLI memories ``` ## Context Gateway [Section titled “Context Gateway”](#context-gateway) The Context Gateway syncs the agent definitions, skills, and commands you store in canonical form out to each AI runtime. The basic flow within one project is detect → init → sync → diff; v0.3.0 adds cross-project / cross-tier transfer and fleet-wide operations. Tiers are addressed by friendly labels: **User** (`--scope user`, personal, visible in every project), **Project (shared)** (`--scope project_shared`, git-tracked), and **Project (local)** (`--scope project_local`, local drafts). ### `mm context sync` [Section titled “mm context sync”](#mm-context-sync) Sync your stored canonical files out to the detected runtime files. ```bash mm context detect mm context init --scope project_shared --confirm-project-shared mm context sync --scope project_shared mm context diff --scope project_shared ``` **Project (shared)** is git-tracked, so it requires explicit confirmation and should not contain secrets. Syncing to the **User** tier (`--scope user`) places the canonical files under `~/.memtomem/` so they show up in every project — because that writes outside the project (your home directory), the gateway shows exactly which file paths it will touch and asks for confirmation. In non-interactive contexts, `--yes` skips the prompt. MCP server definitions move through the same flow. `mm context sync --include=mcp-servers` syncs canonical MCP server definitions into a project’s `.mcp.json` (with secret-safety checks) — an opt-in path that only runs when you ask for it. ### Reuse a skill from another project (`mm context move` / `copy`) [Section titled “Reuse a skill from another project (mm context move / copy)”](#reuse-a-skill-from-another-project-mm-context-move--copy) Use this when you want to bring a skill, agent, or command you already built in another project into this one, or shift it between tiers. `copy` leaves the original in place (rename it with `--as` if needed); `move` cleans up the source. ```bash # copy another project's skill into the current one (preview first) mm context copy skills my-skill --to-project ~/work/other-app mm context copy skills my-skill --to-project ~/work/other-app --apply # copy to your user tier under a new name mm context copy agents reviewer --to user --as reviewer-strict --apply # tier move: promote a local draft to the shared tier mm context move commands deploy --to project_shared --confirm-project-shared --apply # copy an MCP server definition to another project mm context copy mcp-servers github --to-project ~/work/other-app --apply ``` Both default to a dry-run preview; pass `--apply` to execute. A destination collision always refuses (no `--force` valve). A landing in **Project (shared)** runs a privacy scan and additionally requires `--confirm-project-shared`. After a transfer the command prints the follow-up that pushes the artifact out to your AI tools at the destination (e.g. `mm context sync`) so you can run it next. ### Operate across many projects (`mm context projects`) [Section titled “Operate across many projects (mm context projects)”](#operate-across-many-projects-mm-context-projects) Register the projects you work across, then push shared artifacts out to all of them in one call (`sync --all-projects`) or ask read-only which projects have drifted (`status --all-projects`). ```bash mm context projects add ~/work/app-a # register in the registry mm context projects list # registered projects + health/enrollment mm context projects pause ~/work/app-a # exclude from batch operations mm context projects resume ~/work/app-a # include again mm context sync --all-projects # bulk-sync every eligible project mm context status --all-projects # read-only: which projects drifted ``` The bulk sync targets the **Project (shared)** tier only, and one project’s failure does not abort the batch. A `pause`d project is skipped by every `--all-projects` operation. ### Seeding from existing runtime files [Section titled “Seeding from existing runtime files”](#seeding-from-existing-runtime-files) There is no separate `mm context import` command. To seed canonical files from runtime-specific files, run `mm context init` with the artifact kinds and destination tier. ```bash mm context detect --include agents,skills mm context init --include agents,skills --scope project_shared --confirm-project-shared mm context diff --include agents,skills --scope project_shared ``` This is useful when you already authored files directly in Claude Code, Codex CLI, Antigravity CLI, or another runtime and want memtomem to manage them going forward. For reuse across projects see `move`/`copy` above; to install from a host-global library see `mm wiki`. ## Wiki — a canonical artifact library [Section titled “Wiki — a canonical artifact library”](#wiki--a-canonical-artifact-library) Collect canonical versions of your skills, agents, and commands in a host-global wiki (`~/.memtomem-wiki/`) and install them into projects on demand. The wiki is a normal git repo, so changes are recorded as isolated commits and backed up / synced across machines via remote/push/pull — no separate sync tooling needed. ```bash mm wiki init # create ~/.memtomem-wiki/ (skills/ agents/ commands/) mm wiki init --from git@host:me/wiki # clone an existing wiki from a git URL mm wiki list # list the skills / agents / commands you hold mm wiki list --type skills mm wiki remote git@host:me/wiki # configure the backup remote (origin) mm wiki push # back up to the remote mm wiki pull # restore on another machine ``` Each artifact kind (`skill` / `agent` / `command`) has a subgroup to seed per-runtime overrides and to diff, lint, and commit them. The Commit button in the dev-mode browser does the same, so no raw git is required. ```bash mm wiki skill override my-skill --vendor claude --editor # seed an override from canonical content mm wiki skill diff my-skill --vendor claude # diff against the canonical render mm wiki skill lint my-skill # validate it is installable (usable as a CI gate) mm wiki skill commit my-skill --vendor claude # record as an isolated commit ``` Install an artifact you’ve collected with `mm context install `. ## Sessions & Multi-Agent [Section titled “Sessions & Multi-Agent”](#sessions--multi-agent) ### `mm session` [Section titled “mm session”](#mm-session) Manage agent sessions — start, end, list, events, and wrap. Sessions group activity events and tie them to an agent runtime. ```bash mm session start --agent-id claude-code --title "refactor auth" mm session list --json # scriptable list output mm session events --json # event timeline as JSON mm session wrap -- # auto start/end around a command mm session end ``` The current session ID is stored in `~/.memtomem/.current_session`, so `mm activity log` and other commands pick it up automatically. ### `mm activity log` [Section titled “mm activity log”](#mm-activity-log) Log an activity event (tool call, decision, error, subagent lifecycle) to the current session. Silent by default so hook callers never fail; `--json` emits an ack shape for scripting. ```bash mm activity log --type tool_call --content "ran tests" mm activity log --type decision --content "picked strategy X" --meta '{"k":"v"}' --json ``` With `--json`, a successful write returns `{"ok": true, ...}` on stdout; no active session or a write failure returns `{"ok": false, "reason": ...}`. Exit code is always 0. ### `mm agent register / list / share` [Section titled “mm agent register / list / share”](#mm-agent-register--list--share) CLI mirrors of the MCP `mem_agent_*` tools — register agents, inspect the registry, and copy chunks between scopes. ```bash mm agent register planner --description "Planning subagent" --color "#6c5ce7" mm agent list # registered agents + the shared namespace mm agent list --json mm agent share # copy into the shared namespace mm agent share --target agent-runtime:reviewer ``` `mm agent register` creates the `agent-runtime:{agent_id}` namespace; re-registering with the same id only updates metadata. `agent_id` must match `[A-Za-z0-9._-]` — IDs outside the allowed pattern are rejected. `mm agent share` is a **copy**, not a reference link. The new chunk gets a fresh UUID and source updates do not propagate; provenance is recorded only via a `shared-from=` tag on the copy. ## Diagnostics [Section titled “Diagnostics”](#diagnostics) ### `mm status` [Section titled “mm status”](#mm-status) Terminal mirror of the MCP `mem_status` tool. Use it as a post-install sanity check: confirms the binary runs, the config parses, the DB is reachable, and the embedding config is in sync — without needing to launch an MCP client. Sits between `mm config show` (config only) and `mm watchdog status` (periodic snapshots). ```bash mm status # indexing stats + config summary (same output as mem_status) mm status --json # machine-readable, for scripts / `jq` pipelines ``` Added in v0.1.25; `--json` / `--format json` added in v0.3.4. Good fit for a one-liner “is the DB open and how many entries are in it” check before wiring an MCP client. ### `mm warmup` [Section titled “mm warmup”](#mm-warmup) Preload the local embedder / reranker models so the **first** query doesn’t pay the one-time model load. Optional — without it the models load lazily on first use. ```bash mm warmup # load models now (one-shot) ``` To warm up automatically when the MCP server starts, set `MEMTOMEM_WARMUP__ENABLED=true`. Remote providers (Ollama / OpenAI / Cohere) are skipped — there’s nothing local to preload. ### `mm memory doctor` [Section titled “mm memory doctor”](#mm-memory-doctor) Inspect memory-store consistency read-only — it reports 3-way drift between the notes folder on disk, the index file, and the searchable DB (e.g. files added while the server was off and never indexed, or dead index links). The default report is read-only and changes nothing. ```bash mm memory doctor # inspect every memory_dir (read-only) mm memory doctor ~/notes # scope to one configured memory_dir mm memory doctor --fix # preview removal of broken index links (dry-run) mm memory doctor --fix --apply # actually remove broken links ``` `--fix` only removes index pointer lines whose target is missing on disk, and it is a dry-run unless `--apply` is also passed. It exits 1 when any error-severity finding exists, so it works as a CI check. ### `mm watchdog` [Section titled “mm watchdog”](#mm-watchdog) Periodic health-check command group. Read back snapshots left by the background scheduler, or run every check once on demand. ```bash mm watchdog status # latest results summary mm watchdog status --json # JSON output mm watchdog run # run all checks now mm watchdog history db_size --hours 48 # 48h trend for a specific check ``` The scheduler only runs in the background when `health_watchdog.enabled` is on (the MCP server drives it). Even with the scheduler off, `mm watchdog run` works any time for a one-shot offline check. ### `mm schedule add / list / run-now / delete` [Section titled “mm schedule add / list / run-now / delete”](#mm-schedule-add--list--run-now--delete) Register cron-driven jobs (compaction, importance decay, dead-link cleanup, dedup scans, …) and inspect or run them. ```bash mm schedule add --cron "0 3 * * *" --job dedup_scan mm schedule add --cron "0 */6 * * *" --job importance_decay --params '{"max_age_days": 90}' mm schedule list mm schedule list --json mm schedule run-now # fire immediately, out of band mm schedule delete ``` `--cron` is a 5-field expression in UTC. `--params` is a JSON dict of job-specific parameters. The dispatcher rides the health-watchdog loop, so registered jobs only fire when both `scheduler.enabled` and `health_watchdog.enabled` are on. ## Maintenance & Lifecycle [Section titled “Maintenance & Lifecycle”](#maintenance--lifecycle) ### `mm embedding-reset` [Section titled “mm embedding-reset”](#mm-embedding-reset) Check or resolve mismatches between the embedding model/dimension stored in the DB and the current config (typically after swapping providers or following a reinstall). `--mode` selects the action. ```bash mm embedding-reset # --mode status (default): compare DB vs. config mm embedding-reset --mode apply-current # reset DB to current config (destructive — re-index required) mm embedding-reset --mode revert-to-stored # switch runtime embedder to DB stored values (non-destructive) ``` `apply-current` rebuilds `chunks_vec` at the current config’s dimension. The chunks table itself is preserved, but all vectors are deleted — run `mm index ` afterwards to re-index. `revert-to-stored` only flips runtime state; to make it permanent, update the embedding fields in `~/.memtomem/config.json` accordingly. ### `mm purge --matching-excluded` [Section titled “mm purge --matching-excluded”](#mm-purge---matching-excluded) Remove already-indexed chunks whose source paths match the built-in credential denylist or your `indexing.exclude_patterns`. Runs as a dry-run by default — pass `--apply` to actually delete. ```bash mm purge --matching-excluded # dry-run — shows what would be removed mm purge --matching-excluded --apply # perform the deletion ``` ### `mm reset` [Section titled “mm reset”](#mm-reset) Delete all data (chunks, sessions, activity log, etc.) from the DB and reinitialize the schema. Embedding configuration is preserved — re-index to repopulate, no re-config needed. A confirmation prompt shows the row count; pass `-y` to skip. ```bash mm reset # confirm, then delete mm reset -y # skip prompt ``` Where `mm embedding-reset --mode apply-current` rebuilds vectors only, `mm reset` drops the whole index. It doesn’t touch the config file — for a full wipe, pair it with `mm init --fresh` or `mm uninstall`. ### `mm upgrade` [Section titled “mm upgrade”](#mm-upgrade) Stop a running memtomem-server, then reinstall via `uv tool`. `uv tool install --reinstall memtomem` alone only swaps the on-disk bytes — a server already imported by an MCP client keeps running the previous version — so this adds the process-cleanup step around it. ```bash mm upgrade # reinstall to the latest version (extras auto-detected) mm upgrade --version 0.3.10 # pin a specific version mm upgrade --extras all # name the extras to install (default: auto-detect) mm upgrade --dry-run # print the plan, change nothing ``` Extras are auto-detected from the current uv-tool install by default, so a `memtomem[all]` user keeps `[all]`. ### `mm uninstall` [Section titled “mm uninstall”](#mm-uninstall) Clean up `~/.memtomem/` state (config, DB, fragments, backups, uploads) separately from removing the binary. Package-manager commands like `uv tool uninstall memtomem` only remove the executable, which leaves stale state behind on reinstall — since v0.1.23 this subcommand closes the gap. ```bash mm uninstall # interactive, removes everything mm uninstall -y # skip the confirmation prompt mm uninstall --keep-config # preserve config.json + config.d/* + backups mm uninstall --keep-data # preserve the SQLite DB + ~/.memtomem/memories/ mm uninstall --force # bypass the running-server safety check ``` Custom `storage.sqlite_path` values outside the default directory are included in the inventory. The command refuses to run while the MCP server is alive (open WAL handles risk corruption); stop it first or pass `--force`. External editor MCP entries (`~/.claude.json`, `~/.codex/config.toml`, etc.) are **detected and reported**, never modified. At the end it prints the exact binary-removal command for your install context (`uv tool uninstall memtomem`, `pip uninstall memtomem`, etc.) so you can follow through. > See [Quick Start](/guides/quickstart/) for the full getting-started walkthrough. # Context Gateway > Define agents, skills, and commands once, then sync them across AI runtimes. You wrote a skill in Claude Code and want the same one in Codex and Cursor, or you want the same command set across several projects. Because every runtime stores context in a different place and format, those copies drift fast. Context Gateway solves this by syncing each AI runtime from one canonical `.memtomem/` source. In LTM 0.3.0 the Context Gateway grew beyond a single-project, one-way model: it is now the central surface for moving and copying artifacts across projects and tiers, bulk-syncing many projects, and authoring a canonical wiki. ## What It Solves [Section titled “What It Solves”](#what-it-solves) AI runtimes store context in different places and formats: | Runtime | Example runtime files | | ------------------------------ | --------------------------------------------------------------------------- | | Claude Code | `.claude/agents/*.md`, `.claude/skills/*/SKILL.md`, `.claude/commands/*.md` | | Codex CLI | `.agents/skills/*/SKILL.md`, `.codex/agents/*` | | Antigravity CLI | `.gemini/agents/*`, `.gemini/skills/*`, `.gemini/commands/*` | | Other MCP clients / frameworks | Agent definition surfaces vary by runtime | Without a canonical layer, every runtime copy drifts. With Context Gateway, you edit the canonical file once and sync it out to each AI runtime path. ## First Workflow [Section titled “First Workflow”](#first-workflow) From your project root: ```bash mm context detect mm context init --scope project_shared --confirm-project-shared mm context sync --scope project_shared mm context diff --scope project_shared ``` | Command | Purpose | | -------- | ------------------------------------------------------ | | `detect` | Shows existing runtime files memtomem can see | | `init` | Creates canonical files under `.memtomem/` | | `sync` | Syncs canonical files out to each runtime path | | `diff` | Shows whether canonical and runtime copies still match | For the full command list — move/copy, multi-project, versions — see the [CLI Reference](/ltm/cli/). ## Canonical Tiers [Section titled “Canonical Tiers”](#canonical-tiers) Context Gateway uses the same three tiers as memory writes. The UI shows friendly labels (User / Project (shared) / Project (local)); the scope values below are the CLI flag values: | Tier (CLI scope) | UI label | Canonical location | Good for | | ---------------- | ---------------- | ------------------------------------------ | -------------------------------------------------------- | | `user` | User | `~/.memtomem//...` | Personal agents, skills, commands reused across projects | | `project_shared` | Project (shared) | `/.memtomem//...` | Team-shared project context committed to git | | `project_local` | Project (local) | `/.memtomem/.local/...` | Private drafts for one checkout | The `user` tier became an actively managed write path in 0.3.0. Because these paths live outside the project in your home directory, every user-tier write goes through a “Write outside the project?” confirmation: the gateway first shows the exact home-directory files it will touch, and only writes them once you approve. Enable it with the `context_gateway.user_tier_enabled` setting. `project_local` canonical files are gitignored and do not sync to runtime agent / skill / command paths. `project_shared` is git-tracked, so do not put secrets there. In 0.3.0 sync and transfer hard-refuse a `project_shared` write when a secret is detected, with no `--force` valve (because git history is permanent). The `user` and `project_local` tiers allow an override after review, but `project_shared` refuses in every case. ## Common Recipes [Section titled “Common Recipes”](#common-recipes) ### Share a Project Agent With the Team [Section titled “Share a Project Agent With the Team”](#share-a-project-agent-with-the-team) ```bash mm context init --include agents --scope project_shared --confirm-project-shared mm context sync --include agents --scope project_shared ``` Commit the generated `.memtomem/agents/` file after review. ### Keep a Personal Skill Across Projects [Section titled “Keep a Personal Skill Across Projects”](#keep-a-personal-skill-across-projects) ```bash mm context init --include skills --scope user mm context sync --include skills --scope user ``` This writes the canonical skill under `~/.memtomem/skills/` and syncs it out to supported user-level runtime paths (the first write goes through the host-write confirmation). ### Draft Locally Before Sharing [Section titled “Draft Locally Before Sharing”](#draft-locally-before-sharing) ```bash mm context init --include agents --scope project_local mm context diff --include agents --scope project_local ``` `project_local` canonical files are gitignored and do not sync to runtime paths. When the draft is ready, use `mm context move` to shift it to `project_shared`, then run `mm context sync --scope project_shared`. ### Seed Canonical Files From Existing Runtime Files [Section titled “Seed Canonical Files From Existing Runtime Files”](#seed-canonical-files-from-existing-runtime-files) If you already authored agents or skills directly in a runtime, run `init` with the destination tier. `init` seeds canonical files and imports detected runtime files when possible: ```bash mm context detect --include agents,skills mm context init --include agents,skills --scope project_shared --confirm-project-shared mm context diff --include agents,skills --scope project_shared ``` Review the generated canonical files before committing. ## Move or Copy Across Projects and Tiers [Section titled “Move or Copy Across Projects and Tiers”](#move-or-copy-across-projects-and-tiers) 0.3.0 goes beyond the one-way model with a transfer engine that moves or copies a single canonical artifact (`agents` / `commands` / `skills`) between tiers or between projects: ```bash # Move one skill to the user tier (source is cleaned up) mm context move skills my-skill --to user # Copy to another project (source untouched, can be renamed) mm context copy agents reviewer --to-project --as reviewer-v2 ``` * `move` consumes the source and cleans up its stale runtime copies. * `copy` never touches the source and can rename the copy with `--as`. * Every transfer is a dry-run preview by default; pass `--apply` to execute. * Destination collisions always refuse, with no `--force` valve. * A transfer landing in `project_shared` runs the secret scan and requires `--confirm-project-shared`. * Every successful transfer prints the follow-up `mm context sync` command to run. The `mem_context_artifact_transfer` MCP action performs the same operation headlessly. ## Manage Multiple Projects [Section titled “Manage Multiple Projects”](#manage-multiple-projects) Register several projects to bulk-sync shared artifacts, or check drift across all of them at once. All multi-project operations target the `project_shared` tier: ```bash mm context projects list mm context projects add mm context projects pause mm context projects resume # Bulk-sync every registered project (one lock window) mm context sync --all-projects # Read-only check of which projects drifted mm context status --all-projects ``` Paused projects and projects not enrolled for sync are skipped. In the web UI, opting a project into sync is shown as **Activate** (“Project activated for sync”). ## MCP Server Definitions [Section titled “MCP Server Definitions”](#mcp-server-definitions) Beyond agents / skills / commands, the gateway also manages MCP server definitions. Keep canonical definitions in `.memtomem/mcp-servers/.json` and sync them into the project’s `.mcp.json`: ```bash # Sync canonical MCP server definitions into .mcp.json (opt-in) mm context sync --include=mcp-servers # Copy a definition to another project mm context copy mcp-servers --to-project ``` The `mcp-servers` sync is opt-in (a bare `mm context sync` never touches `.mcp.json`). The same secret-safety checks apply, so put secrets in `${VAR}` references rather than directly in an `env` block. v1 supports only stdio servers on the `project_shared` tier. ## Version Snapshots [Section titled “Version Snapshots”](#version-snapshots) Agents and commands can carry a version history with movable labels (production / staging, etc.): ```bash mm context version create agents reviewer --note "initial version" mm context version promote agents reviewer --label production mm context version list agents reviewer ``` You can configure sync to use the version a label points to. See the [CLI Reference](/ltm/cli/) for the full flag list. ## Canonical Wiki [Section titled “Canonical Wiki”](#canonical-wiki) Author reusable artifacts once in a host-global wiki (`~/.memtomem-wiki/`), then install them into a project with `mm context install`. Each artifact is stored as an isolated git commit, and `remote`/`push`/`pull` back it up and sync it across devices: ```bash mm wiki init mm wiki skill commit my-skill --canonical mm wiki remote mm wiki push ``` You can also edit in the browser; saved-but-uncommitted edits are flagged with a nav badge. ## Conversion Loss Handling [Section titled “Conversion Loss Handling”](#conversion-loss-handling) When a target runtime cannot represent a field exactly, memtomem classifies the loss: | Severity | Behavior | | -------- | -------------------------------- | | `ignore` | Field is unsupported and skipped | | `warn` | Continue, but print a warning | | `error` | Abort conversion | ## Web UI [Section titled “Web UI”](#web-ui) ```bash mm web --open ``` The Context Gateway opens in a comprehension-first **Simple view**. For the active project it shows a one-line verdict (“Everything is in your tools.”, “Some items aren’t in your tools yet — sync to push them out.”, and so on) above a per-type row list (skills / commands / subagents). Each row that needs action carries one button: * **Sync** — push your stored copy out to the tool. * **Import** — pull a runtime’s copy back in. Clean rows show a check. An onboarding layer explains the model: your master copies live in one **Store** (`.memtomem/`), Sync pushes them out to your **Runtimes**, and Import pulls a runtime’s copy back in. It is one-way: edit in the Store, then Sync. A **Store ── Sync → Runtimes** diagram makes this visual. The full control grid (the artifact / tier / runtime / scope axes) is one **Advanced** toggle away, and the choice persists per browser. ## Next [Section titled “Next”](#next) * [CLI Reference](/ltm/cli/) — full `mm context` and `mm wiki` command list * [MCP Tools](/ltm/mcp-tools/) — context actions through `mem_do` * [Multi-Agent Collaboration](/ltm/multi-agent/) — memory namespaces for multiple agents # Hybrid Search > How BM25 keyword + dense vector + RRF fusion search works and how to tune it. > New to memtomem? Start with the [Memory Persistence Across Sessions](/guides/memory-persistence/) tutorial to see the basic search flow in action first. memtomem’s hybrid search combines keyword search and semantic search, leveraging both exact term matching and meaning-based similarity in a single query. ### Why both? [Section titled “Why both?”](#why-both) Keyword search finds exact names like `mem_search` or `FastAPI` — things a vector model often misses because their meaning isn’t distributed across the embedding space. Semantic search finds ideas like “how do I deploy?” that match documents using different wording. Running both and merging the rankings covers both cases. ## Search Architecture [Section titled “Search Architecture”](#search-architecture) Hybrid search runs three search engines in parallel: | Engine | Based on | Strength | | ----------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------- | | **BM25** | SQLite FTS5 | Exact keyword/term matching. Strong for unique identifiers like “FastAPI”, “mem\_search” | | **Vector search** | sqlite-vec + ONNX/Ollama/OpenAI embeddings | Semantic similarity. Can match “how to deploy” → “deployment checklist” | | **RRF fusion** | Reciprocal Rank Fusion | Combines rankings from both engines into a final score | ## Reranker Pool Tuning [Section titled “Reranker Pool Tuning”](#reranker-pool-tuning) When reranking is enabled, the reranker sees a candidate pool of size `max(min_pool, min(max_pool, int(oversample * response_top_k)))`. The defaults (oversample `2.0`, min\_pool `20`, max\_pool `200`) give the classic 2× oversample at `top_k=10` and scale up with larger `top_k` requests. Tune with: | Key | Env var | Default | Notes | | ------------------- | ----------------------------- | ------- | -------------------------------------------- | | `rerank.oversample` | `MEMTOMEM_RERANK__OVERSAMPLE` | `2.0` | Pool multiplier over `response_top_k` | | `rerank.min_pool` | `MEMTOMEM_RERANK__MIN_POOL` | `20` | Floor — reranker never sees fewer candidates | | `rerank.max_pool` | `MEMTOMEM_RERANK__MAX_POOL` | `200` | Cap — prevents runaway cost on large `top_k` | Runtime-tunable via `mm config set rerank.oversample 3.0` etc. The remaining `rerank.*` keys, including reranker model selection, are covered in the [configuration reference](/reference/configuration/). ## Semantic Chunking [Section titled “Semantic Chunking”](#semantic-chunking) During indexing, supported documents are split into meaningful units by structure before the short-section merge pass runs. | Chunker | Target | Behavior | | ------------------- | ----------------------------------------- | ------------------------------------------------------------------------ | | **Markdown** | `.md` files | Split by heading level, preserving hierarchy | | **Structured data** | `.json`, `.yaml`, `.yml`, `.toml` files | Top-level key splitting, with recursive mode available via config | | **Code** | `.py`, `.js`, `.ts`, `.tsx`, `.jsx` files | Function / class-aware splitting when code chunking extras are installed | Very short sections are greedily packed with adjacent siblings up to `indexing.target_chunk_tokens` (default `384`) to keep each chunk informative enough to retrieve. Set `target_chunk_tokens=0` to disable the pass and keep every small section as its own chunk. Directory indexing is extension-filtered. If a file type is not chunked by the active registry, it is skipped rather than indexed as plain text. ## Incremental Indexing [Section titled “Incremental Indexing”](#incremental-indexing) Instead of full re-indexing, only changed chunks are updated: 1. Store **SHA-256 hash** for each chunk 2. On re-index, compare hashes to detect changes 3. Only re-embed changed chunks This minimizes indexing cost even for large document sets. ## Search Scope and Maintenance [Section titled “Search Scope and Maintenance”](#search-scope-and-maintenance) Searches can be scoped by namespace. Namespaces are auto-derived from folder names, and you can filter a search to a specific namespace or isolate and share scopes per agent. See [Multi-Agent](/ltm/multi-agent/) for details. Maintenance behaviors that affect search quality — near-duplicate detection, time-based decay, TTL expiration, and auto-tagging — are documented alongside their environment variables in the [configuration reference](/reference/configuration/). ## Retrieval benchmark v2 [Section titled “Retrieval benchmark v2”](#retrieval-benchmark-v2) The current holdout evaluates 120 bilingual queries across separate English, Korean, and cross-language tracks with portable qrels and pinned corpus/query hashes. It complements the original 48-file, 192-chunk, 100-query regression portfolio rather than replacing it. A one-run staged k-sweep retained the product defaults: `top_k=10`, BM25/dense candidates `50/50`, `rrf_k=60`, and reranking disabled. Candidate width 100 at `top_k=5` is only a follow-up candidate; repeated 5-run/10-run validation is required before any default change. # MCP Tools > How memtomem exposes memory features to MCP clients. memtomem exposes its LTM features as MCP tools. New users should keep the default `core` mode: it gives agents the common tools directly and routes everything else through `mem_do`, which keeps the agent’s visible tool list small. ## Tool Modes [Section titled “Tool Modes”](#tool-modes) Set the mode with `MEMTOMEM_TOOL_MODE` in your MCP client config. | Mode | Tools exposed | Use when | | ---------------- | ------------------------------------- | ------------------------------------------------------------------------------------ | | `core` (default) | 9 total, including `mem_do` | Best default for most agents | | `standard` | 38, including `mem_do` | You want common management tools directly visible | | `full` | 96 current tools + 1 deprecated alias | You are debugging, documenting, or using a client that handles large tool lists well | Example: ```json { "mcpServers": { "memtomem": { "command": "memtomem-server", "env": { "MEMTOMEM_TOOL_MODE": "core" } } } } ``` ## Core Mode [Section titled “Core Mode”](#core-mode) In `core` mode, the agent sees the tools needed for daily memory work: | Tool | Purpose | | ------------ | -------------------------------------------------- | | `mem_status` | Check server, storage, embedding, and index status | | `mem_stats` | Return index statistics | | `mem_add` | Store a new memory | | `mem_search` | Hybrid search over indexed memory | | `mem_recall` | Browse recent or date-filtered memory | | `mem_index` | Index a file or directory | | `mem_list` | List indexed memories / sources | | `mem_read` | Read an indexed source file | | `mem_do` | Route all non-core actions by name | Tell the agent what you want in natural language. It will usually pick the right core tool. ## `mem_do` [Section titled “mem\_do”](#mem_do) `mem_do` provides access to every remaining action. It takes an `action` and optional `params`. ```text mem_do(action="help") mem_do(action="help", params={"category": "context"}) mem_do(action="schedule_list") mem_do(action="context_diff", params={"scope": "project_shared"}) mem_do(action="context_artifact_transfer", params={"asset_type": "skill", "name": "my-skill", "mode": "copy", "to_scope": "project_shared"}) ``` Use `mem_do(action="help")` from your MCP client to see the action catalog for the installed version. The full v0.3.10 registry contains 96 current tools. Full mode also keeps the deprecated `mem_context_migrate` alias (97 registered names total) until its v0.5.0 removal. Pinned Context adds `mem_pinned_list/get/set/delete` and `mem_context_compose`; review-first formation adds `mem_formation_scan` and `mem_candidate_propose/list/review/recover`. `mem_candidate_propose` creates a privacy-scanned pending review item rather than durable memory. It requires `content`, `source`, `source_ref`, and an `idempotency_key`; approved candidates alone pass through the normal write path. ## OpenCode [Section titled “OpenCode”](#opencode) The npm plugin source exists but is not published. Configure a local MCP server in `opencode.json` today: ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "memtomem": { "type": "local", "command": ["uvx", "--isolated", "--from", "memtomem[all]==0.3.10", "memtomem-server"], "enabled": true, "timeout": 60000, "environment": {"MEMTOMEM_TOOL_MODE": "core"} } } } ``` After npm publication, OpenCode uses the singular configuration key `{"plugin": ["opencode-memtomem@0.1.0"]}`; there is no `opencode plugin add` command. ## Common Actions [Section titled “Common Actions”](#common-actions) | Category | Examples | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Namespace | `ns_list`, `ns_set`, `ns_assign`, `ns_update`, `ns_rename`, `ns_delete` | | Tags | `tag_list`, `tag_rename`, `tag_merge`, `tag_delete` | | Sessions | `session_start`, `session_end`, `session_list` | | Scratch | `scratch_set`, `scratch_get`, `scratch_promote` | | Context Gateway | `context_detect`, `context_init`, `context_generate`, `context_diff`, `context_sync`, `context_artifact_transfer` (move/copy skills, agents, commands across projects and tiers), `context_version`, `context_promote` | | Maintenance | `dedup_scan`, `dedup_merge`, `decay_scan`, `decay_expire`, `cleanup_orphans`, `auto_tag` | | Import / export | `export`, `import`, `import_obsidian`, `import_notion`, `ingest` | | Analytics | `activity`, `timeline`, `eval`, `reflect` | ## When to Change Modes [Section titled “When to Change Modes”](#when-to-change-modes) Stay in `core` when: * You are setting up memtomem for an agent. * You want lower prompt/tool-list overhead. * You are not sure which mode you need. Use `standard` when an MCP client works better with direct tools than `mem_do` routing. Use `full` when you are testing, writing docs, or manually exercising every tool. `full` intentionally exposes a large surface. ## CLI Mirrors [Section titled “CLI Mirrors”](#cli-mirrors) Most common MCP operations have CLI equivalents: | MCP | CLI | | -------------------------------- | ------------------ | | `mem_status` | `mm status` | | `mem_add` | `mm add` | | `mem_search` | `mm search` | | `mem_index` | `mm index` | | `mem_do(action="context_sync")` | `mm context sync` | | `mem_do(action="schedule_list")` | `mm schedule list` | If an agent is struggling to call the right tool, run the CLI command once yourself and then ask the agent to follow the same operation. # Multi-Agent Collaboration > Namespace-based isolation and sharing for cross-agent knowledge exchange. memtomem supports knowledge sharing between agents through namespace-based isolation and sharing. As a runtime-agnostic memory layer, it enables Human→Agent, Agent→Agent, and Agent→Human knowledge flows. ## Namespace Structure [Section titled “Namespace Structure”](#namespace-structure) ```plaintext agent-runtime:{agent-id} # Agent-private — only that agent can access shared # Shared — accessible by all agents ``` Each agent works in its own private namespace but can export useful knowledge to the shared namespace. ## 5-Step Workflow [Section titled “5-Step Workflow”](#5-step-workflow) ### Step 1: Register an Agent [Section titled “Step 1: Register an Agent”](#step-1-register-an-agent) ```plaintext mem_agent_register(agent_id="analyzer", description="Code analysis agent") ``` ### Step 2: Start a Session [Section titled “Step 2: Start a Session”](#step-2-start-a-session) ```plaintext mem_session_start(agent_id="analyzer") ``` The session record’s namespace auto-derives to `agent-runtime:analyzer`. Subsequent calls in this session inherit the agent scope without re-passing `agent_id`: * **Writes** — `mem_add(content="...")` and `mem_batch_add(...)` write to `agent-runtime:analyzer` automatically. Pass `namespace="shared"` explicitly to publish cross-agent on a single call. * **Reads** — `mem_agent_search` / `mem_agent_share` resolve to the agent scope without `agent_id=`. (`mem_search` itself stays single-agent — use `mem_agent_search` to read inside the agent scope.) ### Step 3: Search Knowledge [Section titled “Step 3: Search Knowledge”](#step-3-search-knowledge) ```plaintext mem_agent_search(query="auth module structure", include_shared=true) ``` With `include_shared=true`, searches both the agent’s own namespace and the shared namespace. ### Step 4: Share Knowledge [Section titled “Step 4: Share Knowledge”](#step-4-share-knowledge) ```plaintext mem_agent_share(chunk_id="...", target="shared") ``` Before the copy is written into a wider namespace, share re-scans the content with the trust-boundary redaction guard. Secret-looking content is blocked at share time (the block is recorded in the audit counters), so a sensitive chunk does not silently propagate into a wider namespace. ### Step 5: End the Session [Section titled “Step 5: End the Session”](#step-5-end-the-session) ```plaintext mem_session_end(summary="...") ``` ## Setting `agent_id` [Section titled “Setting agent\_id”](#setting-agent_id) `agent_id` is not auto-detected. The principle is the same across runtimes — **pass it explicitly when a session starts**, and it is inherited by subsequent calls through session context. ### Claude Code · Codex (MCP) [Section titled “Claude Code · Codex (MCP)”](#claude-code--codex-mcp) The MCP server does not identify which client is calling, so **fix the session-start rule in the agent’s instructions** (CLAUDE.md · AGENTS.md · system prompt). Example instruction: > At the start of a conversation, call `mem_session_start(agent_id="claude-code")` first to register the session. When acting as a new agent role, use `mem_agent_register(agent_id="planner", description="...")`. Once registered, later calls to `mem_search`, `mem_add`, and so on are routed to the `agent-runtime:{agent-id}` namespace without having to pass `agent_id` again. ### LangGraph · CrewAI (Python adapter) [Section titled “LangGraph · CrewAI (Python adapter)”](#langgraph--crewai-python-adapter) ```python from memtomem.integrations.langgraph import MemtomemStore store = MemtomemStore() await store.start_agent_session(agent_id="analyzer") # Subsequent store.search / store.add calls are isolated to the analyzer namespace ``` In multi-agent graphs, each node starts its own session with its own `agent_id`. Use `mem_agent_share` to publish outputs that need to cross agents to the `shared` namespace. ### CLI (`mm session`) [Section titled “CLI (mm session)”](#cli-mm-session) Use this to pre-register a session outside the server process. ```bash mm session start --agent-id planner ``` See [`mm session`](/ltm/cli/#mm-session) for the full subcommand surface (`start`, `end`, `list`, `events`, `wrap`). ### CLI (`mm agent`) [Section titled “CLI (mm agent)”](#cli-mm-agent) Use this to register or list agents and share chunks from a shell without an MCP client. Each command mirrors the `mem_agent_register` / `mem_agent_share` MCP tools above. ```bash mm agent register analyzer --description "Code analysis agent" --color "#534AB7" mm agent list # lists registered agent-runtime: namespaces + shared (--json supported) mm agent share --target shared ``` `mm agent share` also re-runs the redaction guard before copying; secret-looking content is blocked unless re-confirmed with `--force-unsafe`. See the [CLI reference](/ltm/cli/) for the full flag surface. ### Difference from `mm ingest` [Section titled “Difference from mm ingest”](#difference-from-mm-ingest) `mm ingest claude-memory`, `mm ingest gemini-memory`, and `mm ingest codex-memory` **do not** assign an `agent_id`. They load memories into fixed namespaces — `claude-memory:`, `gemini-memory:`, and `codex-memory:` — to consolidate per-editor memories into one searchable index. For per-agent isolation, use the MCP/adapter/CLI paths above to set `agent_id` explicitly. ## Interaction Patterns [Section titled “Interaction Patterns”](#interaction-patterns) ### Human → Agent [Section titled “Human → Agent”](#human--agent) When a developer works in Claude Code or Cursor, architecture decisions, coding patterns, and debugging history from previous sessions are automatically surfaced. ### Agent → Agent [Section titled “Agent → Agent”](#agent--agent) In LangGraph/CrewAI workflows, when an agent chain runs, the “test generation agent” reads the codebase structure that the “code analysis agent” published to the shared namespace via `mem_agent_share`. The shared LTM store is the cross-agent handoff point; intermediate outputs and decision history cross agents through that explicit share step. ### Agent → Human [Section titled “Agent → Human”](#agent--human) Knowledge accumulated by agents can be searched and browsed through the Web UI dashboard. When onboarding new team members, they can review architecture decisions, bug resolution patterns, and coding conventions at a glance. ## Related — AI Tool Memory Ingestion [Section titled “Related — AI Tool Memory Ingestion”](#related--ai-tool-memory-ingestion) `mm ingest {claude,gemini,codex}-memory` is a separate feature from per-agent isolation: it consolidates each AI editor’s memory directory into fixed namespaces (`*-memory:`) for unified indexing (see [Difference from `mm ingest`](#difference-from-mm-ingest) above). For the full options — source paths and slug behavior — see the [installation guide](/guides/installation/). # Operations and Web API > Readiness, API validation, indexing outcomes, upgrades, and production safety. ## Readiness and API documentation [Section titled “Readiness and API documentation”](#readiness-and-api-documentation) Run `mm web` and open `/api/docs` for the local OpenAPI interface. Automation should probe `GET /api/readiness`: it returns `200` when ready and `503` with `startup_unavailable` while required startup components are unavailable. Search supports `source_exact`, `chunk_type`, `created_from`, and `created_before`. Timestamps require a timezone and invalid or reversed ranges return `422`. Export supports namespace filtering. Initial indexing reports `success`, `partial`, or `failed` rather than collapsing every outcome into one success response. ## Operational checks [Section titled “Operational checks”](#operational-checks) ```bash mm status mm status --json mm warmup mm web status ``` For CI, treat a top-level `error` field in `mm status --json` as failure; the command keeps JSON output stable and may still exit zero for initialization errors. `mm upgrade` manages `uv tool` installs. Use `pipx upgrade memtomem` for pipx, update the lockfile and run `uv sync` for project dependencies, or update Git and run `uv sync --extra all` for a source checkout. The Web UI binds to loopback by default. Off-loopback access requires the explicit remote UI, trusted-origin, and trusted-host flags and should remain behind an authenticating reverse proxy. # Overview > What memtomem is — an MCP-native long-term memory server for AI agents. ## What is memtomem? [Section titled “What is memtomem?”](#what-is-memtomem) memtomem gives your AI agent **memory that persists across sessions and across agents**. It runs as a local MCP server — your agent uses the same tool-calling it already does, and past information becomes searchable. ## Use It When [Section titled “Use It When”](#use-it-when) * **You keep re-explaining yesterday’s decisions in today’s session** — memtomem solves the “every new session is a blank slate” problem. Walk through the flow in [Memory Persistence Across Sessions](/guides/memory-persistence/). * **You want notes or docs to be searchable by your agent** — point `mm index ~/notes` at a folder of Markdown / structured files and every MCP-connected agent can query it. * **Multiple agents need to share the same knowledge** — Claude Code, Cursor, Codex CLI, and any other MCP client share one memory store. ## Start in 3 Steps [Section titled “Start in 3 Steps”](#start-in-3-steps) ```bash uv tool install 'memtomem[all]' # 1. install mm init # 2. interactive setup claude mcp add memtomem -s user -- memtomem-server # 3. connect your agent ``` Full walkthrough (including other MCP clients) in [Quick Start](/guides/quickstart/). ## Core Concepts [Section titled “Core Concepts”](#core-concepts) * **Hybrid Search** — BM25 keyword + dense vector search merged via RRF, so exact identifiers and meaning-based queries both land. See [Hybrid Search](/ltm/hybrid-search/). * **Namespaces** — Per-agent private spaces (`agent-runtime:{id}`) plus a `shared` space for cross-agent knowledge. See [Multi-Agent Collaboration](/ltm/multi-agent/). * **Lifecycle Policies** — `auto_archive` / `auto_expire` / `auto_promote` / `auto_tag` run on a background scheduler, so memories are aged and promoted automatically. ## Architecture [Section titled “Architecture”](#architecture) ```plaintext AI Agent (Claude Code, Cursor, Antigravity CLI, …) ↕ MCP protocol memtomem server ↕ SQLite (FTS5 + sqlite-vec) ``` memtomem runs as a local MCP server. All data stays on your machine — SQLite for storage, ONNX for embeddings. No GPU, no external services, no account required. ## Relationship to STM [Section titled “Relationship to STM”](#relationship-to-stm) | | LTM (memtomem) | STM (memtomem-stm) | | ---------------- | ------------------------------------ | -------------------------------------------------------- | | **Role** | Persistent storage & search | Real-time proxy & compression | | **Required?** | Yes (core) | Optional | | **How it works** | Agent calls `mem_search` when needed | Relevant memories auto-injected into every tool response | The default setup is LTM alone. If you want token-optimized responses with proactive memory injection, add [memtomem-stm](/stm/overview/) as a proxy in front. ## Package Info [Section titled “Package Info”](#package-info) | | | | ------------------ | --------------------------------------------------------- | | **PyPI** | [`memtomem`](https://pypi.org/project/memtomem/) | | **Latest release** | `0.3.10` | | **CLI** | `mm` | | **License** | Apache 2.0 | | **GitHub** | [memtomem/memtomem](https://github.com/memtomem/memtomem) | ## Next Steps [Section titled “Next Steps”](#next-steps) * [Quick Start](/guides/quickstart/) — Install and store your first memory in 5 minutes * [Memory Persistence Across Sessions](/guides/memory-persistence/) — Save in session A, recall in session B * [Hybrid Search](/ltm/hybrid-search/) — How the search engine works * [Multi-Agent Collaboration](/ltm/multi-agent/) — Namespace design and sharing workflows * [Context Gateway](/ltm/context-gateway/) — Define agents / skills / commands once, then sync, move, or copy them across projects and runtimes * [MCP Tools](/ltm/mcp-tools/) — Full tool reference * [CLI Reference](/ltm/cli/) — `mm` command reference # Pinned Context and Review-First Memory > Compose bounded instructions before retrieval and review proposed memories before durable writes. Pinned Context stores small Markdown facts or instructions that must appear before ordinary retrieval. User, project-local, and project-shared blocks use the same privacy and confirmation rules as other memtomem writes. ```bash mm pinned set response-style \ --content "Prefer concise answers with runnable commands." --priority 10 mm pinned get response-style --scope user mm pinned compose "deployment checklist" mm pinned delete response-style --scope user ``` Use `--scope user|project_local|project_shared` for exact operations. A Git-tracked shared write requires `--confirm-project-shared`. Each block is limited to 2,000 characters. The 6,000-character value is the pinned budget for one compose request, not a global storage limit. The default complete bundle is 12,000 characters and never cuts a block in half. `mem_context_compose` schema 3 preserves adjacent context-window chunks while keeping matched hits ahead of neighboring context in the shared budget. ## Review-first proposals [Section titled “Review-first proposals”](#review-first-proposals) `mem_candidate_propose(content, source, source_ref, idempotency_key)` creates a privacy-scanned pending candidate and never writes durable memory. Pending candidates expire after 30 days. Reusing an idempotency key with the same proposal returns the original candidate; different content is rejected. Only an explicit approve decision invokes the normal durable write path. ```bash mm review list mm review show CANDIDATE_ID mm review approve CANDIDATE_ID --reviewer "$USER" mm review recover --stale-after-minutes 15 --actor "$USER" ``` ## LangGraph adapters [Section titled “LangGraph adapters”](#langgraph-adapters) `MemtomemBaseStore` implements LangGraph’s tuple-namespace JSON store. `MemtomemStore` is the higher-level async adapter for search, writes, sessions, and working memory. Its `config_overrides` apply after ambient config, making isolated graph databases explicit and preventing test writes from landing in the user’s default store. # Environment Variables > Configuration reference for memtomem LTM and STM environment variables. Both memtomem (LTM) and memtomem-stm (STM) use [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) with `env_prefix` + `env_nested_delimiter="__"`. **Nested settings use double underscore** — `MEMTOMEM_EMBEDDING__PROVIDER`, not `MEMTOMEM_EMBEDDING_PROVIDER`. Resolution order (highest priority first): CLI flags → environment variables → config file → built-in defaults. This public reference tracks the `memtomem` 0.3.10 and `memtomem-stm` 0.1.38 configuration surfaces. ## LTM (memtomem) — prefix `MEMTOMEM_` [Section titled “LTM (memtomem) — prefix MEMTOMEM\_”](#ltm-memtomem--prefix-memtomem_) ### Storage [Section titled “Storage”](#storage) | Variable | Description | Default | | ----------------------------------- | ------------------------- | ------------------------- | | `MEMTOMEM_STORAGE__BACKEND` | Storage backend | `sqlite` | | `MEMTOMEM_STORAGE__SQLITE_PATH` | SQLite database file path | `~/.memtomem/memtomem.db` | | `MEMTOMEM_STORAGE__COLLECTION_NAME` | Logical collection name | `memories` | ### Embedding [Section titled “Embedding”](#embedding) | Variable | Description | Default | | -------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------ | | `MEMTOMEM_EMBEDDING__PROVIDER` | `none` / `onnx` / `ollama` / `openai` | `none` (keyword-only until `mm init` runs) | | `MEMTOMEM_EMBEDDING__MODEL` | Model name for the chosen provider | `""` | | `MEMTOMEM_EMBEDDING__DIMENSION` | Vector dimension (must match model) | provider-specific | | `MEMTOMEM_EMBEDDING__BASE_URL` | Ollama / OpenAI-compatible endpoint | — | | `MEMTOMEM_EMBEDDING__API_KEY` | API key for paid providers | — | | `MEMTOMEM_EMBEDDING__BATCH_SIZE` | Texts per embedding batch | `64` | | `MEMTOMEM_EMBEDDING__MAX_CONCURRENT_BATCHES` | Max parallel embedding batches | `4` | | `MEMTOMEM_EMBEDDING__THREADS` | ONNX Runtime thread cap (`0` = ORT default) | `4` | | `MEMTOMEM_EMBEDDING__PROGRESS_THRESHOLD` | Emit per-chunk progress only when a file produces more chunks than this threshold; `0` always emits | `32` | ### Indexing [Section titled “Indexing”](#indexing) | Variable | Description | Default | | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | `MEMTOMEM_INDEXING__MEMORY_DIRS` | Directories reactively re-indexed by the `mm server` file watcher (JSON list). Pre-existing files are not auto-scanned — seed them once with `mm index `, then the watcher picks up further edits. Populated by `mm init` when you opt in to AI agent memory enrollment. | `["~/.memtomem/memories"]` plus selected provider folders | | `MEMTOMEM_INDEXING__PROJECT_MEMORY_DIRS` | Project-tier memory roots under `.memtomem/memories` or `.memtomem/memories.local` | `[]` | | `MEMTOMEM_INDEXING__SUPPORTED_EXTENSIONS` | File extensions to index (JSON list) | `[".md", ".json", ".yaml", ".yml", ".toml", ".py", ".js", ".ts", ".tsx", ".jsx"]` | | `MEMTOMEM_INDEXING__MAX_CHUNK_TOKENS` | Maximum tokens per chunk | `512` | | `MEMTOMEM_INDEXING__MIN_CHUNK_TOKENS` | Merge threshold for short chunks | `128` | | `MEMTOMEM_INDEXING__AUTO_DISCOVER` | When `true`, `mm init` prompts to enroll AI agent memory directories into `memory_dirs`. Set `false` to skip the prompt. | `true` | | `MEMTOMEM_INDEXING__EXCLUDE_PATTERNS` | `.gitignore`-syntax patterns (JSON list) that stack on top of the built-in credential denylist (`oauth_creds.json`, `credentials*`, `id_rsa*`, `*.pem`, `*.key`, `.ssh/**`, …). User `!negation` cannot override the built-in secret patterns. | `[]` | | `MEMTOMEM_INDEXING__TARGET_CHUNK_TOKENS` | Greedy semantic-pack target for short sibling sections. Set `0` to disable the pack pass. | `384` | | `MEMTOMEM_INDEXING__CHUNK_OVERLAP_TOKENS` | Token overlap between adjacent chunks | `0` | | `MEMTOMEM_INDEXING__STRUCTURED_CHUNK_MODE` | JSON/YAML/TOML chunking mode: `original` or `recursive` | `original` | | `MEMTOMEM_INDEXING__PARAGRAPH_SPLIT_THRESHOLD` | Split long prose into paragraphs above this token count | `800` | | `MEMTOMEM_INDEXING__STARTUP_BACKFILL` | On server start, run a one-shot scan over `memory_dirs` to catch files added while the server was down | `false` | | `MEMTOMEM_INDEXING__AUTO_SUMMARIZE` | Generate AI per-source summaries when LLM is configured | `false` | | `MEMTOMEM_INDEXING__SUMMARY_LANGUAGE` | Output language for AI source summaries | `en` | | `MEMTOMEM_INDEXING__SUMMARY_MAX_INPUT_CHARS` | Max source chars sent to the summary LLM | `3000` | | `MEMTOMEM_INDEXING__SUMMARY_MAX_TOKENS` | Summary output token cap | `256` | ### Namespace Policy Rules [Section titled “Namespace Policy Rules”](#namespace-policy-rules) Path-glob → namespace mappings that auto-tag files at index time, so you don’t pass `namespace=` on every `mem_index` call. | Variable | Description | Default | | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | `MEMTOMEM_NAMESPACE__RULES` | JSON list of `{path_glob, namespace}` objects. `pathspec.GitIgnoreSpec` patterns, case-insensitive. `{parent}` and `{ancestor:N}` placeholders expand from the matched file path. Resolution order: explicit `namespace=` param → rules (first match) → `enable_auto_ns` → `default_namespace`. | `[]` | | `MEMTOMEM_NAMESPACE__DEFAULT_NAMESPACE` | Default namespace for new chunks | `default` | | `MEMTOMEM_NAMESPACE__ENABLE_AUTO_NS` | Derive namespace from a file’s immediate parent folder when no explicit namespace or rule applies | `false` | Example (via `config.d/namespace.json`, APPEND-merged): ```json {"namespace": {"rules": [ {"path_glob": "docs/**", "namespace": "docs"}, {"path_glob": "projects/{parent}/**", "namespace": "proj/{parent}"} ]}} ``` ### Reranking [Section titled “Reranking”](#reranking) Cross-encoder reranking runs fully locally by default — no external API required. | Variable | Description | Default | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | `MEMTOMEM_RERANK__ENABLED` | Enable reranking of hybrid search results | `false` | | `MEMTOMEM_RERANK__PROVIDER` | `fastembed` (local ONNX) / `cohere` (external API) | `fastembed` | | `MEMTOMEM_RERANK__MODEL` | Model name. Use `jinaai/jina-reranker-v2-base-multilingual` for non-English content. | `Xenova/ms-marco-MiniLM-L-6-v2` | | `MEMTOMEM_RERANK__API_KEY` | Only required when `provider=cohere` | — | | `MEMTOMEM_RERANK__OVERSAMPLE` | Pool multiplier over `response_top_k`. Pool size is `max(min_pool, min(max_pool, int(oversample * response_top_k)))`. | `2.0` | | `MEMTOMEM_RERANK__MIN_POOL` | Floor — reranker never sees fewer candidates than this | `20` | | `MEMTOMEM_RERANK__MAX_POOL` | Cap — prevents runaway cost at large `top_k` | `200` | | `MEMTOMEM_RERANK__TOP_K` | Deprecated legacy pool size; migrates to `min_pool` when present | `20` | ### Search [Section titled “Search”](#search) | Variable | Description | Default | | -------------------------------------------- | ---------------------------------------------------------------------------------------- | -------------------------------- | | `MEMTOMEM_SEARCH__DEFAULT_TOP_K` | Default result count | `10` | | `MEMTOMEM_SEARCH__BM25_CANDIDATES` | BM25 candidate pool size | `50` | | `MEMTOMEM_SEARCH__DENSE_CANDIDATES` | Dense vector candidate pool size | `50` | | `MEMTOMEM_SEARCH__RRF_K` | Reciprocal Rank Fusion constant | `60` | | `MEMTOMEM_SEARCH__ENABLE_BM25` | Enable keyword retriever | `true` | | `MEMTOMEM_SEARCH__ENABLE_DENSE` | Enable semantic vector retriever | `true` | | `MEMTOMEM_SEARCH__RRF_WEIGHTS` | RRF weights for `[BM25, Dense]` (JSON list, REPLACE merge) | `[1.0, 1.0]` | | `MEMTOMEM_SEARCH__TOKENIZER` | FTS tokenizer: `unicode61` or `kiwipiepy` | `unicode61` | | `MEMTOMEM_SEARCH__CACHE_TTL` | Search result cache TTL in seconds | `30.0` | | `MEMTOMEM_SEARCH__SYSTEM_NAMESPACE_PREFIXES` | Namespace prefixes hidden from default `namespace=None` search (JSON list, APPEND merge) | `["archive:", "agent-runtime:"]` | ### Decay (time-based scoring) [Section titled “Decay (time-based scoring)”](#decay-time-based-scoring) Half-life decay multiplier applied to hybrid-search scores. Gradually deprioritises older chunks. | Variable | Description | Default | | -------------------------------- | ---------------------------------------------------------------- | ------- | | `MEMTOMEM_DECAY__ENABLED` | Enable time-based decay weighting | `false` | | `MEMTOMEM_DECAY__HALF_LIFE_DAYS` | Half-life in days — a chunk’s contribution halves every interval | `30.0` | ### MMR (diversity rerank) [Section titled “MMR (diversity rerank)”](#mmr-diversity-rerank) Maximal Marginal Relevance rerank. Reduces redundancy among top results and mixes in alternate angles. | Variable | Description | Default | | ---------------------------- | ----------------------------------------------------- | ------- | | `MEMTOMEM_MMR__ENABLED` | Enable MMR diversity rerank | `false` | | `MEMTOMEM_MMR__LAMBDA_PARAM` | 0.0–1.0. `0.0` = max diversity, `1.0` = max relevance | `0.7` | ### Access (frequency boost) [Section titled “Access (frequency boost)”](#access-frequency-boost) Frequency-based multiplier that promotes chunks which have been accessed often. | Variable | Description | Default | | ---------------------------- | ------------------------------------------- | ------- | | `MEMTOMEM_ACCESS__ENABLED` | Enable access-frequency boost | `false` | | `MEMTOMEM_ACCESS__MAX_BOOST` | Score multiplier ceiling (must be `>= 1.0`) | `1.5` | ### Importance (metadata boost) [Section titled “Importance (metadata boost)”](#importance-metadata-boost) Multiplier derived from chunk metadata features (tags, size, position, …) applied on top of the search score. | Variable | Description | Default | | -------------------------------- | ----------------------------------------------------------- | ---------------------- | | `MEMTOMEM_IMPORTANCE__ENABLED` | Enable importance boost | `false` | | `MEMTOMEM_IMPORTANCE__MAX_BOOST` | Score multiplier ceiling (must be `>= 1.0`) | `1.5` | | `MEMTOMEM_IMPORTANCE__WEIGHTS` | Importance-feature weight vector (JSON list, REPLACE merge) | `[0.3, 0.2, 0.3, 0.2]` | ### Query expansion [Section titled “Query expansion”](#query-expansion) Augments the original query with related tags, headings, or LLM-generated terms to improve recall. `strategy=llm` uses the LLM section below. | Variable | Description | Default | | ------------------------------------- | ------------------------------------ | ------- | | `MEMTOMEM_QUERY_EXPANSION__ENABLED` | Enable query expansion | `false` | | `MEMTOMEM_QUERY_EXPANSION__MAX_TERMS` | Max additional terms to append | `3` | | `MEMTOMEM_QUERY_EXPANSION__STRATEGY` | `tags` / `headings` / `both` / `llm` | `tags` | ### Context window [Section titled “Context window”](#context-window) Small-to-big retrieval: returns ±N adjacent chunks around each search hit. Useful for recovering fragmented context in long documents. | Variable | Description | Default | | -------------------------------------- | ------------------------------------- | ------- | | `MEMTOMEM_CONTEXT_WINDOW__ENABLED` | Enable context-window expansion | `false` | | `MEMTOMEM_CONTEXT_WINDOW__WINDOW_SIZE` | ±N adjacent chunks per hit (`0`–`10`) | `2` | ### LLM (summarisation · query-expansion backend) [Section titled “LLM (summarisation · query-expansion backend)”](#llm-summarisation--query-expansion-backend) Shared LLM backend used by `query_expansion.strategy=llm`, consolidation summaries, and other LLM-powered features. | Variable | Description | Default | | -------------------------- | ------------------------------------------------------- | ------------------------ | | `MEMTOMEM_LLM__ENABLED` | Enable LLM-powered features | `false` | | `MEMTOMEM_LLM__PROVIDER` | `ollama` / `openai` / `anthropic` / compatible endpoint | `ollama` | | `MEMTOMEM_LLM__MODEL` | Model name. Empty = provider-specific default | `""` | | `MEMTOMEM_LLM__BASE_URL` | Endpoint URL | `http://localhost:11434` | | `MEMTOMEM_LLM__API_KEY` | API key for paid providers | — | | `MEMTOMEM_LLM__MAX_TOKENS` | Generation token cap | `1024` | | `MEMTOMEM_LLM__TIMEOUT` | Request timeout in seconds | `60.0` | ### Tool exposure [Section titled “Tool exposure”](#tool-exposure) | Variable | Description | Default | | -------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------- | | `MEMTOMEM_TOOL_MODE` | `core` (9 names incl. `mem_do`) / `standard` (38) / `full` (96 current tools + deprecated `mem_context_migrate` alias) | `core` | ### Web UI [Section titled “Web UI”](#web-ui) | Variable | Description | Default | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `MEMTOMEM_WEB__MODE` | `prod` (polished pages only) / `dev` (adds maintainer pages: Sessions, Namespaces, Health Report). `mm web --mode` and `mm web --dev` override this at launch. | `prod` | ### Lifecycle policies & webhooks [Section titled “Lifecycle policies & webhooks”](#lifecycle-policies--webhooks) | Variable | Description | Default | | --------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------- | | `MEMTOMEM_POLICY__ENABLED` | Run PolicyScheduler (auto\_archive / auto\_promote / auto\_expire / auto\_tag) | `false` | | `MEMTOMEM_POLICY__SCHEDULER_INTERVAL_MINUTES` | Scheduler tick interval | `60.0` | | `MEMTOMEM_POLICY__MAX_ACTIONS_PER_RUN` | Cumulative action cap per scheduled policy run | `100` | | `MEMTOMEM_WEBHOOK__ENABLED` | Enable outbound webhooks for memory events | `false` | | `MEMTOMEM_WEBHOOK__URL` | Webhook target URL | — | | `MEMTOMEM_WEBHOOK__EVENTS` | Event types to send (JSON list, APPEND merge) | `["add", "delete", "search"]` | | `MEMTOMEM_WEBHOOK__SECRET` | HMAC signing secret | — | | `MEMTOMEM_WEBHOOK__TIMEOUT_SECONDS` | HTTP timeout | `10.0` | ### Consolidation schedule [Section titled “Consolidation schedule”](#consolidation-schedule) Background job that periodically groups near-duplicate memories and compresses them into archive summaries. | Variable | Description | Default | | ------------------------------------------------- | --------------------------------- | ------- | | `MEMTOMEM_CONSOLIDATION_SCHEDULE__ENABLED` | Run the consolidation scheduler | `false` | | `MEMTOMEM_CONSOLIDATION_SCHEDULE__INTERVAL_HOURS` | Scheduler interval (hours) | `24.0` | | `MEMTOMEM_CONSOLIDATION_SCHEDULE__MIN_GROUP_SIZE` | Minimum group size to consolidate | `3` | | `MEMTOMEM_CONSOLIDATION_SCHEDULE__MAX_GROUPS` | Max groups processed per run | `10` | ### Health watchdog [Section titled “Health watchdog”](#health-watchdog) Background loop for periodic health checks, orphan-record cleanup, and automatic maintenance. | Variable | Description | Default | | ------------------------------------------------------- | ------------------------------- | -------- | | `MEMTOMEM_HEALTH_WATCHDOG__ENABLED` | Run the health watchdog | `false` | | `MEMTOMEM_HEALTH_WATCHDOG__HEARTBEAT_INTERVAL_SECONDS` | Heartbeat interval | `60.0` | | `MEMTOMEM_HEALTH_WATCHDOG__DIAGNOSTIC_INTERVAL_SECONDS` | Diagnostic-check interval | `300.0` | | `MEMTOMEM_HEALTH_WATCHDOG__DEEP_INTERVAL_SECONDS` | Deep-scan interval | `3600.0` | | `MEMTOMEM_HEALTH_WATCHDOG__MAX_SNAPSHOTS` | Snapshot retention cap | `1000` | | `MEMTOMEM_HEALTH_WATCHDOG__ORPHAN_CLEANUP_THRESHOLD` | Orphan-record cleanup threshold | `10` | | `MEMTOMEM_HEALTH_WATCHDOG__AUTO_MAINTENANCE` | Perform automatic maintenance | `true` | ### Scheduler [Section titled “Scheduler”](#scheduler) | Variable | Description | Default | | -------------------------------------------- | ---------------------------------------------------- | ------- | | `MEMTOMEM_SCHEDULER__ENABLED` | Enable cron dispatch for registered maintenance jobs | `false` | | `MEMTOMEM_SCHEDULER__MAX_CONCURRENT_JOBS` | Max concurrently running scheduled jobs | `1` | | `MEMTOMEM_SCHEDULER__DEFAULT_TIMEZONE` | Schedule timezone; Phase A honors `utc` | `utc` | | `MEMTOMEM_SCHEDULER__RUNNER_TIMEOUT_SECONDS` | Timeout for one scheduled job run | `300.0` | ### Session summary [Section titled “Session summary”](#session-summary) | Variable | Description | Default | | ----------------------------------------------------- | ------------------------------------------------------------------------------- | ------- | | `MEMTOMEM_SESSION_SUMMARY__AUTO` | Auto-generate an LLM summary on `mem_session_end` when enough chunks were added | `true` | | `MEMTOMEM_SESSION_SUMMARY__MIN_CHUNKS` | Minimum chunks before auto-summary runs | `5` | | `MEMTOMEM_SESSION_SUMMARY__MAX_SUMMARY_TOKENS` | Output token cap | `500` | | `MEMTOMEM_SESSION_SUMMARY__MAX_INPUT_CHARS` | Skip auto-summary above this assembled input size | `60000` | | `MEMTOMEM_SESSION_SUMMARY__MAX_SUMMARY_LINKS` | Cap summary-to-source chunk links | `50` | | `MEMTOMEM_SESSION_SUMMARY__EXPANSION_LOOKUP_TOP_K` | Session-summary chunks considered for search rescue | `3` | | `MEMTOMEM_SESSION_SUMMARY__EXPANSION_SCORE_THRESHOLD` | Minimum summary score for rescue expansion | `0.3` | | `MEMTOMEM_SESSION_SUMMARY__EXPANSION_RESCUE_WEIGHT` | RRF input weight for rescued source-file hits | `0.5` | ### Session tracing [Section titled “Session tracing”](#session-tracing) Traces session command execution to a JSONL file and, optionally, to Langfuse. Off by default. `payload_mode` defaults to `metadata`, which records no payload body; `redacted` keeps a secret-masked body, and `full` keeps the entire body. | Variable | Description | Default | | --------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------- | | `MEMTOMEM_SESSION_TRACE__ENABLED` | Enable session execution tracing | `false` | | `MEMTOMEM_SESSION_TRACE__JSONL_ENABLED` | Write to the JSONL sink | `true` | | `MEMTOMEM_SESSION_TRACE__JSONL_PATH` | JSONL output file path | `~/.memtomem/traces/session-traces.jsonl` | | `MEMTOMEM_SESSION_TRACE__LANGFUSE_ENABLED` | Emit traces to the Langfuse sink | `false` | | `MEMTOMEM_SESSION_TRACE__LANGFUSE_PUBLIC_KEY` | Langfuse public key | `""` | | `MEMTOMEM_SESSION_TRACE__LANGFUSE_SECRET_KEY` | Langfuse secret key | `""` | | `MEMTOMEM_SESSION_TRACE__LANGFUSE_HOST` | Langfuse host URL | `""` | | `MEMTOMEM_SESSION_TRACE__SAMPLING_RATE` | 0.0–1.0. Fraction of sessions recorded | `1.0` | | `MEMTOMEM_SESSION_TRACE__PAYLOAD_MODE` | `metadata` (no body) / `redacted` (secret-masked body) / `full` (entire body) | `metadata` | | `MEMTOMEM_SESSION_TRACE__MAX_PAYLOAD_CHARS` | Char cap on payload retained in a trace | `10000` | Setting `langfuse_enabled=true` requires the `langfuse` extra installed and both the public and secret keys set; otherwise startup validation fails. ### Logging [Section titled “Logging”](#logging) | Variable | Description | Default | | --------------------- | -------------------------------------- | ------- | | `MEMTOMEM_LOG_LEVEL` | `DEBUG` / `INFO` / `WARNING` / `ERROR` | `INFO` | | `MEMTOMEM_LOG_FORMAT` | Log format | — | ### Hooks / Context Gateway [Section titled “Hooks / Context Gateway”](#hooks--context-gateway) | Variable | Description | Default | | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | `MEMTOMEM_HOOKS__TARGET_SCOPE` | Scope for memtomem-managed Claude Code settings hooks: `user`, `project_shared`, or `project_local` | `user` | | `MEMTOMEM_CONTEXT_GATEWAY__KNOWN_PROJECTS_PATH` | Web UI project registry for Context Gateway | `~/.memtomem/known_projects.json` | | `MEMTOMEM_CONTEXT_GATEWAY__EXPERIMENTAL_CLAUDE_PROJECTS_SCAN` | Decode `~/.claude/projects/` directory names back into project roots and scan them (includes unverified candidates) | `false` | | `MEMTOMEM_CONTEXT_GATEWAY__AUTO_DISPLAY_CONFIGURED_PROJECTS` | Auto-display a scanned project only when its root carries a recognized runtime marker (`.claude`/`.gemini`/`.codex`/`.agents`/`.kimi`/`.memtomem`) | `true` | | `MEMTOMEM_CONTEXT_GATEWAY__USER_TIER_ENABLED` | Forward-compat field gating writes to the User tier (host-global artifacts). While `false`, the User tier is hidden from discovery responses | `false` | ### Embedding provider comparison [Section titled “Embedding provider comparison”](#embedding-provider-comparison) | Provider | GPU | Cost | Notes | | -------- | --- | ---- | ----------------------------------------------- | | `onnx` | No | Free | Built-in via fastembed. \~270 MB on first run | | `ollama` | No | Free | Requires Ollama. `ollama pull nomic-embed-text` | | `openai` | No | Paid | Requires API key | > Full list: [configuration.md](https://github.com/memtomem/memtomem/blob/main/docs/guides/configuration.md) in the upstream repo. ## STM (memtomem-stm) — prefix `MEMTOMEM_STM_` [Section titled “STM (memtomem-stm) — prefix MEMTOMEM\_STM\_”](#stm-memtomem-stm--prefix-memtomem_stm_) STM settings are organized into six sections: a flat `LOG_LEVEL`, plus `PROXY__*`, `SURFACING__*`, `HOOK__*`, `DAEMON__*`, and `LANGFUSE__*`. Compression, caching, metrics, auto-indexing, and extraction all live **under `PROXY__`**. ### General [Section titled “General”](#general) | Variable | Description | Default | | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | `MEMTOMEM_STM_LOG_LEVEL` | Log level | `WARNING` | | `MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS` | When `true`, advertises eight observability/admin tools (`stm_proxy_stats`, `stm_proxy_health`, `stm_proxy_cache_clear`, `stm_surfacing_stats`, `stm_selection_stats`, `stm_compression_stats`, `stm_progressive_stats`, `stm_tuning_recommendations`). The four model-facing tools remain visible when false. | `false` | | `MEMTOMEM_STM_FORMATION__ENABLED` | Advertise the opt-in `stm_memory_propose` tool. This flag alone controls advertisement; upstream LTM support for review-first proposals is checked at call time (an incompatible core returns `formation_unsupported`). | `false` | ### Proxy [Section titled “Proxy”](#proxy) | Variable | Description | Default | | ---------------------------------------------- | ------------------------------------ | ---------- | | `MEMTOMEM_STM_PROXY__ENABLED` | Master switch for the proxy pipeline | `false` | | `MEMTOMEM_STM_PROXY__DEFAULT_COMPRESSION` | Default compression strategy | `auto` | | `MEMTOMEM_STM_PROXY__DEFAULT_MAX_RESULT_CHARS` | Per-response char budget | `16000` | | `MEMTOMEM_STM_PROXY__MAX_UPSTREAM_CHARS` | OOM guard on upstream response size | `10000000` | | `MEMTOMEM_STM_PROXY__MIN_RESULT_RETENTION` | Retention floor (0.0–1.0) | `0.65` | ### Proxy → Cache [Section titled “Proxy → Cache”](#proxy--cache) | Variable | Description | Default | | ------------------------------------------------ | ----------------------- | ------- | | `MEMTOMEM_STM_PROXY__CACHE__ENABLED` | Enable response caching | `true` | | `MEMTOMEM_STM_PROXY__CACHE__DEFAULT_TTL_SECONDS` | Cache TTL | `3600` | | `MEMTOMEM_STM_PROXY__CACHE__DB_PATH` | Cache DB location | — | | `MEMTOMEM_STM_PROXY__CACHE__MAX_ENTRIES` | Cache eviction ceiling | — | ### Proxy → Auto-Index (Stage 4) [Section titled “Proxy → Auto-Index (Stage 4)”](#proxy--auto-index-stage-4) | Variable | Description | Default | | -------------------------------------------- | ---------------------------------------------------- | ---------------- | | `MEMTOMEM_STM_PROXY__AUTO_INDEX__ENABLED` | Index tool responses into LTM | `false` | | `MEMTOMEM_STM_PROXY__AUTO_INDEX__BACKGROUND` | Run indexing in the background, off the request path | `false` | | `MEMTOMEM_STM_PROXY__AUTO_INDEX__MIN_CHARS` | Minimum response size to index | — | | `MEMTOMEM_STM_PROXY__AUTO_INDEX__MEMORY_DIR` | Output directory | — | | `MEMTOMEM_STM_PROXY__AUTO_INDEX__NAMESPACE` | Namespace for auto-indexed memories | `proxy-{server}` | The bundled `mms` server reads from LTM but, by design, does not write back to it. These `auto_index` and extraction fields are therefore accepted as valid config but have no effect on its behavior. ### Proxy → Metrics / Extraction / Relevance scorer [Section titled “Proxy → Metrics / Extraction / Relevance scorer”](#proxy--metrics--extraction--relevance-scorer) | Variable | Description | Default | | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------- | | `MEMTOMEM_STM_PROXY__METRICS__ENABLED` | Record call metrics | `true` | | `MEMTOMEM_STM_PROXY__EXTRACTION__ENABLED` | Stage 4b EXTRACT (fact extraction) | `false` | | `MEMTOMEM_STM_PROXY__RELEVANCE_SCORER__SCORER` | Scorer backend | — | | `MEMTOMEM_STM_PROXY__COMPRESSION_FEEDBACK__ENABLED` | Persist `stm_compression_feedback` | `true` | | `MEMTOMEM_STM_PROXY__PROGRESSIVE_READS__ENABLED` | Record progressive-delivery read telemetry (surfaces via `stm_progressive_stats`) | `true` | | `MEMTOMEM_STM_PROXY__LOCK_TIMEOUT_SECONDS` | Internal lock-acquisition ceiling; a timeout signals a deadlock/stuck holder rather than a slow upstream | `30.0` | ### Proxy → Tool exposure [Section titled “Proxy → Tool exposure”](#proxy--tool-exposure) An STM-native filter that decides, at tool-advertisement time, which of an upstream’s tools the agent gets to see. Tools that fail consistently, carry credentials, or duplicate another tool’s name are kept out of the advertised list. Health signals are evaluated once at proxy startup, so the advertised set stays stable for the session. | Variable | Description | Default | | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | `MEMTOMEM_STM_PROXY__EXPOSURE__PROFILE` | `strict` (signal rules hard-reject) / `review` (demote in ranking instead of rejecting, recorded in telemetry) / `explore` (signal rules off) | `strict` | | `MEMTOMEM_STM_PROXY__EXPOSURE__HEALTH_WINDOW_HOURS` | Look-back window over the metrics store for per-tool health | `24.0` | | `MEMTOMEM_STM_PROXY__EXPOSURE__HEALTH_MIN_CALLS` | Minimum calls in the window before health is judged; below this a tool is presumed healthy | `5` | | `MEMTOMEM_STM_PROXY__EXPOSURE__HEALTH_ERROR_RATE_THRESHOLD` | Upstream-attributable error rate at or above which a tool is flagged unhealthy | `0.95` | | `MEMTOMEM_STM_PROXY__EXPOSURE__REVIEW_RISK_PENALTY` | Ranking-demotion multiplier applied to signal-flagged tools under the `review` profile | `0.5` | ### Proxy → Selection telemetry / Tool relevance [Section titled “Proxy → Selection telemetry / Tool relevance”](#proxy--selection-telemetry--tool-relevance) Records one selection + execution entry per proxied call as JSONL, and BM25-ranks the advertised tool set against the call’s query signal. Ranking is recorded into telemetry only — it never changes exposure. | Variable | Description | Default | | ------------------------------------------------------ | ------------------------------------------------------------------------------------- | ------------------------------------- | | `MEMTOMEM_STM_PROXY__SELECTION_TELEMETRY__ENABLED` | Enable per-call selection/execution JSONL records | `false` | | `MEMTOMEM_STM_PROXY__SELECTION_TELEMETRY__PATH` | JSONL log path | `~/.memtomem/stm_selection_log.jsonl` | | `MEMTOMEM_STM_PROXY__SELECTION_TELEMETRY__SAMPLE_RATE` | 0.0–1.0. Fraction of calls recorded | `1.0` | | `MEMTOMEM_STM_PROXY__SELECTION_TELEMETRY__MAX_BYTES` | Rotate the log at this size | `50000000` | | `MEMTOMEM_STM_PROXY__SELECTION_TELEMETRY__MAX_BACKUPS` | Rotated files kept (`0` truncates instead) | `3` | | `MEMTOMEM_STM_PROXY__TOOL_RELEVANCE__ENABLED` | Record per-call BM25 tool ranking; only takes effect when `selection_telemetry` is on | `true` | | `MEMTOMEM_STM_PROXY__TOOL_RELEVANCE__TOP_N` | Ranked candidates recorded per selection event | `20` | ### Proxy → Tool-graph eligibility (optional) [Section titled “Proxy → Tool-graph eligibility (optional)”](#proxy--tool-graph-eligibility-optional) Consults a separate tool-graph MCP server for cross-server authorization / data-flow eligibility and feeds the verdict into the exposure filter as an extra rule source. Off by default. The graph server is consulted, never proxied — the client never sees its tools. | Variable | Description | Default | | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ENABLED` | Enable the external tool-graph eligibility provider | `false` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__COMMAND` | Launch command for the stdio tool-graph MCP server | `toolgraph` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ARGS` | Command args (JSON list) | `["serve"]` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ENV` | Extra environment for the graph server (e.g. `NEO4J_*`, JSON object) | `null` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__AGENT_ID` | Identity (registered in the graph) that eligibility is authorized against | `stm-proxy` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__QUERY_PROFILE` | Profile passed to the graph consult | `strict` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ON_UNREACHABLE` | Graph unreachable: `open` (advertise per STM-native rules) / `closed` (withhold every tool the graph did not bless) | `open` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ON_TOOL_NOT_FOUND` | Candidate not in the graph: `open` / `closed` | `open` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ON_AGENT_NOT_FOUND` | `agent_id` unknown (usually a typo): `fail_start` / `open` / `closed` | `fail_start` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__ON_PROTOCOL_ERROR` | Graph response contract violation: `fail_start` / `open` / `closed` | `fail_start` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__RISK_PENALTY_SCALE` | Ranking-demotion multiplier for eligible-but-risky tools | `1.0` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__TIMEOUT_SECONDS` | Per-consult timeout | `5.0` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__CONSULT_CACHE_ENABLED` | Disk-cache a successful consult’s verdict | `true` | | `MEMTOMEM_STM_PROXY__TOOLGRAPH__CONSULT_CACHE_PATH` | SQLite path for the consult cache | `~/.memtomem/toolgraph_consult.db` | ### Per-upstream (`UpstreamServerConfig`) [Section titled “Per-upstream (UpstreamServerConfig)”](#per-upstream-upstreamserverconfig) These live on per-upstream `UpstreamServerConfig` entries in `~/.memtomem/stm_proxy.json` (set per server, not via env vars). The timeout fields fall back to the defaults below for every registered upstream unless overridden. | Field | Description | Default | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `surfacing_enabled` | Opt this upstream’s responses in/out of proactive surfacing. `false` suppresses surfacing for every tool on this server. | `true` | | `origin` | Import-provenance block. Written by `mms add --import`/`mms init` and used later by `mms eject` to restore the original entry to the host config. | — | | `call_timeout_seconds` | Per-attempt timeout for `session.call_tool()`. On timeout the session is force-reset and the retry loop proceeds. | `90.0` | | `overall_deadline_seconds` | Total wall-clock budget across all retry attempts. Prevents `call_timeout × (max_retries+1)` worst-case blowout. | `180.0` | | `compression.llm.llm_timeout_seconds` | Timeout for `llm_summary` compression; on timeout STM falls back to `truncate`. | `60.0` | ### Surfacing (Stage 3) [Section titled “Surfacing (Stage 3)”](#surfacing-stage-3) | Variable | Description | Default | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------- | | `MEMTOMEM_STM_SURFACING__ENABLED` | Enable proactive surfacing from LTM | `true` | | `MEMTOMEM_STM_SURFACING__MIN_SCORE` | Minimum relevance score | `0.03` | | `MEMTOMEM_STM_SURFACING__MAX_RESULTS` | Max memories injected per call | `3` | | `MEMTOMEM_STM_SURFACING__MIN_RESPONSE_CHARS` | Skip surfacing on tiny responses | `5000` | | `MEMTOMEM_STM_SURFACING__MIN_QUERY_TOKENS` | Min tokens in extracted query | `3` | | `MEMTOMEM_STM_SURFACING__DEDUP_TTL_SECONDS` | Cross-session dedup window | `604800` (7 days) | | `MEMTOMEM_STM_SURFACING__FEEDBACK_ENABLED` | Accept `stm_surfacing_feedback` | `true` | | `MEMTOMEM_STM_SURFACING__AUTO_TUNE_ENABLED` | Per-tool threshold auto-tuning | `true` | | `MEMTOMEM_STM_SURFACING__QUERY_RETENTION_DAYS` | Days to retain raw query text in the feedback DB before clearing the column; `0` disables cleanup | `30` | | `MEMTOMEM_STM_SURFACING__PERSIST_QUERY_TEXT` | Store raw query text when `true`; store `sha256:<16-hex>` digests when `false` | `true` | | `MEMTOMEM_STM_SURFACING__FEEDBACK_DEMOTION_ENABLED` | Locally filter memories with repeated negative feedback before injection | `true` | | `MEMTOMEM_STM_SURFACING__FEEDBACK_DEMOTION_NEGATIVE_THRESHOLD` | Distinct negative surfacing events before local demotion applies | `3` | | `MEMTOMEM_STM_SURFACING__LTM_MCP_TRANSPORT` | LTM MCP transport: `stdio`, `sse`, or `streamable_http` | `stdio` | | `MEMTOMEM_STM_SURFACING__LTM_MCP_COMMAND` | MCP command launching the LTM server for stdio transport | `memtomem-server` | | `MEMTOMEM_STM_SURFACING__LTM_MCP_ARGS` | Args for the LTM command (JSON list) | `[]` | | `MEMTOMEM_STM_SURFACING__LTM_MCP_URL` | LTM endpoint URL for `sse` / `streamable_http` | `""` | | `MEMTOMEM_STM_SURFACING__LTM_MCP_HEADERS` | Optional static headers for network LTM transport (JSON object) | `null` | Injection mode (`append` default, plus `prepend` / `section`) is set via `MEMTOMEM_STM_SURFACING__INJECTION_MODE`. ### Hook / Daemon [Section titled “Hook / Daemon”](#hook--daemon) | Variable | Description | Default | | ------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ----------- | | `MEMTOMEM_STM_HOOK__USE_DAEMON` | Route `mms hook` surfacing through a resident local daemon instead of a fresh in-process path each call | `true` | | `MEMTOMEM_STM_HOOK__DAEMON_TIMEOUT_SECONDS` | Hook-to-daemon round-trip timeout | `2.5` | | `MEMTOMEM_STM_HOOK__FALLBACK` | Behavior when daemon is unavailable: `skip` (skip surfacing) or `cold` (handle via the in-process path) | `skip` | | `MEMTOMEM_STM_HOOK__AUTO_SPAWN` | Start a daemon asynchronously on the first eligible hook call (does not wait for it) | `true` | | `MEMTOMEM_STM_HOOK__RECORD_FEEDBACK_EVENTS` | Persist hook surfacing feedback/query events; default keeps dedup without storing raw query text | `false` | | `MEMTOMEM_STM_HOOK__COMPRESSION__ENABLED` | Enable built-in Bash `updatedToolOutput` compression | `false` | | `MEMTOMEM_STM_HOOK__COMPRESSION__MAX_CHARS` | Target char budget for Bash output replacement | `16000` | | `MEMTOMEM_STM_DAEMON__HOST` | Local daemon bind address; keep it loopback-only | `127.0.0.1` | | `MEMTOMEM_STM_DAEMON__IDLE_TIMEOUT_SECONDS` | Stop the daemon after this many idle seconds; `0` disables idle shutdown | `900.0` | ### Langfuse (observability) [Section titled “Langfuse (observability)”](#langfuse-observability) | Variable | Description | Default | | -------------------------------------- | ------------------- | ------- | | `MEMTOMEM_STM_LANGFUSE__ENABLED` | Emit spans | `false` | | `MEMTOMEM_STM_LANGFUSE__PUBLIC_KEY` | Langfuse public key | — | | `MEMTOMEM_STM_LANGFUSE__SECRET_KEY` | Langfuse secret key | — | | `MEMTOMEM_STM_LANGFUSE__HOST` | Langfuse host URL | — | | `MEMTOMEM_STM_LANGFUSE__SAMPLING_RATE` | 0.0–1.0 | `1.0` | Setting `MEMTOMEM_STM_LANGFUSE__ENABLED=true` without the `[langfuse]` extra installed raises a `ValueError` at startup (fail-fast since v0.1.16). Install the extra first, or leave `enabled=false`. The old silent-disable-with-WARNING behavior is gone, so a typo no longer leaves tracing quietly off. ### Compression strategies (`MEMTOMEM_STM_PROXY__DEFAULT_COMPRESSION`) [Section titled “Compression strategies (MEMTOMEM\_STM\_PROXY\_\_DEFAULT\_COMPRESSION)”](#compression-strategies-memtomem_stm_proxy__default_compression) | Strategy | Use for | | ---------------- | ----------------------------------------------------- | | `auto` | Default — picks per content type | | `hybrid` | Markdown (structure + summarize non-essentials) | | `selective` | Keep only query-relevant sections | | `progressive` | Large content; cursor-based delivery (zero loss) | | `extract_fields` | JSON dictionaries | | `schema_pruning` | Large JSON arrays | | `skeleton` | API docs (schema-only) | | `llm_summary` | LLM-based summarization (OpenAI / Anthropic / Ollama) | | `truncate` | Fallback truncation | | `none` | Pass-through | > Full list: [configuration.md](https://github.com/memtomem/memtomem-stm/blob/main/docs/configuration.md) in the upstream repo. # CLI Reference > mms CLI commands for memtomem-stm proxy management. The `mms` command is installed with the `memtomem-stm` v0.1.38 package. It manages upstream-server registration, MCP-client registration, and proxy-config lifecycle. Run `mms --help` for the full command list or `mms --version` to print the installed version (the `mms version` subcommand also works). STM’s import is reversible. Pulling an upstream behind the STM proxy preserves its original registration, so if the result isn’t what you want, `mms eject` restores it to the original host MCP-client config. ## Commands [Section titled “Commands”](#commands) ### `mms init` [Section titled “mms init”](#mms-init) Run `mms init` with no flags — the wizard asks for one upstream server, optionally probes its connectivity, writes `~/.memtomem/stm_proxy.json`, and then offers a 3-way MCP-client registration prompt: 1. **Add to Claude Code** — runs `claude mcp add` for you. 2. **Generate `.mcp.json`** — writes a project-scoped config in the current directory. 3. **Skip** — prints paste hints so you can wire it up by hand later. Use the `--mcp` flag to pre-answer the prompt in scripted / CI runs: ```bash mms init --mcp claude # auto-register with Claude Code mms init --mcp json # write .mcp.json in the current directory mms init --mcp skip # write config, print paste hints, exit mms init --no-validate # skip the upstream connectivity probe mms init --lang ko # token-aware budget preset for CJK workloads mms init --prune-originals # also remove imported upstreams from source clients ``` `--lang ko` writes Korean / CJK token-equivalent defaults: `chars_per_token=1.85`, `default_max_result_chars=8500`, and a per-server `max_result_tokens=2000`. Non-TTY callers default to `en` when `--lang` is omitted. `mms init` aborts if the config file already exists — use `mms add` to append more upstream servers, or `mms register` to re-run the registration prompt without touching the config. ### `mms register` [Section titled “mms register”](#mms-register) Re-run the MCP-client registration flow after `mms init`. Useful if you picked `skip` the first time or want to re-register after reinstalling the client. ```bash mms register # interactive prompt mms register --mcp claude # shell out to `claude mcp add` mms register --mcp json # write .mcp.json in cwd mms register --mcp skip # print manual registration hints ``` Safe to re-run. If `memtomem-stm` is already registered with Claude Code, the command defaults to keeping the existing entry. ### `mms add ` [Section titled “mms add \”](#mms-add-name) Register an upstream MCP server to proxy through STM. ```bash mms add filesystem --command filesystem-server --prefix fs mms add github --command github-mcp --args "--token $GH_TOKEN" --prefix gh mms add remote-api --transport streamable_http --url https://example/mcp --prefix api mms add filesystem --command filesystem-server --prefix fs --validate ``` | Flag | Description | | ----------------- | ------------------------------------------------------------------------------------- | | `--command` | Executable command (stdio transport) | | `--args` | Space-separated arguments | | `--prefix` | Tool namespace (required unless `--from-clients`); tools appear as `{prefix}__{tool}` | | `--transport` | `stdio` (default), `sse`, or `streamable_http` | | `--url` | Endpoint URL for `sse` / `streamable_http` | | `--env KEY=VALUE` | Environment variable to forward to the upstream process (repeatable) | | `--compression` | `auto` (default), `none`, `truncate`, `selective`, `hybrid` | | `--max-chars` | Output-size budget (default `8000`) | | `--validate` | Probe the server (MCP initialize + list-tools) before saving | | `--timeout` | Probe timeout in seconds when `--validate` is set (default `10`) | #### Bulk import from MCP clients [Section titled “Bulk import from MCP clients”](#bulk-import-from-mcp-clients) `mms add --from-clients` (alias `--import`) discovers servers registered with Claude Desktop, Claude Code, and project `.mcp.json` files and imports them into the STM proxy config (`stm_proxy.json`) — reusing `mms init`’s discovery + TUI flow. Servers already registered in this proxy config are skipped. (This is a different command from [`mms import`](#mms-import), which copies host configs into `~/.mms/registry.toml`.) ```bash mms add --from-clients # interactive bulk import mms add --import # alias mms add --from-clients --prune # also remove the direct registration from each source client ``` After a successful import, the same server is advertised on two paths — direct from the source client and via STM’s proxied namespace — and the direct path bypasses compression, caching, and LTM surfacing. Each imported entry also records its provenance — the source-client kind plus a copy of the original registration — so [`mms eject`](#mms-eject-name) can restore it at any time. `--prune` (or an interactive confirm prompt shown in TTY, defaulting to **No**) closes the dual-registration by calling `claude mcp remove` for each Claude Code scope and atomically rewriting the Claude Desktop JSON. Each pruned entry is backed up to `~/.memtomem/pruned_upstreams.json` first, so the cleanup is undoable too. Non-TTY callers without `--prune` keep the hint-only behavior — the import still succeeds, and the warning prints the exact manual removal command. Incompatible with `NAME` / `--prefix` / `--command` / `--args` / `--url` / `--env`. `--prune` requires `--from-clients` / `--import`. ### `mms list` [Section titled “mms list”](#mms-list) List all registered upstream servers — the per-server view. ```bash mms list # human-readable mms list --json # scriptable JSON ``` The table includes an **ORIGIN** column reporting each upstream’s import source. The value is the source-client kind (`mcp-json`, `claude-user`, `claude-project`, `claude-desktop`); manually `mms add`-ed entries show `-`. A trailing `*` marks an entry whose host original was pruned, so it now exists only behind STM — `mms eject ` restores it. As of v0.1.32 the table also carries a **SURFACING** column — the visible home of the per-server `mms surfacing` toggle. ### `mms status` [Section titled “mms status”](#mms-status) Answer “is the proxy set up and pointed at the right config?” — a config summary, not the per-server view. ```bash mms status mms status --json # scriptable JSON ``` As of v0.1.32 `status` is a summary: config path, the `enabled` flag, any schema-validation warning, and `Servers: N (P host-pruned)`. Per-server detail (compression, output budget, surfacing state) moved to `mms list`. `status --json` keeps its full redacted `servers` map and adds `server_count` / `pruned_count`. ### `mms surfacing [on|off]` [Section titled “mms surfacing \ \[on|off\]”](#mms-surfacing-server-onoff) Toggle proactive memory surfacing for a single upstream server. Omit the state argument to print the current value. ```bash mms surfacing filesystem # show current state mms surfacing filesystem off # disable surfacing for this upstream mms surfacing filesystem on # re-enable ``` `surfacing_enabled` is written into the shared proxy config (`stm_proxy.json`). A running proxy hot-reloads it without a restart, and because the flag lives in the shared config rather than per-client env, every MCP client that proxies through this `mms` sees the same scope. See [Proactive Surfacing](/stm/surfacing/) for how surfacing works. ### `mms remove ` [Section titled “mms remove \”](#mms-remove-name) Remove a registered upstream server. ```bash mms remove filesystem # confirmation prompt mms remove filesystem -y # skip confirmation ``` Removing an imported server emits a hint pointing at `mms eject`, so the original host registration can be restored rather than lost. ### `mms health` [Section titled “mms health”](#mms-health) Probe every registered upstream server and report MCP connectivity status. Output is pretty-printed to match `status` / `list`. ```bash mms health # human-readable mms health --json # scriptable JSON mms health --timeout 5 # per-server connect timeout (seconds) mms health --names # also flag tools whose proxied name overflows the 64-char MCP limit ``` `--names` is the way to find an upstream tool that silently disappeared after registration because the composed `mcp______` name exceeded the MCP 64-char limit (#261). `health` also renders a per-upstream **circuit breaker** line. As of v0.1.32 the breaker is on by default: after 3 consecutive failed calls an upstream’s tools fast-fail with `circuit_open` for \~60s instead of each call burning the full retry/deadline budget; cached responses keep serving and other upstreams are unaffected. Set `circuit_max_failures: 0` on an upstream in `stm_proxy.json` to restore the old always-retry behavior. ### `mms prune` [Section titled “mms prune”](#mms-prune) After registering upstreams via `mms init` or `mms add --import`, this removes the direct entries left in source MCP clients (Claude Code, Claude Desktop, project `.mcp.json`) so tool calls route through the STM proxy on a single path — picking up compression, caching, and LTM surfacing. It’s an explicit opt-in command. ```bash mms prune --all # every dual-registered upstream mms prune filesystem github # specific names mms prune --all --dry-run # show what would be pruned, no writes mms prune --all -y # skip the confirm prompt (CI) ``` Each entry is backed up to `~/.memtomem/pruned_upstreams.json` before removal, so the operation is reversible — use [`mms eject`](#mms-eject-name) to restore the original client registration. STM’s own config (`~/.memtomem/stm_proxy.json`) is left alone. ### `mms eject ` [Section titled “mms eject \”](#mms-eject-name) The inverse of `prune`. It restores an imported upstream back to its original host MCP-client config and only removes the STM entry once the restore is verified. This lets you try the STM proxy and back out safely if it isn’t what you want. Multiple names can be ejected at once. ```bash mms eject filesystem # restore to host config, then remove the STM entry mms eject filesystem github # several at once mms eject filesystem --dry-run # preview what would be restored mms eject filesystem --keep # restore to host but keep the STM entry (dual registration) mms eject filesystem --yes # non-interactive — skip the confirm prompt ``` It writes the verbatim host entry captured at import time (the provenance) back where it came from, verifies the restore against the host config, and only then removes the STM entry. If any step fails, the server stays registered in at least one place — worst case is dual registration, never a disappeared server. | Flag | Description | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--to TARGET` | Restore target for entries without a recorded origin (`claude-user` / `claude-project[:PATH]` / `mcp-json[:PATH]` / `claude-desktop`). Entries with a recorded origin ignore this | | `--keep` | Restore to the host but keep the STM entry (dual registration) | | `--force` | Overwrite a same-name host entry whose identity differs | | `--allow-argv-secrets` | Permit `claude mcp add-json` shell-outs whose payload carries secret-classified values (argv is visible in the process list) | | `--accept-schema-loss` | Proceed with STM removal even when the restored host entry does not structurally match the original (default keeps the STM entry and fails) | | `--dry-run` | Print the plan; no writes | | `--yes` / `-y` | Skip the confirm prompt (scripts / CI / non-TTY) | ### `mms hook` [Section titled “mms hook”](#mms-hook) Bridge supported host built-in tool calls into STM surfacing. Claude Code and compatible hosts call it as a `PostToolUse` hook: the JSON payload arrives on stdin, and `mms hook` prints hook output that can include `additionalContext` with surfaced memories. Bash output compression is separate and opt-in via `MEMTOMEM_STM_HOOK__COMPRESSION__ENABLED=1`. ```json { "hooks": { "PostToolUse": [ { "matcher": "Read|Grep|Glob|WebFetch|Bash", "hooks": [{ "type": "command", "command": "mms hook" }] } ] } } ``` The hook always exits 0. If surfacing, the daemon, or compression fails, the host tool output passes through unchanged. ### `mms daemon` [Section titled “mms daemon”](#mms-daemon) Manage the local surfacing daemon used by `mms hook`. Daemon mode is on by default (`MEMTOMEM_STM_HOOK__USE_DAEMON=1`) and auto-spawns on the first eligible hook call, so manual startup is usually unnecessary. ```bash mms daemon status # show whether the warm daemon is running mms daemon start # start it explicitly mms daemon stop # stop the daemon for this config ``` The daemon holds one warm LTM MCP session for the active config. Set `MEMTOMEM_STM_HOOK__USE_DAEMON=0` to force the legacy cold in-process hook path, or `MEMTOMEM_STM_HOOK__FALLBACK=cold` if you prefer a cold fallback when the daemon is unavailable. ## Project Management (W1) [Section titled “Project Management (W1)”](#project-management-w1) `.mms/project.toml` markers let you scope which MCPs are active per directory — for example, GitHub MCP only when working in your work repo, filesystem only in side projects. Project markers are indexed at `~/.mms/projects.toml` so the active set is consistent regardless of where you invoke `mms` from. ### `mms project init [PATH]` [Section titled “mms project init \[PATH\]”](#mms-project-init-path) Create `/.mms/project.toml` and add it to the projects index. Defaults to cwd. ```bash mms project init # create .mms/project.toml in cwd mms project init ~/work/billing # create in another directory mms project init --name acme # override directory-basename name mms project init --force # overwrite an existing marker ``` ### `mms project show [NAME]` [Section titled “mms project show \[NAME\]”](#mms-project-show-name) Show the detected (or named) project’s enabled MCP list and marker path. ```bash mms project show mms project show acme mms project show --json ``` ### `mms project list` [Section titled “mms project list”](#mms-project-list) List indexed projects. The current cwd’s project is marked with `*`. ```bash mms project list mms project list --json mms project list --prune # drop entries whose path is gone ``` ### `mms project enable / disable ` [Section titled “mms project enable / disable \”](#mms-project-enable--disable-mcps) Add or remove MCP names from a project’s `mcp.enabled` list. Target is auto-detected from cwd; pass `--project ` to override. ```bash mms project enable filesystem github mms project disable github mms project enable filesystem --project acme ``` `enable` only accepts MCPs that are already in the registry — it errors clearly when the registry is empty. `disable` works regardless of registry state. ## Importing host configs (W1) [Section titled “Importing host configs (W1)”](#importing-host-configs-w1) ### `mms import` [Section titled “mms import”](#mms-import) Discover MCP definitions in host MCP clients (Claude Code, Claude Desktop, Cursor, …) and copy them into `~/.mms/registry.toml`. This populates the registry used by project management (W1) — a different target file and purpose from [`mms add --from-clients`](#bulk-import-from-mcp-clients), which imports upstreams into the proxy config. **`--plan` is the default** — pass `--apply` to actually write. ```bash mms import --plan # default: show what would be imported (secrets redacted) mms import --apply # write to the registry mms import --from claude-code --plan # restrict source (claude-code / cursor / codex / claude-desktop / all) mms import --plan --show-imported # reveal secret values in the plan output (use carefully) ``` First import wins: identical names with different definitions are flagged as conflicts and skipped; identical definitions are left unchanged. ## Operational statistics [Section titled “Operational statistics”](#operational-statistics) To inspect proxy, surfacing, selection, and compression behavior at runtime, STM ships eight observability MCP tools (`stm_proxy_stats`, `stm_proxy_cache_clear`, `stm_proxy_health`, `stm_surfacing_stats`, `stm_selection_stats`, `stm_compression_stats`, `stm_progressive_stats`, `stm_tuning_recommendations`). They are hidden from `tools/list` by default; set `MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS=true` to expose them. See [MCP Tools](/stm/mcp-tools/). ## Running the proxy server [Section titled “Running the proxy server”](#running-the-proxy-server) The proxy server itself ships as the `memtomem-stm` console script. You don’t launch it by hand — your MCP client spawns it automatically once `memtomem-stm` is registered (via `mms init --mcp claude`, `mms register`, or a `.mcp.json` entry). ## Example Workflow [Section titled “Example Workflow”](#example-workflow) ```bash # 1. First-time setup — registers one upstream + your MCP client in one go mms init --mcp claude # 2. Add more upstreams (manually, or bulk-import from existing client configs) mms add filesystem --command filesystem-server --prefix fs --validate mms add --from-clients # 3. Verify connectivity mms status mms health # 4. (Optional) turn off surfacing for one upstream mms surfacing filesystem off # 5. (Optional) back out — restore an upstream to its original host config mms eject filesystem # 6. (Optional) re-register with Claude Code after reinstalling the client mms register --mcp claude ``` Your MCP client now connects to `memtomem-stm` instead of each individual upstream. All upstream tools are available through the proxy, with automatic memory surfacing, response compression, and progressive delivery. > See [Installation](/guides/installation/) for setup details, and [Proactive Surfacing](/stm/surfacing/) for how surfacing works. # Compression Strategies > 10 compression strategies, auto-selection logic, and query-aware budget allocation. > New here? Start with the [STM Overview](/stm/overview/) to see the full pipeline in context first. Every MCP tool response passes through STM before it reaches your agent. When a response exceeds the agent’s context budget, STM compresses it — and the compression method depends on the content type. memtomem-stm automatically compresses MCP tool responses by content type to save tokens. It ships 10 strategies in total — 8 content-type reducers plus the `auto` selector and the `none` passthrough — reducing response size while preserving the information the agent needs. If you’re not sure which to pick, leave the setting on `auto` — it chooses the right reducer per response from the immediate-response strategies. ## Compression Strategies [Section titled “Compression Strategies”](#compression-strategies) | Strategy | Target content | Behavior | | ------------------- | --------------------- | ------------------------------------------------------------------------------- | | **truncate** | Small text | Length-limited truncation (default fallback) | | **hybrid** | Markdown | Preserve structure + abbreviate non-essential sections | | **selective** | Large structured data | Two-phase TOC first, then retrieve selected sections on demand | | **progressive** | Large content | Cursor-based sequential delivery (zero information loss) | | **extract\_fields** | JSON dictionaries | Preserve top-level shape with representative nested values | | **schema\_pruning** | JSON arrays | Recursive schema-preserving sampling | | **skeleton** | API docs | Preserve headings and first content lines | | **llm\_summary** | Complex text | LLM-based summarization (OpenAI/Anthropic/Ollama) — timeout-bound (default 60s) | | **auto** | All types | Analyze content and auto-select optimal strategy | | **none** | — | Pass through original without compression | ## Auto-Selection Logic [Section titled “Auto-Selection Logic”](#auto-selection-logic) The `auto` strategy (default) analyzes content to pick the optimal strategy: | Content type | Selected strategy | | ------------------------------------------------- | ----------------- | | Already within budget | `none` | | Large JSON array, or dict containing large arrays | `schema_pruning` | | Nested JSON dictionary | `extract_fields` | | API docs with HTTP endpoints | `skeleton` | | Large structured Markdown / code-heavy text | `hybrid` | | Other text or simple JSON | `truncate` | `selective`, `progressive`, and `llm_summary` are opt-in only. `auto` never chooses them because they change the interaction pattern or add external latency. ## Query-Aware Budget Allocation [Section titled “Query-Aware Budget Allocation”](#query-aware-budget-allocation) During compression, the agent’s current query is taken into account — relevant sections receive a larger token budget. The `selective` / `hybrid` / `schema_pruning` / `skeleton` strategies also rank table-of-contents entries by BM25 relevance to the active query. The deterministic BM25 score used here is recorded by selection telemetry for offline analysis (see [Configuration](/reference/configuration/)). ## JSON Safety [Section titled “JSON Safety”](#json-safety) JSON-aware tiers re-serialize strict JSON after compression. Non-finite values such as `NaN`, `Infinity`, and `-Infinity` are mapped to `null` before JSON output so downstream parsers do not receive Python extension tokens. The JSON tiers degrade monotonically as budgets shrink. The documented exception is standalone `selective`: it shrinks per-entry previews first, but a zero-preview TOC envelope can still exceed budget at very high section counts because dropping entries would break the selection contract. ## Zero Information Loss: Progressive Delivery [Section titled “Zero Information Loss: Progressive Delivery”](#zero-information-loss-progressive-delivery) The `progressive` strategy delivers large content without any information loss: 1. First response delivers a table of contents (TOC) and the first chunk 2. Agent calls `stm_proxy_read_more(key, offset)` → cursor-based delivery of subsequent chunks 3. Full content can be inspected sequentially Every progressive chunk ends with the canonical footer `\n---\n[progressive: chars=]` — agents must split on the full `PROGRESSIVE_FOOTER_TOKEN` string (exported from `memtomem_stm.proxy.progressive`). Splitting on `\n---\n` alone silently drops bytes when content contains Markdown horizontal rules or YAML fences. Per-response follow-up rate and coverage for progressive delivery — along with degradation to passthrough when the primary store fails — are reported by the `stm_progressive_stats` tool (see [MCP Tools](/stm/mcp-tools/)). ## Fallback Ladder [Section titled “Fallback Ladder”](#fallback-ladder) The retention floor (`MEMTOMEM_STM_PROXY__MIN_RESULT_RETENTION`, default `0.65`) guards against over-compression. When an output drops below the floor, a 3-tier fallback activates automatically: ```plaintext progressive → hybrid → truncate ``` Each tier checks the floor — if satisfied, that strategy’s output is used. The char budget is raised to `len(response) * min_result_retention` before truncation when per-tool `max_result_chars` would otherwise drop more than the floor allows. The `llm_summary` strategy has its own **timeout guard**: the `llm_timeout_seconds` field (default `60`s) on the per-server / per-tool `llm` block. A slow or stuck LLM endpoint no longer blocks the proxy — on timeout, STM falls back to `truncate` so the agent still receives a bounded response. ## Compression Budget Tuning [Section titled “Compression Budget Tuning”](#compression-budget-tuning) Agent feedback automatically adjusts per-tool compression budgets: * Agent reports **information loss** → Increase preservation ratio for that tool * Agent reports **response too long** → Decrease preservation ratio This feedback loop is driven by the `stm_compression_feedback` tool; accumulated feedback and per-tool adjustments are visible via `stm_compression_stats` (see [MCP Tools](/stm/mcp-tools/)). # MCP Tools > STM proxy exposes 12 control tools for stats, cache, surfacing, compression, progressive delivery, and selection telemetry, plus an opt-in formation tool. When you want to see how much the proxy is saving, clear a stale cache, or tune what gets surfaced, memtomem-stm exposes **control tools** over MCP. Alongside proxying upstream MCP tools, it provides **12** base tools plus the opt-in `stm_memory_propose` formation tool. ## Advertising observability tools [Section titled “Advertising observability tools”](#advertising-observability-tools) Of the 12 base tools, 4 are **model-facing** and advertised by default; the remaining 8 are **observability / admin** tools hidden from the MCP list by default. Set `MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS=true` to advertise them. Set `MEMTOMEM_STM_FORMATION__ENABLED=true` separately to advertise `stm_memory_propose`. That flag alone controls advertisement; whether the upstream LTM supports review-first proposals is checked at call time — an incompatible core returns `{"ok": false, "reason": "formation_unsupported"}`. | Category | Advertised by default | Advertised when its flag is on | | ----------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Model-facing (4)** | `stm_proxy_select_chunks`, `stm_proxy_read_more`, `stm_surfacing_feedback`, `stm_compression_feedback` | — | | **Observability / admin (8)** | — | `stm_proxy_stats`, `stm_proxy_health`, `stm_proxy_cache_clear`, `stm_surfacing_stats`, `stm_selection_stats`, `stm_compression_stats`, `stm_progressive_stats`, `stm_tuning_recommendations` (`MEMTOMEM_STM_ADVERTISE_OBSERVABILITY_TOOLS`) | | **Formation (opt-in)** | — | `stm_memory_propose` (`MEMTOMEM_STM_FORMATION__ENABLED`) | ## Proxy stats & control [Section titled “Proxy stats & control”](#proxy-stats--control) ### `stm_proxy_stats` [Section titled “stm\_proxy\_stats”](#stm_proxy_stats) Token savings, cache hits, per-tool call history. No parameters. *(Observability — advertised only when `advertise_observability_tools=true`.)* ### `stm_proxy_health` [Section titled “stm\_proxy\_health”](#stm_proxy_health) Upstream connectivity and proxy health. For each upstream it reports both how many tools were **discovered** and how many were actually **advertised**, so when the eligibility filter withholds some tools the gap is visible at a glance. It also shows the surfacing circuit-breaker state and, if the external tool-graph eligibility provider is enabled, its status. No parameters. *(Observability.)* ### `stm_proxy_cache_clear` [Section titled “stm\_proxy\_cache\_clear”](#stm_proxy_cache_clear) Clear the response cache. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------- | | `server` | string | No | Scope to one upstream server | | `tool` | string | No | Scope to one tool | *(Observability.)* ### `stm_proxy_select_chunks` [Section titled “stm\_proxy\_select\_chunks”](#stm_proxy_select_chunks) Pick specific sections from a `selective` / `hybrid` TOC returned by an earlier call. | Parameter | Type | Required | Description | | ---------- | --------- | -------- | ---------------------------------- | | `key` | string | Yes | TOC key from the previous response | | `sections` | string\[] | Yes | Section ids to expand | ### `stm_proxy_read_more` [Section titled “stm\_proxy\_read\_more”](#stm_proxy_read_more) Read the next chunk of a `progressive` response. | Parameter | Type | Required | Description | | --------- | ------- | -------- | --------------------------------------------- | | `key` | string | Yes | Progressive response key | | `offset` | integer | No | Character offset to resume from (default `0`) | | `limit` | integer | No | Chars to return this turn | > Agents should split on the canonical `PROGRESSIVE_FOOTER_TOKEN` (`\n---\n[progressive: chars=`) rather than `\n---\n` alone — the latter collides with Markdown HR / YAML fences. ## Surfacing feedback [Section titled “Surfacing feedback”](#surfacing-feedback) ### `stm_surfacing_feedback` [Section titled “stm\_surfacing\_feedback”](#stm_surfacing_feedback) Rate surfaced memories so the auto-tuner can adjust thresholds. Each surfaced memory carries its own `memory_id`, so you can rate them one at a time; a memory marked `not_relevant` or `already_known` is invalidated — only that memory — on the next surfacing call. | Parameter | Type | Required | Description | | -------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------ | | `surfacing_id` | string | Yes | Id from the surfacing footer | | `rating` | string | No | `helpful` / `partially_helpful` / `not_relevant` / `already_known` (single-rating path) | | `memory_id` | string | No | Specific memory the single-rating feedback refers to | | `ratings` | object\[] | No | Batched per-memory feedback, each with `memory_id` and `rating` (mutually exclusive with the single-rating fields) | ### `stm_surfacing_stats` [Section titled “stm\_surfacing\_stats”](#stm_surfacing_stats) Aggregated surfacing metrics and feedback distribution. Reports `events_total`, `distinct_tools`, `total_feedback`, per-tool breakdown, rating distribution, helpfulness %, and a configurable recent tail. | Parameter | Type | Required | Description | | --------- | ------- | -------- | --------------------------------------------------------------------------------------------- | | `tool` | string | No | Filter by upstream tool name | | `since` | string | No | ISO-8601 timestamp (e.g. `2026-04-20T00:00:00`) — restricts to events at or after this moment | | `limit` | integer | No | Tail size for the `Recent` section (default `10`; `0` hides it) | *(Observability.)* ## Selection stats [Section titled “Selection stats”](#selection-stats) ### `stm_selection_stats` [Section titled “stm\_selection\_stats”](#stm_selection_stats) Summarizes tool-selection and execution telemetry. Set `proxy.selection_telemetry.enabled = true` and the proxy records a JSONL log; this tool reads it back into event counts, selections by ranker version, selections by server and tool, execution ok/error with latency percentiles, and the eligibility hard-filter reject-reason tally. It also shows this process’s write-path counters (events written / sampled out / redaction drops / write errors). Only the active log is aggregated; rotated backups are noted but not parsed. No parameters. *(Observability — advertised only when `advertise_observability_tools=true`.)* ## Compression feedback [Section titled “Compression feedback”](#compression-feedback) ### `stm_compression_feedback` [Section titled “stm\_compression\_feedback”](#stm_compression_feedback) Report missing information that compression dropped. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------ | | `server` | string | Yes | Upstream server | | `tool` | string | Yes | Tool name | | `missing` | string | Yes | What the agent needed but didn’t get | | `kind` | string | No | Category hint | | `trace_id` | string | No | Langfuse trace id if available | ### `stm_compression_stats` [Section titled “stm\_compression\_stats”](#stm_compression_stats) Compression feedback counts per tool. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------- | | `tool` | string | No | Filter by tool name | *(Observability.)* ## Progressive delivery stats [Section titled “Progressive delivery stats”](#progressive-delivery-stats) ### `stm_progressive_stats` [Section titled “stm\_progressive\_stats”](#stm_progressive_stats) Per-response follow-up rate and coverage across all progressive-compressed calls. Each initial chunk and each follow-up `stm_proxy_read_more` appears as a row in `progressive_reads`; aggregates collapse per cache key, so a response with five follow-ups is weighted the same as one with none. Reports total reads, total responses, follow-up rate, avg chars served, avg total chars, avg coverage, and a per-tool breakdown. It also reports how often the primary `PROGRESSIVE` store path failed and degraded to an uncached full-content passthrough, so a failing backing store does not go silent. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------- | | `tool` | string | No | Filter by upstream tool name | *(Observability — advertised only when `advertise_observability_tools=true`.)* ### `stm_tuning_recommendations` [Section titled “stm\_tuning\_recommendations”](#stm_tuning_recommendations) Per-tool auto-tuner recommendations derived from recent feedback. | Parameter | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------- | | `since_hours` | number | No | Time window (default `24.0`) | | `tool` | string | No | Filter by tool name | *(Observability.)* ## Proxied upstream tools [Section titled “Proxied upstream tools”](#proxied-upstream-tools) Tools from a registered upstream MCP server are proxied through STM using the pattern `{prefix}__{tool}`. For example: ```bash mms add filesystem --command npx \ --args "-y @modelcontextprotocol/server-filesystem ~/projects" \ --prefix fs # filesystem's read_file becomes fs__read_file ``` STM does not advertise every upstream tool 1:1 — it applies an eligibility filter at exposure time. Tools from a disconnected server, tools whose metadata contains credential-looking strings, and tools with colliding names are not advertised to the agent; the discovered-vs-advertised counts in `stm_proxy_health` make the difference visible. Proxied tool **titles** — the `annotations.title` field rendered by MCP tool-picker UIs (e.g. Claude Code’s `/mcp`) — are automatically prefixed with `[{server}]` for attribution: a `filesystem` server’s `Read file` tool appears as `[filesystem] Read file`. This is separate from the `{prefix}__{tool}` name used when calling the tool, and applies only when the upstream tool provides an `annotations.title`. When the agent calls `fs__read_file`, the proxy runs the active pipeline: **CLEAN → COMPRESS → SURFACE**, with **INDEX** available only when an index engine is wired. It returns the compressed response plus any surfaced memories. > See [Proactive Surfacing](/stm/surfacing/) and [Compression Strategies](/stm/compression/) for mechanism details. # Overview > What memtomem-stm is — an MCP proxy that adds proactive surfacing and compression for AI agents. ## What is memtomem-stm? [Section titled “What is memtomem-stm?”](#what-is-memtomem-stm) memtomem-stm is a **short-term memory (STM) proxy** that sits between your AI agent and your existing MCP servers. Without any agent-side code changes, it adds **response compression**, **proactive memory injection**, and **exposed-tool curation** to every tool call — typically cutting token use by 20–80%. ## Use It When [Section titled “Use It When”](#use-it-when) * **MCP tool responses keep blowing your context window** — filesystem or GitHub MCP servers often return 8,000-token payloads. STM compresses them to \~2,000 with a strategy picked for the content type. * **You want memories auto-injected without the agent having to ask** — with LTM alone, the agent has to call `mem_search`. With STM in front, relevant memories ride along with every tool response, no explicit query needed. * **You want to curate the tool list your agent sees** — STM drops unresponsive servers, credential-leaking descriptions, and duplicate-named tools from the advertised list at exposure time. * **You want to try the proxy without committing** — STM imports your existing MCP servers and proxies them in front, and the move is reversible. `mms eject` restores an imported server to its original host config, returning you to the pre-STM state. ## Start in 3 Steps [Section titled “Start in 3 Steps”](#start-in-3-steps) ```bash uv tool install memtomem-stm # 1. install mms init --mcp claude # 2. register upstream + Claude Code (one step) mms health # 3. verify connectivity ``` `mms init` prompts for an upstream server and then registers `memtomem-stm` with your MCP client of choice (`--mcp claude`, `--mcp json`, or `--mcp skip`). Full setup walkthrough in [Quick Start](/guides/quickstart/). ## Core Capabilities [Section titled “Core Capabilities”](#core-capabilities) * **Proactive Surfacing** — Every tool call runs candidate memories through 5 relevance checks (context extraction → query suitability → LTM search → score threshold → dedup window) before anything is injected. Surfacing toggles per upstream (`mms surfacing on|off`), so you can exclude a single server’s responses from surfacing. See [Proactive Surfacing](/stm/surfacing/). * **Response Compression** — 10 strategies, auto-selected by content type (JSON, Markdown, API docs, free text, …), with query-aware ranking and safer JSON output tiers. See [Compression Strategies](/stm/compression/). * **Exposed-Tool Curation** — STM does not just relay every upstream tool as-is; it curates the advertised tool list at exposure time. Tools from unresponsive servers, descriptions that leak credentials, and duplicate or overflowing names are withheld from the agent. Tune the policy with `exposure.profile` (`strict` default / `review` / `explore`); `stm_proxy_health` reports “N discovered / M advertised”. * **Reversible Import** — Imported upstreams record their origin, so `mms list` distinguishes directly-registered servers from imported ones in an ORIGIN column (`*` marks a pruned host original). `mms eject` verifies the restore before it removes the STM entry. ## How It Works [Section titled “How It Works”](#how-it-works) ```plaintext AI Agent ↕ MCP protocol memtomem-stm (STM Proxy) ├── ↕ Surfacing queries → memtomem (LTM) └── ↕ Proxied calls → Upstream MCP Servers (filesystem, GitHub, …) ``` STM runs every MCP tool call through this pipeline: 1. **CLEAN** — normalize the request (strip noise, unify format) 2. **COMPRESS** — shrink the response (auto-select from 10 strategies) 3. **SURFACE** — pull relevant memories from LTM and inject them (5-level gating) STM does not write memories back to LTM at runtime. Surfacing only reads from LTM, and the INDEX (auto-accumulation) stage is inert by design in the standalone `mms` server. ## Relationship to LTM [Section titled “Relationship to LTM”](#relationship-to-ltm) STM and LTM are **independent packages** — no Python dependency between them. They communicate only via MCP protocol, and each can be deployed and upgraded separately. | | LTM (memtomem) | STM (memtomem-stm) | | ----------------- | --------------------------- | ----------------------------- | | **Role** | Persistent storage & search | Real-time proxy & compression | | **Required?** | Yes (core) | Optional | | **Communication** | Direct MCP server | MCP proxy → queries LTM | ## Package Info [Section titled “Package Info”](#package-info) | | | | ------------------ | ----------------------------------------------------------------- | | **PyPI** | [`memtomem-stm`](https://pypi.org/project/memtomem-stm/) | | **Latest release** | `0.1.38` | | **CLI** | `mms` | | **License** | Apache 2.0 | | **GitHub** | [memtomem/memtomem-stm](https://github.com/memtomem/memtomem-stm) | ## Next Steps [Section titled “Next Steps”](#next-steps) * [Quick Start](/guides/quickstart/) — from install to agent connection * [Proactive Surfacing](/stm/surfacing/) — 5-level gating and feedback auto-tuning * [Compression Strategies](/stm/compression/) — 10 strategies and auto-selection logic * [MCP Tools](/stm/mcp-tools/) — STM management and observability tools * [CLI Reference](/stm/cli/) — `mms` command reference # Proactive Surfacing > Real-time surfacing per tool call, relevance gating, feedback-based auto-tuning. Traditional RAG only provides relevant information when the agent explicitly requests a search. memtomem-stm’s proactive surfacing observes proxied MCP calls, infers the current working context, and **automatically** injects matching memories from LTM into the response — no explicit query needed. `mms hook` extends this surfacing path to supported Claude Code native-tool `PostToolUse` events as `additionalContext`. ## How It Works [Section titled “How It Works”](#how-it-works) When an agent calls an MCP tool, the STM proxy runs this pipeline: ```plaintext Tool call → Context extraction → LTM search → Relevance gating → Inject into response ``` No agent code changes needed — routing through the STM proxy enables automatic memory injection for MCP communication. For Claude Code built-in tools, install `mms hook` as a host hook; it uses a warm local daemon by default so repeated hook calls do not pay LTM cold-start cost. ## 5-Level Context Extraction [Section titled “5-Level Context Extraction”](#5-level-context-extraction) STM needs a search query before it can ask LTM for memories. Instead of relying on a single signal, it runs a five-pass pipeline — each pass tries a different source, and the first one that produces a usable query wins. That way a tool call with a clean `_context_query` argument is used directly, while a bare call like `fs__read_file(path=...)` still yields a usable search query. | Priority | Method | Description | | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | 1 | Tool-specific query template | Pre-defined query patterns mapped to tool names | | 2 | `_context_query` argument | Explicit search query passed by the agent | | 3 | Path arguments | Dedicated tokenization for `path` / `file` / `filepath` / `file_path` / `filename` keys (split on separators, drop extensions) | | 4 | Semantic keys | Keyword combination from `query` / `search` / `url` / `description` and similar argument values | | 5 | Tool name | Last resort — use the tool name itself as the query | ## Relevance Gating [Section titled “Relevance Gating”](#relevance-gating) Once a query is extracted, surfaced memories are filtered further to ensure usefulness (context extraction already happened in the [step above](#5-level-context-extraction)): 1. **LTM search** — Hybrid search for candidate memories 2. **Score filtering** — Remove results below the `min_score` threshold 3. **Deduplication** — In-session + cross-session (7-day) duplicate prevention ## Injection Modes [Section titled “Injection Modes”](#injection-modes) How surfaced memories are stitched into the response is controlled by `MEMTOMEM_STM_SURFACING__INJECTION_MODE`. Progressive delivery splits a large response into chunks, with follow-up `stm_proxy_read_more` calls relying on continuing offsets: | Mode | Behavior | | ------------------ | --------------------------------------------------------------------------------------------------------------------- | | `append` (default) | Memories appended below the response. Preserves progressive-delivery offsets and works on the continuing read path. | | `prepend` | Memories prepended as a header. Skipped on progressive delivery because it would shift `stm_proxy_read_more` offsets. | | `section` | Memories placed in a dedicated section. Triggers surfacing on progressive continuations. | ## Model-Aware Defaults [Section titled “Model-Aware Defaults”](#model-aware-defaults) Automatically scales based on the agent’s context window size: | Context window | Compression | Injection size | Result count | | -------------- | ---------------- | -------------- | ------------ | | ≤ 32K | High compression | Small | Few | | 32K – 200K | Default | Medium | Default | | > 200K | Low compression | Large | Many | ## Feedback Loop [Section titled “Feedback Loop”](#feedback-loop) Each memory in the surfaced block shows a relevance bucket — `[weak]` / `[related]` / `[strong]` — instead of a raw score, computed across the range between the active `min_score` threshold and 1.0. Each memory also exposes its own `memory_id` (a backticked token), so the agent can rate a whole event or rate individual memories one at a time: * Whole event: `stm_surfacing_feedback(surfacing_id=..., rating="helpful")` * Specific memories: `stm_surfacing_feedback(surfacing_id=..., ratings=[{"memory_id": ..., "rating": "not_relevant"}])` When an agent evaluates surfacing quality, the auto-tuner continuously optimizes per-tool relevance thresholds: * **helpful** → Maintain or lower `min_score` for that tool * **partially\_helpful** → Count as neutral evidence * **not\_relevant** → Raise `min_score` (stricter filtering) * **already\_known** → Count as negative feedback and feed local demotion / dedup behavior Rating an individual memory `not_relevant` or `already_known` invalidates exactly that memory on the next cache hit, excluding only those memories from injection rather than the whole event. ## Scoping Surfacing per Upstream [Section titled “Scoping Surfacing per Upstream”](#scoping-surfacing-per-upstream) Surfacing applies to every upstream by default, but you can durably turn it off (or back on) for a single upstream. This is useful for a third-party server whose calls never match LTM memories (pure wasted latency), or a sensitive upstream whose request context should never become an LTM query: ```bash mms surfacing # show current state mms surfacing off # disable surfacing for this upstream mms surfacing on # re-enable ``` The setting is written as a per-upstream `surfacing_enabled` flag (default `true`) in the shared proxy config (`stm_proxy.json`), so every MCP client that proxies through this `mms` sees the same scope. A running proxy hot-reloads it without a restart, and `mms list` shows the effective state in its SURFACING column. A disabled upstream’s calls are skipped before the LTM search and counted as a healthy skip (`upstream_disabled`) in `stm_surfacing_stats`. For tool-grained or cross-server glob scope, set `MEMTOMEM_STM_SURFACING__EXCLUDE_TOOLS` (matches the `server__tool` pattern). ## Safety Mechanisms [Section titled “Safety Mechanisms”](#safety-mechanisms) Surfacing runs under the following safeguards for resilience and privacy: * **Circuit breaker** (3-state: closed / open / half-open) — Opens after `circuit_max_failures` consecutive failures (default `3`) and transitions to half-open after `circuit_reset_seconds` (default `60s`) * **Surfacing timeout** — `3s` hard ceiling per call * **Rate limit** — `15 calls / minute` ceiling across all tools * **Write-tool skip** — Disables surfacing for tools with side effects (file writes, deletes) * **Query cooldown** — Skips surfacing when the extracted query has Jaccard similarity `> 0.95` with one seen in the last 5 seconds * **Cross-session dedup** — Default TTL `604800s` (7 days) via `MEMTOMEM_STM_SURFACING__DEDUP_TTL_SECONDS` * **Injection size cap** — Default `3000 chars` per injection * **Local feedback demotion** — Memories repeatedly rated `not_relevant` or `already_known` are filtered before injection once they cross `feedback_demotion_negative_threshold` (default `3` distinct events) * **Query-text privacy** — `query_retention_days` clears persisted raw query text after 30 days by default, and `persist_query_text=false` stores a `sha256:` digest instead of the raw query ## LTM Transport [Section titled “LTM Transport”](#ltm-transport) STM talks to LTM over MCP. The default transport spawns `memtomem-server` over stdio, and it can also connect to long-running LTM services over `sse` or `streamable_http`: ```bash export MEMTOMEM_STM_SURFACING__LTM_MCP_TRANSPORT=streamable_http export MEMTOMEM_STM_SURFACING__LTM_MCP_URL=https://ltm.example/mcp export MEMTOMEM_STM_SURFACING__LTM_MCP_HEADERS='{"Authorization":"Bearer ..."}' ``` LTM responses are consumed by the surfacing engine and bypass the proxy compression/cache pipeline. A `trace_id` is threaded through the surfacing and progressive-delivery path so follow-up reads correlate with the initial chunk in Langfuse (or any OpenTelemetry-style tracer).