M3 Memory
m3 Memory is a local-first, MCP-native persistent memory server that stores, retrieves, and self-maintains knowledge shared across agents and tools.
Persist memories —
memory_writestores typed items (decisions, beliefs, facts, procedures) with metadata, provenance, scope, importance, and bitemporal validity.Resolve contradictions — automatic supersession on write (cosine/title heuristic) plus deterministic
memory_supersedethat closes the old fact's validity interval while keeping it retrievable.Hybrid search —
memory_search/memory_getcombine BM25 keyword, local BGE-M3 vector similarity, and MMR diversity, with optional score explanations, time-travel (as_of), and filters.Capture conversations —
chatlog_write,chatlog_search, andchatlog_statuslog chat turns verbatim before compaction so prior sessions stay searchable.Ingest and query files —
files_index,files_search,files_get,files_stats,files_health, andfiles_corpus_listprovide corpus-level file retrieval with history/time-travel.Coordinate multiple agents —
agent_listandtask_listsupport multi-agent orchestration with scoped memory, inbox handoffs, and recursive task trees.Discover and invoke tools —
tools_list_domains,tools_load_domain,m3_index,m3_help_capabilities, andm3_callexpose the full 100+ tool catalog lazily, including batch calls, dry-run validation, and a destructive-action gate.Run sovereign — no account or API key required; local embedder, SQLite by default (PostgreSQL optional), air-gapped install, and identical memory via CLI or MCP.
Optionally uses Ollama to load a small chat model for auto-classification, summarization, and consolidation of memories.
Enables syncing memory data across devices using PostgreSQL, allowing seamless continuation between different machines.
Uses local SQLite databases as the primary storage for memories, chat logs, files, and knowledge graph, ensuring sovereign data storage.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@M3 Memorysave this conversation about project requirements"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
🧠 m3 Memory
Give your AI a memory that lasts.
Your AI assistant is helpful until you start a new conversation and it has forgotten what you were working on. m3 fixes that.
Your assistants remember your projects, preferences, decisions and past work, even after you close the app, start a new session or switch to a different agent. By default everything stays on your own computer, and it works offline. m3 itself needs no cloud account or API key; your AI assistant may have its own requirements.
pipx install m3-memory # or pip install m3-memory in a virtual environment; use one, not both
m3 setup # finds your agents and connects them to m3
m3 doctor # checks that everything is workingNo pipx yet? sudo apt install pipx (Debian, Ubuntu), brew install pipx (macOS) or
py -m pip install --user pipx (Windows). If m3 is not found right after installing,
open a new terminal.
Setup finds your agents and connects m3 to them. m3 setup detects your AI agents and wires m3 into each; if you run a local LLM (Ollama, LM Studio), it offers to use it to summarize and link your memories. That part is optional; to use it, install the LLM before m3 setup: Windows · macOS · Linux. That's the whole install.
New here? The 5-minute Getting Started guide walks you through your first saved memory.
What m3 is
m3 is a memory layer for AI agents: the AI assistants that work for you, such as Claude Code, Codex, Cursor or Gemini CLI. It runs on your own computer and stores facts, decisions, preferences and conversation history so your assistants can recall them later, across sessions, across tools and across machines. Assistants reach it through MCP, the standard way AI assistants connect to tools, and you can use it from the command line too.
It is not an AI model or a chatbot. You keep using the assistants you already use; they call m3 when they need to remember or recall something.
Related MCP server: Cortex
📅 A week with m3
Monday: you tell your AI assistant you're building a website and decide on PostgreSQL.
Wednesday: you open a new session and ask, "Where did we leave off?" Your assistant finds the decision and carries on, without you repeating it.
Friday: you switch agents, say from Claude Code to Codex. Codex sees the same project memory.
See it for yourself in a short video of one agent saving a decision that another recalls. (Developers: the same thing from the command line.)
✨ What m3 does for you
You want to... | m3... | Under the hood |
Stop repeating yourself | remembers what you told it in earlier sessions | persistent memory over MCP and a CLI |
Pick up where you left off | keeps your conversations and finds them again | |
Use more than one AI assistant | shares one memory across Claude Code, Cursor, Gemini CLI and others | one local store, many clients |
Find things in your own words | finds a memory even when you don't recall the exact words | hybrid search: keywords plus meaning |
Use fewer AI tokens | puts the most relevant memory first, and loads only six of its tools when your assistant connects | the right session first for 91.8% of questions; about 3,200 tokens of tool descriptions instead of 33,000 |
Keep track when things change | keeps the earlier version when a decision changes: similarity-based supersession on write, explicit corrections, and optional model-assisted contradiction review | |
Keep your information private | stores everything on your computer and works offline | |
Let assistants work together | lets several assistants share notes, hand off work and split tasks | |
Keep memory tidy | can tidy up in the background: links related facts, merges duplicates, fades stale notes | the built-in cognitive loop (enable it in |
Simple to understand, easy to start, powerful when you need it. Every row links to the doc that backs it; How memory works in m3 explains the mechanics, and the technical summary and benchmarks carry the measurements.
🎯 Better memory, fewer wasted tokens
AI assistants can only work with so much text at once, and they measure it in tokens: small pieces of words, which can also set what you pay. When your assistant searches its memory, finding the right thing first means it reads less of what it doesn't need.
An illustration, not a measurement:
less precise search m3: the right memory first
1. unrelated note 1. ✔ the decision you need
2. unrelated note (it may already have what it needs)
3. ✔ the decision you need
4. unrelated note
5. unrelated noteOn the LongMemEval-S benchmark, the correct session was m3's first result for 91.8% of questions (459 of 500). That measures retrieval accuracy, not token savings: how much your assistant saves depends on how it uses the results. m3 returns as many as it is asked for, so precise ranking lets an assistant ask for fewer, or stop at the first good one, and keep more room for the work itself.
m3 saves context in a second, measured way: it registers only 6 of its 100+ tools when an assistant connects, so their descriptions take about 3,200 tokens instead of about 33,000 for the full catalog (Interfaces).
How memory works in m3
When an agent (or you, from the shell) wants to remember something, it calls
memory_write. m3 stores the text exactly as given, with a type, title and metadata.
Later, memory_search finds it with hybrid retrieval: keyword matching (BM25),
semantic similarity (local BGE-M3 embeddings) and diversity re-ranking (MMR). Nine
signals contribute to the score, and every result can explain it.
When a fact changes, m3 does not overwrite it. Three mechanisms, each different:
Similarity-based supersession (on every write). A new memory very similar to an older one of the same type (cosine similarity above 0.92 by default) but with different text becomes the current version: the older one's
valid_tois closed and both stay queryable withas_of. It does not judge whether the two actually contradict, so a refinement ("PostgreSQL with connection pooling") replaces the older wording too; nothing is lost from the history. It applies only to an agent's own memories, and only when the write names its user or agent.Explicit supersession. An agent calls
memory_supersedeto replace a memory it knows is wrong.Contradiction detection (model-assisted). With the cognitive loop on, its Reflector stage uses a model to find memories that genuinely disagree and records them for resolution.
With the cognitive loop enabled, m3 also embeds new memories, extracts entities and relationships, and decays memories that are not used. Rolling related notes up into higher-level beliefs is a separate opt-in.
The default store is a single SQLite file. PostgreSQL is a first-class alternative when you want one store shared across machines.
📍 Project status
The core is stable, and so are the web dashboard, the cognitive loop and the Observer & Reflector stages.
Status | What it means | Features |
Stable | Safe to build on: tested on every release, and changes come with a deprecation notice. | Saving, searching, updating and superseding memories · hybrid search (keywords plus meaning) · version history · supersession on write · GDPR export and erasure · SQLite and PostgreSQL storage · MCP server and |
Planned | Coming next, in this order (ROADMAP). | Health and Prometheus metrics endpoint · HNSW approximate search on PostgreSQL |
Memory reads audited: each memory read and search hit is logged with who read it, whose data it was and when, kept 90 days, and included in GDPR export and erasure (GDPR). Chat-log reads are next.
One config file:
m3_config.tomlholds every setting, andm3 config showprints each one with where it came from (Config reference). Old environment-variable names are no longer read;m3 doctornames any still set (Environment variables).Predictable upgrades: calendar versions (
YYYY.M.D.N). A renamed setting, argument or tool keeps working, with a warning, before it is removed, andm3 doctornames anything you still use (Changelog).
⚡ m3 at a glance: technical capabilities
m3 is a persistent, local-first memory layer for AI agents: an MCP server and a JSON-in, JSON-out command-line tool over the same store. It is not an LLM, a chatbot, a plain vector database, a RAG framework or an agent runtime.
m3 is more than a searchable memory store. It combines hybrid keyword and semantic retrieval, bitemporal history, automatic supersession, model-assisted contradiction review, a knowledge graph and background memory maintenance (the cognitive loop). Several agents can share one store; several machines can share one PostgreSQL database, or keep local stores synced through a PostgreSQL warehouse. Your existing assistants reach all of it through MCP, the CLI or framework integrations, with no new agent runtime, and it can run entirely on your own hardware.
Capability | Support | Details |
Memory that persists across sessions and agents | Built in | Text is stored verbatim and survives restarts, new sessions and switching agents. (Memory model) |
Hybrid retrieval | Built in | BM25 keywords (SQLite FTS5) plus local BGE-M3 vectors, with MMR for diversity: nine ranking signals, and every result can explain its score. (Ranking signals) |
Bitemporal history | Built in | Valid time and transaction time on every memory; ask what was believed at any point ( |
Similarity-based supersession | Built in | On every write, a very similar memory of the same type with different text becomes the current version. This is similarity, not a judgement of contradiction; the earlier version stays in the history ( |
Explicit correction | Built in |
|
Model-assisted contradiction review | With the cognitive loop and a model | The Reflector stage finds memories that may conflict and records them for resolution. (How memory maintains itself) |
Knowledge graph | Built in | Links between memories, graph traversal up to 3 hops, and entity tools. Entities are extracted rule-based by default, or by a model in the cognitive loop. (Architecture) |
Background maintenance (cognitive loop) | Built in; enable in | Embedding, entity extraction, enrichment (Observer and Reflector), classification, session summaries, pruning, importance decay, sync and an audit chain. Passes that need a model use a local or cloud LLM. (How memory maintains itself) |
Session recall | Built in | At a fresh session start, a numbered menu of your recent sessions (0 = none); summaries are written by the cognitive loop. |
Multi-agent shared memory | Built in | Agent, user and org scopes, handoffs into another agent's inbox, shared task trees, and safe concurrent writes. Isolation between agents is advisory unless you turn on enforcement. (Multi-agent) |
Several machines, one store | Built in | Every machine reads and writes one PostgreSQL 16+ database directly, with no separate synchronization step. (Multi-agent) |
Several machines, synced | Optional | Each machine keeps SQLite and syncs hourly, both ways, with a PostgreSQL warehouse (hub and spoke; the latest write wins). Deliberately not peer-to-peer: one hub keeps one place where conflicts are resolved and one network surface to secure. (Sync) |
Local embeddings, offline use | Built in | BGE-M3 runs on your machine; nothing needs the internet after install, and air-gapped installs are supported. (Sovereign deployment) |
Storage | Built in | SQLite by default: a database file, with no server to run. PostgreSQL 16, 17 and 18 tested; pgvector optional. (Architecture) |
Interfaces | Built in | MCP server; |
Context efficiency | Built in | 100+ tools in 9 domains; only 6 load at startup (about 3,200 tokens, 1.6% of a 200K window), the rest on demand. (Domain gating) |
Agent integrations | Supported integrations | Claude Code, Codex, Gemini CLI and Antigravity (plugins and extension); Cursor, Cline, OpenCode and OpenClaw (wired by |
Framework integrations | Supported integrations | LangChain and LangGraph, CrewAI, PydanticAI. (Integrations) |
Chat capture | Built in | Conversation turns saved as they happen, before an agent compacts its context: Claude Code, Codex, Gemini CLI, Antigravity (app, IDE and CLI), OpenCode, OpenClaw and Aider. (Chat log) |
Files memory | Built in | A 25-tool domain ingests and chunks whole directories. (Files memory) |
Dashboard and wiki | Built in | A local web dashboard (graph, browser, audit log, health); |
GDPR | Built in | Export (Art. 20) and erasure (Art. 17); every memory read and search hit is logged for 90 days. Chat-log reads are not audited yet. (GDPR) |
FIPS 140-3 | Ready | m3's cryptography runs through one provider that a validated module (wolfCrypt FIPS) can serve; m3 itself is not a validated product. (FIPS boundary) |
Remote clients | Verified | Claude.ai, the Anthropic API, the xAI API (Grok) and the OpenAI Responses API, through |
Approximate (HNSW) search | Planned | Search is exact today, accelerated by pgvector on PostgreSQL. (Roadmap) |
Tested: 5,700+ tests on Windows, macOS and Linux × Python 3.12–3.15, plus a PostgreSQL (with pgvector) lane on Linux, with the native (Rust) core that ships with m3; warnings fail the build. Security scans are published in
docs/audits/. (Testing)Status: stable: the core, the web dashboard, the autonomous cognitive loop and the Observer & Reflector stages. Apache 2.0. (Project status · Roadmap)
Configuration: one file,
m3_config.toml.m3 config showprints every setting and where it came from. (Config reference)For AI agents: llm-context.md lists the real tool names and usage rules, and features.json is the machine-readable summary.
🧭 Where to go next
New to AI memory? Start with the 5-minute Getting Started guide, then your system's install guide: Windows · macOS · Linux. Something not working? Troubleshooting · FAQ · Health FAQ.
Building with AI agents? Installation · Client setup · LangChain · CrewAI · PydanticAI · Agent instructions · For AI agents · For developers · Coding guide · CLI reference.
Evaluating memory systems? Benchmarks · Comparison with Mem0, Letta, Zep and others · Memory model · Architecture · Technical details · Sovereign deployments · Compliance.
Every document: the documentation index.
🤝 Multi-agent memory and cross-machine use
One memory layer for many agents and machines. m3 supports concurrent agents sharing one database; separate agent, user and organization scopes; handoffs and shared tasks; and two cross-machine models: direct access to one shared PostgreSQL database, or local SQLite stores synced through a PostgreSQL warehouse.
Several agents can share one m3 memory at the same time. Each memory carries a scope: agent (one agent's own notes), user or org. Agents coordinate through handoffs into another agent's inbox and through shared task trees. Writes are safe under concurrency: on SQLite, 16 agents writing at once completed 640 writes with no failures, each waiting at most half a second. Isolation between agents is advisory by default; an opt-in filter enforces it in SQL.
Across machines there are two setups, and they work differently:
One shared PostgreSQL store. Every machine reads and writes the same PostgreSQL 16+ database. There is no separate synchronization step; this is the setup for a fleet.
Sync with a warehouse. Each machine keeps its own SQLite store and syncs every hour, in both directions, with a PostgreSQL warehouse: memories, embeddings, relationships, tasks and chat-log rows. The warehouse is the hub (machines never sync with each other directly), and the most recent write wins. Some local-only data, such as the entity graph, stays on its machine.
SQLite is the default and m3 setup keeps it. To move to a shared PostgreSQL store:
pip install "m3-memory[postgres]", store the server's address with
m3 secret set M3_PRIMARY_PG_URL, then run m3 install-m3 --db-backend postgres.
For clients that cannot run m3 locally, m3 serve exposes the memory as a remote MCP
endpoint behind a bearer token.
(Multi-agent · Sync · Remote clients)
📊 Benchmarks
To compare retrieval quality, start with Session Hit-Rate (SHR). SHR measures whether the memory system retrieves the session holding the evidence a question needs, independently of the model that writes the answer.
End-to-end QA accuracy measures a different outcome: whether the whole system produces the correct answer. It depends on retrieval, the answer model, the prompt and the judge, and those are rarely held constant across published comparisons.
m3 reports both and uses SHR as its primary retrieval benchmark. SHR does not measure everything a memory layer does (supersession, history, maintenance and multi-agent coordination are not scored by it).
Retrieval Accuracy — Session Hit-Rate @ k (the primary retrieval metric)
Evaluated on the 500-question LongMemEval-S dataset, using m3's production search function:
Retrieve Depth (k) | Session Hit-Rate (SHR) ⁂ | Success Count |
1 † | 91.8% | 459 / 500 |
5 | 98.2% | 491 / 500 |
8 (default) | 99.2% | 496 / 500 |
10 | 99.2% | 496 / 500 |
20 | 100.0% | 500 / 500 |
Compared with the previous engine, v3 improves SHR@5 from 96.2% to 98.2% and SHR@10 from 96.8% to 99.2%. It reaches 100% at k=20, where the previous engine reported 97.8% at k=30 (LongMemEval issue #43). All of these are retrieval-only measurements, with no answer model.
† SHR@1 measures whether the correct session is the top-ranked result. High first-result accuracy can let an agent retrieve less context, when its retrieval strategy supports it. SHR@8 is m3's default search depth: a gold session is present for 99.2% of questions, the same as at k=10, which retrieves 25% more rows on LongMemEval-S for no gain. Other systems usually report k=5, k=10, k=20 or k=50; compare at the same k, using m3's figure for that depth.
⁂ Which aggregation. These are binary per-question
recall_any@kvalues — the convention adjacent LongMemEval submissions report. The benchmarking report's per-question-type table aggregates slightly differently and reads marginally higher at shallow depth (98.8% at k=5, 99.4% at k=10); k=20 is 100.0% either way. The table above quotes the more conservative figures.
End-to-End QA Accuracy (depends on the answer model and the judge)
92.0% accuracy (460/500 correct responses) without using the dataset's question-type labels (no oracle routing). This measures the whole system; see the note above on why it is not comparable across systems the way SHR is:
Question Domain | Count (n) | Accuracy |
single-session-user | 70 | 94.3% |
single-session-assistant | 56 | 96.4% |
single-session-preference | 30 | 80.0% |
multi-session | 133 | 87.2% |
temporal-reasoning | 133 | 95.5% |
knowledge-update | 78 | 93.6% |
Overall Summary | 500 | 92.0% |
How the QA figure was produced. m3 retrieves; it does not answer questions. In deployment the calling agent chooses what to retrieve and writes the answer. The benchmark harness plays that role: it chooses retrieval options per question (session expansion and a precomputed recall surface, both available in m3's engine but off by default) using a question-text router that is part of the harness, and it supplies the answer prompts and model. m3's built-in intent routing is on by default in both. The retrieval figures (SHR) use m3's search alone.
Methodology and reproducibility details are located in the LongMemEval-S Benchmarking Report.
Performance
Writes: about 2 ms with the embedding deferred: text search finds the memory at once, and with the cognitive loop enabled, semantic search finds it in under 30 seconds. With the embedding inline, a write takes about 31 ms.
Search: about 45 ms (p50) on the benchmark store. At 50,000 memories, 0.45 s on SQLite and 0.27 s on PostgreSQL with pgvector. A real 83,000-memory store answers in 2.7 s on SQLite, or 0.54 s on PostgreSQL with pgvector.
Concurrency: 16 agents writing to SQLite at once lost nothing and waited at most half a second.
Native core: the Rust core speeds up MMR re-ranking 95× to 846× and batch cosine 97× to 178×; without it, results are the same, more slowly.
(Performance · Oxidation benchmarks)
🔌 Interfaces and integrations
Two interfaces, one store. The MCP server and the m3 CLI reach the same
database. Every tool reads JSON on stdin and writes JSON on stdout, grouped as
memory, files, chatlog, tasks, agent, admin, conversations,
diagnostics and entity. A dropped MCP connection is not a memory outage: the CLI
keeps working until the client reconnects.
The full catalog without the context cost. 100+ tools sit in 9 domains, but only 6
register at startup: memory_write, memory_search, memory_supersede,
memory_get, chatlog_search and m3_call. Across real development sessions the four
memory tools (memory_write, memory_search, memory_supersede, memory_get) took
95% of all direct tool calls. An agent reaches any other tool by name
through m3_call, or loads a whole domain.
Gating mode | Registered tools | Tokens in schema | Share of a 200K window |
Lazy (Default) | 6 | ~3,217 | 1.6% |
Typical Active Session (+ | 60 | ~19,549 | 9.8% |
Eager Mode ( | 120 | ~33,149 | 16.6% |
Agents and frameworks:
Agent or framework | How it connects |
Claude Code | Plugin ( |
Codex | Plugin ( |
Gemini CLI | Extension ( |
Google Antigravity | Plugin or |
Cursor, Cline, OpenCode, OpenClaw |
|
Hermes Agent | m3 as its memory provider, wired by |
Aider | Through m3's MCP-to-OpenAI proxy, with a chat-log watcher. (Client setup) |
LangChain and LangGraph | Python library: store, retriever and checkpointer ( |
CrewAI | Storage backend ( |
PydanticAI | Toolset and history processor ( |
Claude.ai, Anthropic API, xAI API, OpenAI API | Remote MCP through |
🛡️ Privacy, security and operations
After installation, m3 runs offline by default. It contacts the internet only for what you turn on: a cloud LLM you configure for enrichment, sync with a warehouse you name, and the daily version check if you said yes to it in m3 setup (a single request to pypi.org).
Sovereign Local Embedder
BGE-M3 (1,024 dimensions) runs on your machine after installation: one shared embed
server on 127.0.0.1:8082 that every m3 process reuses, so one model sits in memory.
In-process embedding is an opt-in at m3 setup: about 1.9× faster on short text and
1.75× on medium text, at the cost of one model copy per process. m3 embedder install-gpu adds a CUDA build (tested) or Vulkan and Metal builds; any
OpenAI-compatible embeddings endpoint also works (m3 config set embed.url …).
(Embedding: shared vs in-process)
Rust-Oxidized Performance Core
A native Rust core (m3_core_rs) is installed by default and speeds up ranking and
vector math (measured in Performance); without it, m3 returns the same
results in pure Python, more slowly. (Oxidation Benchmarks)
Enterprise Security & Compliance
FIPS 140-3 Ready: m3 implements no cryptography; its own (secrets vault, key derivation, HMACs, audit chain, random keys) runs through one provider that a validated module (wolfCrypt FIPS) can serve, and every network path is named and fails closed under FIPS mode. Ready, not validated: see the FIPS Boundary Reference for each path and the deployment profiles.
Air-Gapped Install: Supports installation without internet access via pre-compiled python wheels. (See Sovereign Deployment Guide & FIPS Boundary Reference).
Storage Location: databases (
~/.m3/engine), configuration (~/.m3/config) and logs (~/.m3/logs) live under separate roots, each relocatable under[paths]inm3_config.toml, so they can be secured independently. (Config reference · Architecture)
Operations
Web dashboard:
m3 dashboardserves a local control panel on127.0.0.1:8088: the knowledge graph, a memory browser, the conflict and audit log (with GDPR actions) and system health. (Dashboard)Wiki:
m3 wiki generatecompiles your memories into an interlinked Markdown vault, a self-contained HTML viewer, or an Obsidian vault. (Wiki)Diagnostics:
m3 doctorchecks the whole install andm3 doctor --fixrepairs it;m3 config show --originprints every setting and its source.Audit and GDPR: every memory read and search hit is logged with the reader, the data subject and the time, kept 90 days;
gdpr_exportandgdpr_forgetcover Articles 20 and 17. (GDPR)
🎯 Who This Is For
m3 is a great fit if...
You run a homelab or self-hosted stack: m3 is a single
pip installwith no account, no API key, and no outbound calls unless you turn them on — it runs on the hardware you already own, alongside your other self-hosted services. SQLite by default (zero infrastructure); PostgreSQL when you want a shared store across machines.You operate under sovereignty or data-residency requirements — corporate, government, defence, healthcare, or any regulated environment: memory and embeddings never leave your boundary. The embedder runs on your own hardware, the store is a file you control, and installation works fully air-gapped from pre-compiled wheels. FIPS 140-3-ready crypto (
crypto.fips_mode), GDPRgdpr_forget/gdpr_export, audit logs, and relocatable storage roots so databases and configuration can be secured independently.You want the freedom to switch or add agents without losing what they know: change tools on the fly or down the road — Claude Code, Gemini, OpenClaw, Hermes, whatever comes next — and your project's knowledge carries over instead of disappearing with the switch.
You build with LangChain/LangGraph: An advanced replacement for standard memory models, adding bitemporal queries, supersession with version history, and local embeddings.
You build with CrewAI (v1.10–1.x): A drop-in
StorageBackend(Memory(storage=M3StorageBackend(user_id="crew-alpha"))) that gives CrewAI bitemporal recall, supersession with version history, and local embeddings — plus the thing single-vector stores can't do: a CrewAI-written memory can also be searchable by every other m3 agent (Claude Code, Gemini, LangChain) if you want.pip install m3-memory[crewai]. See the CrewAI integration guide.You build with PydanticAI: m3-backed memory as either drop-in tools + auto-recall (
register_m3_tools,m3_recall_processor) or a formalM3MemoryToolset(a real PydanticAIAbstractToolset). Built on Pydantic v2, so it runs on Python 3.14 with a plainpip install m3-memory[pydantic-ai]. See the PydanticAI integration guide.You need security and compliance: Built-in
gdpr_forgetandgdpr_exporttools, air-gapped support, and audit logs.You value privacy: no cloud service or subscription required; nothing leaves your machine unless you configure it to.
m3 is NOT a fit if...
You need a hosted SaaS dashboard with managed infrastructure (use Letta).
You don't want persistent memory: you want each session to start fresh, with no ability to retrieve prior sessions' knowledge — m3 exists to do the opposite, so your agent's built-in defaults are the simpler fit.
⚖️ How m3 Compares
m3 is the local-first, MCP-native memory layer that stays on your machine and works with the agents you already use. Mem0 is a cloud-oriented memory service with opinionated extraction. Letta is a full agent runtime that owns the conversation loop. Zep and Graphiti are graph-first systems that typically need a dedicated graph database. m3 adds persistent, searchable, versioned memory without asking you to change your agent stack or run extra infrastructure.
A full, feature-by-feature comparison table — m3 vs Mem0, Letta, Zep, Graphiti, LangChain Memory / LangMem, agentmemory, Chronos, Hindsight, Mastra OM, Memento, and more — with sourced benchmarks and honest "when to choose the other tool" guidance, lives in COMPARISON.md.
🛠️ For developers: a memory backend, not a framework
MCP is optional. m3 is a memory layer: it owns durable, searchable, multi-agent memory and stops there, so it drops into whatever you already have. Every tool reads JSON on stdin and writes JSON on stdout, so m3 is scriptable from any language, hook, CI step or cron job, with no SDK and no MCP server:
echo '{"query":"auth","k":3}' | m3 memory memory_search --json-file - | jq '.items[].id'Results compose, and language-specific work (code parsing, VCS watching) stays on your
side of the boundary. Using m3 for coding work has the patterns:
bulk updates from a search, indexing code symbols with ast or tree-sitter, git hooks
and CI steps. (jq is not a dependency; any JSON parser works.)
👀 See it work
What your agent does through MCP, from the shell (output captured from a real run; ids and scores differ on your store). Save a decision:
$ m3 memory memory_write --type decision --title "project-database" \
--content "We chose PostgreSQL for our website."
"Created: 6795c684-53cb-4a6a-9518-819dbc585fe5"Later, in another session or another agent connected to the same m3, ask in your own words:
$ m3 memory memory_search --query "Which database did we decide to use?" --k 1
{
"count": 1,
"items": [
{
"id": "6795c684-53cb-4a6a-9518-819dbc585fe5",
"content": "We chose PostgreSQL for our website.",
"title": "project-database",
"type": "decision",
"importance": 0.5,
"bm25_score": 0.0,
"score": 0.9122939705848694
}
],
"query": "Which database did we decide to use?",
"grade_with": [
"6795c684-53cb-4a6a-9518-819dbc585fe5"
]
}The question shares no words with the memory (bm25_score 0.0), and m3 still finds
it, by meaning. Your agent calls the same tools, so it recalls the decision instead of
asking you again. Core Tools lists the five you'll use most. Prefer to
watch? A short captioned video
shows one decision saved in one agent and recalled by another
(download).
⌨️ The m3 CLI
Content comes from --content or from a file (memory_write_from_file --path), and
logs go to stderr, so stdout pipes cleanly. Check that m3 is up with m3 --version;
if the CLI answers, your memory is reachable even when an MCP client has dropped its
connection (/mcp reconnects Claude Code). (CLI reference)
📦 Installation
Python 3.12 or newer is required. On Python 3.11, pip silently keeps you on 2026.9.12.0, the last release that supported it. Check with
python --version; HOW-TO-UPGRADE.md has the upgrade per OS. Your memories are unaffected: they live outside the virtualenv, under~/.m3/engine.
The install at the top covers the common path (pip install m3-memory → m3 setup). This section adds the alternatives: the shell installer, per-agent wiring, and manual MCP configuration.
The One-Liner (macOS & Linux)
curl -fsSL https://raw.githubusercontent.com/skynetcmd/m3-memory/main/install.sh | bashFor Windows, please follow the Windows Manual Installation Guide.
To install manually on any platform, refer to the OS-Specific Install Instructions or examine the installer script.
Developer Setup Wizard
If you are developing inside python environments:
pip install m3-memory
m3 setupThe m3 setup wizard automatically detects your installed agents — Claude Code, Codex, Cursor, Cline, Gemini CLI, OpenCode, Antigravity, OpenClaw, Hermes — and wires the m3 memory MCP server into each, installs settings files/hooks, provisions the sovereign CPU embedder, and performs a system diagnostic. Detection and wiring re-run on every m3 update/m3 setup, and m3 doctor --fix repoints any config whose paths have moved — so an agent you install later gets picked up automatically the next time you run setup or update.
Every agent and framework above connects through m3 setup or its plugin; see the integrations table.
Manual MCP Server Configuration
To expose m3 to any Model Context Protocol host, add it to your configuration file:
{
"mcpServers": {
"memory": {
"command": "m3"
}
}
}🧰 Core Tools
m3 has 100+ tools; these five are your primary interface. Agents should use these names
exactly: an invented name returns unknown_tool.
Tool name | What it does | When to use it |
| Save a fact, decision, preference or configuration. | The first time you learn something worth keeping. |
| Hybrid keyword (BM25) and semantic (vector) search. | Before writing, and whenever the user asks about past work. |
| Close an old fact and record its replacement, keeping the history. | When a decision or belief has changed; prefer it to overwriting. |
| Fetch one memory by its id. | When a search already gave you the id. |
| Search with an explicit score breakdown for every result (through | When you need to see why a result ranked where it did. |
Rules that keep memory accurate:
Search before you write. Call
memory_searchfirst; if a similar memory exists, supersede it, or edit it withmemory_update(throughm3_call), instead of adding a duplicate.Supersede, don't overwrite. Corrections go through
memory_supersede(or the automatic check on write), so the old version stays queryable withas_of.Pin protects against ageing, not correction.
memory_pinexempts a memory from decay and expiry; a pinned memory can still be superseded when it becomes wrong.
Complete parameters: the Agent Instructions Guide and the
full MCP tool catalog; machine-readable schemas are in
docs/tools/MCP_CATALOG.json.
🤖 For AI Agents
Drop the ruleset examples/AGENT_RULES.md into your
workspace to teach your agent the habits that keep memory clean (search before
writing; update instead of duplicating). llm-context.md lists the
real tool names and usage rules, features.json is the
machine-readable summary, and copy-paste prompts that let an agent install m3 itself
are in the agent instructions.
Operational facts for agents that read only this page:
The startup tools are
memory_write,memory_search,memory_supersede,memory_get,chatlog_searchandm3_call; every other tool is reachable throughm3_call.Search before writing, and use
memory_supersedefor corrections.Memories have a scope (
agent,userororg) and can be pinned; pinning stops decay, not supersession.The embedder runs locally on
127.0.0.1:8082by default. If semantic search returns nothing, checkembedder_status, or download the model withm3 embedder fetch-model.
🎬 See it in action
Supersession on write and version history
Hybrid Search Scoring Details
Multi-Device Database Sync
💬 Community
How to Contribute · FAQ for Developers · Good First Issues
📜 License & Attributions
This project is licensed under the Apache License 2.0. See LICENSE for details.
Built with
m3 Memory is authored and maintained by skynetCMD. It was built with the help of AI coding assistants — Gemini CLI, Claude Code, and Google Antigravity — which contributed code under the author's direction. (They are tools that assisted; they are not maintainers, sponsors, or co-owners of the project.)
Asset & Icon Credits
The provider badges under docs/badges/ embed small logo glyphs:
OpenClaw & OpenCode icons are from the MIT-licensed LobeHub icon set (
lobe-icons).The Hermes badge uses a generic caduceus glyph.
See NOTICE for the full third-party attribution list.
⭐ Star History
Chart regenerated on a schedule by .github/workflows/star-history.yml using the repo's own token — no third-party embed. Click through for the live interactive version.
Available Tools
6 toolschatlog_searchARead-only
Search chat_log rows. FTS5 keyword when query is non-empty; filter-only when empty.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | Max results. | |
| query | Yes | FTS5 query; empty → filter-only listing. | |
| since | No | ISO-8601 lower bound on created_at. | |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| until | No | ISO-8601 upper bound on created_at. | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| agent_id | No | Filter by agent id. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. | |
| model_id | No | Filter by model id. | |
| provider | No | Filter by provider. | |
| host_agent | No | Filter by host agent. | |
| search_mode | No | Lexical (FTS5) only; vector modes are refused. | keyword |
| conversation_id | No | Filter by conversation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds the meaningful FTS5-vs-filter-only branching, but says nothing about result limits (default k=8), ranking, timeout behavior, or which store is consulted by default.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, and the mode-switching rule is front-loaded. Nothing needs to be trimmed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter tool with no output schema and many filter combinations, the description is thin: it never says how filters interact with a non-empty query (AND vs. ignored), what a result row looks like, or how ordering works. It is sufficient to fire a call but not to predict its output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter including search_mode and store already carries its own description. The description reinforces query semantics but adds no format or interaction detail beyond the schema; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search chat_log rows") and clarifies the two operating modes. It does not distinguish itself from siblings like memory_search, so an agent can't tell from this text alone which search surface to pick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The empty-vs-non-empty query rule implies when each mode fires, but there is no explicit guidance on when to call this versus memory_search or memory_get, and no prerequisites or exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
m3_callA
Invoke ANY m3 catalog tool by name without loading its domain — the low-token path to the full tool surface, and the way to reach every tool not loaded at startup. Single call: pass tool (e.g. 'files_stats') and args (an object). Batch: pass batch, a list of {tool, args} (each isolated — one failure won't abort the rest; capped at 100). Set dry_run to validate args + check the destructive gate WITHOUT executing. Returns JSON. Call m3_index first if you don't know a tool's args. Destructive tools are refused unless mcp.allow_destructive is enabled (m3 config set mcp.allow_destructive true).
| Name | Required | Description | Default |
|---|---|---|---|
| args | No | Arguments object for the target tool. | |
| tool | No | Catalog tool name (see m3_index). | |
| batch | No | List of {tool, args} for one-round-trip batch dispatch. | |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| dry_run | No | Validate + gate-check only; do not execute. | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: batch items are isolated so one failure won't abort the rest, batches are capped at 100, dry_run validates args and checks the destructive gate without executing, and the destructive-refusal policy is spelled out with the enabling command. This is rich operational context the structured fields do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose and the single-call path before batch and dry_run details, with no filler sentences. It is dense with parenthetical asides, but each clause carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param dispatcher with nested objects, the description covers the dispatch model, batch isolation, dry_run, and the destructive gate, and defers arg discovery to m3_index. No output schema exists, but 'Returns JSON' plus the schema's own parameter docs make this nearly complete; only store/timeout/database behavior is left to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value by showing the tool/args pairing (e.g. 'files_stats') and the {tool, args} shape for batch, plus the exact meaning of dry_run. It does not explain `store`, `timeout`, or `database`, but the schema documents those adequately.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Invoke ANY m3 catalog tool by name', plus the distinct value proposition ('low-token path to the full tool surface', 'reach every tool not loaded at startup'). An agent can immediately tell this is a meta-dispatcher distinct from concrete siblings like memory_write or chatlog_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'Call m3_index first if you don't know a tool's args', and defines when to set dry_run versus execute. It also states the prerequisite for destructive tools ('refused unless mcp.allow_destructive is enabled') with the exact config command, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_getARead-only
Retrieves a full MemoryItem; accepts full UUID or 8-char prefix; ambiguous prefixes return an error.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Memory item id — 36-char UUID or 8-char prefix. Ambiguous prefixes return an error listing the matching ids. | |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and destructiveHint=false, so safety is covered by structured data. The description adds non-obvious behavior: prefix matching is accepted and ambiguous prefixes produce an error rather than a partial or arbitrary result. It omits behavior for missing ids or how the per-call timeout/database options interact, but the extra context is genuinely useful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with the core action front-loaded, followed by two clauses that each carry distinct information (accepted formats, ambiguity handling). No filler whatsoever.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only single-item fetch with fully described parameters and no output schema, the description covers what is returned ('full MemoryItem') and the key failure mode. A brief note on not-found behavior or that the full item includes its metadata would close the remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including the id prefix rule, store, timeout, and database is already documented. The description restates the id format and ambiguity rule rather than adding new semantics, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Retrieves') and a specific resource ('a full MemoryItem'), with 'full' implicitly contrasting against the partial results you'd get from the sibling memory_search. It stops short of naming that sibling explicitly, but the retrieval semantics are unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: it's clear you need an id, but there is no statement of when to choose this over memory_search or chatlog_search, nor any prerequisite about knowing the id in advance. An agent can infer the intent but has no explicit routing rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_searchARead-only
Find memories by meaning and keywords: hybrid by default; search_mode semantic (vector only) or keyword (lexical only). Returns the top k matches, ranked, with their ids; grade the ones you use with memory_grade. Narrow with type_filter, agent_filter, user_id, scope or conversation_id; as_of searches the store as it was at a past time. Use chatlog_search for captured chat turns and files_search for indexed files.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | Max results (1-100). | |
| as_of | No | ISO-8601 time-travel cutoff. | |
| query | Yes | Search query. | |
| scope | No | Filter by isolation scope. | |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| explain | No | Attach a per-result `_explanation` block (vector/bm25/title_overlap/importance/recency/temporal score breakdown) plus a human-readable `reason` string explaining why each row matched. Same breakdown memory_suggest shows, on the primary search path. | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| user_id | No | Filter by data subject. | |
| variant | No | Ingest-pipeline filter. '' = real user data only (default, equivalent to IS NULL). Pass a specific variant name (e.g. 'heuristic_c1c4') to scope to that bench ingest. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. | |
| adaptive_k | No | Auto-trim results at the score drop-off point. WARNING: regresses on temporal-reasoning, knowledge-update, and multi-session queries; safe only for sharp-curve queries where most retrievals would be noise. Prefer `auto_route=True` on memory_search_routed for safer multi-signal routing. | |
| as_records | No | Return structured records (JSON) instead of the display string. Default false keeps the human-readable output unchanged. | |
| search_mode | No | Retrieval mode. | hybrid |
| type_filter | No | Restrict to a memory type. | |
| agent_filter | No | Restrict to an agent id. | |
| recency_bias | No | Boost newer items (0.0=off, 0.1-0.2=moderate, higher=aggressive). Useful for 'current' or 'latest' queries. | |
| conversation_id | No | Restrict to a conversation / team session. | |
| requesting_agent | No | Calling agent's id. When set, ENFORCES cross-agent isolation: private (scope='agent') rows from OTHER agents are excluded; the caller still sees its own private rows plus all shared scopes (org/user/session). Empty = no enforcement (sees all, back-compat). | |
| include_bench_data | No | Opt in to LOCOMO / LongMemEval bench rows. Default False hides any row with a variant tag. | |
| include_scratchpad | No | Include ephemeral scratchpad items. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds real behavioral context beyond that: ranked top-k results with ids, time-travel semantics for as_of, and the adaptive_k warning about regressing on temporal/multi-session queries. It stops short of covering output format details or any authentication/limit behavior, but it substantially enriches the annotated safety profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a tight, front-loaded paragraph: the primary capability and default mode come first, then filters, then alternatives. Every sentence carries actionable information despite the large parameter surface, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 20-parameter search tool with no output schema, the description covers the essential calling context: default behavior, mode selection, key filters, return shape (ranked top-k with ids), and sibling alternatives. It leaves niche parameters (include_bench_data, include_scratchpad, store/database, variant) to the schema, which is reasonable given the high schema coverage, though an agent must still consult the schema for those.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value by explaining the meaning of the search_mode enum (semantic = vector only, keyword = lexical only, hybrid default), the purpose of the narrowing filters (type_filter, agent_filter, user_id, scope, conversation_id), and as_of as a past-time snapshot. It does not explain every one of the 20 parameters, but it adds useful semantics beyond the schema for the most decision-relevant ones.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Find memories') and immediately clarifies the default retrieval mode (hybrid) plus the two alternatives (semantic, keyword). It explicitly differentiates itself from chatlog_search and files_search, so an agent can select it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing guidance: use chatlog_search for captured chat turns and files_search for indexed files, and use search_mode to choose vector vs lexical vs hybrid. It also describes the follow-up workflow ('grade the ones you use with memory_grade') and when as_of is appropriate (searching the store as it was at a past time).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_supersedeA
Replace one specific memory, by its full id, with a new version. Use it when you know which memory a new fact replaces; memory_write's automatic contradiction check may link the wrong one or none. Non-destructive: the old memory is closed, not deleted (still retrievable by id, in memory_history and in as_of search, linked new -> old by a 'supersedes' edge); it only leaves default search. Pass content to create the successor (type, title, importance and scope you omit are inherited), or replacement_id (a full UUID) to retire old_id into an EXISTING active memory without creating one: the way to clean up duplicates. Exactly one of the two. old_id must be the full UUID; a prefix is rejected (full UUID required for mutation safety; memory_get accepts a prefix). To remove a memory use memory_delete.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Memory type of the replacement. Omit to inherit the old memory's type. One of: auto, belief, chat_log, code, config, conversation, decision, event_extraction, fact, fact_enriched, home, home_automation, infrastructure, knowledge, linux_only, local_device, log, macos_only, message, migration-log, network_config, note, observation, plan, preference, procedure, reference, scratchpad, security, session_note, session_summary, snippet, summary, synthesis, task, to_do, user_fact, windows_only. | |
| embed | No | Embed the replacement for semantic search. | |
| scope | No | Isolation scope of the replacement. Omit to inherit the old memory's scope. | |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| title | No | Title of the replacement. Omit to inherit the old memory's title. | |
| old_id | Yes | FULL UUID of the memory being superseded (not an 8-char prefix — a prefix is rejected for mutation safety). Must exist and not already be deleted/superseded. | |
| source | No | Provenance tag. | agent |
| content | No | Body of the NEW replacement memory (max 50000 chars). Omit when passing replacement_id. | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| user_id | No | Data subject id. | |
| variant | No | Pipeline identifier for A/B variant tracking. | |
| agent_id | No | Owning agent id. Injected by the orchestrator. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. | |
| metadata | No | JSON-encoded metadata object for the replacement. | {} |
| model_id | No | Originating model id. | |
| embed_text | No | Override text used for embedding; falls back to content when empty. | |
| importance | No | 0.0-1.0 relevance of the replacement. Omit (leave at -1) to inherit the old memory's importance. | |
| valid_from | No | ISO-8601 validity start of the replacement; also the point at which the old memory's validity is closed. Defaults to now. | |
| change_agent | No | Agent causing the supersede (audit). | |
| replacement_id | No | FULL UUID of an EXISTING active memory to retire old_id into; nothing is created. Mutually exclusive with content. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=false, and the description substantiates why: the old memory is closed, not deleted, remains retrievable by id, in memory_history, and as_of search, with a 'supersedes' edge. Adds rich context (mutation-safety UUID rule, inheritance defaults) well beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and when-to-use, then the non-destructive semantics, then the content/replacement_id branch. Dense semicolon-heavy paragraph is efficient though bordering on long; nearly every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 20-parameter mutation tool with no output schema, the description covers the key decision points an agent needs: which sibling to use, mutual exclusivity, inheritance defaults, and non-destructive outcomes. Nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: exactly-one-of content/replacement_id, inheritance of omitted fields, the cleanup-duplicates use of replacement_id, and the full-UUID vs prefix rule. Slightly redundant with schema notes on mutual exclusivity but net additive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (replace/supersede) and resource (one specific memory, by full id) with a new version. Explicitly distinguishes from memory_write's automatic contradiction check, so an agent can tell the two apart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use condition ('when you know which memory a new fact replaces') and a when-not/alternative ('memory_write's automatic contradiction check may link the wrong one or none'), plus routing to memory_delete for removal. Nothing left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_writeA
Store a new memory and, by default, embed it for semantic search. For a new fact; to replace a specific memory whose id you know use memory_supersede, and to edit one in place memory_update. An embedded write is checked against existing memories of the same type from the same agent: if it closely matches one (cosine > 0.92 by default) but says something different, the old one is superseded automatically. type='auto' lets the LLM choose the type.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Memory type. One of: auto, belief, chat_log, code, config, conversation, decision, event_extraction, fact, fact_enriched, home, home_automation, infrastructure, knowledge, linux_only, local_device, log, macos_only, message, migration-log, network_config, note, observation, plan, preference, procedure, reference, scratchpad, security, session_note, session_summary, snippet, summary, synthesis, task, to_do, user_fact, windows_only. | |
| embed | No | Embed for semantic search. | |
| scope | No | Isolation scope. | agent |
| store | No | Named store for this call only: main, or a [stores.<name>] in m3_config.toml. | |
| title | No | Short title. | |
| source | No | Provenance tag. | agent |
| content | Yes | Memory body (max 50000 chars). | |
| timeout | No | Per-call timeout in seconds; <=0 disables. | |
| user_id | No | Data subject id. | |
| variant | No | Pipeline identifier for A/B variant tracking. | |
| agent_id | No | Owning agent id. Injected by the orchestrator. | |
| database | No | SQLite file for this call only (legacy; prefer store). SQLite backend only. | |
| metadata | No | JSON-encoded metadata object. | {} |
| model_id | No | Originating model id. | |
| valid_to | No | ISO-8601 validity end. | |
| embed_text | No | Override text used for embedding; falls back to content when empty. | |
| importance | No | 0.0-1.0 relevance. | |
| refresh_on | No | ISO-8601 timestamp when this memory should be flagged for review (lifecycle / planned obsolescence). | |
| valid_from | No | ISO-8601 validity start. | |
| change_agent | No | Agent causing the write (audit). | |
| auto_classify | No | Let the LLM pick the type (forced true if type='auto'). | |
| refresh_reason | No | Why this memory needs refreshing (e.g., 'quarterly policy review'). | |
| conversation_id | No | Groups this memory with a conversation / team session. Same ID space as conversation_start. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses a non-obvious side effect annotations do not: an embedded write is deduplicated against same-type/same-agent memories and can automatically supersede one when cosine > 0.92. That is the key behavioral risk for a caller. It does not mention failure modes, whether supersede is reversible, or what is returned, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core action, then routing to alternatives, then the dedupe caveat. No sentence is redundant with the name or the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, routing, and the automatic-supersede side effect for a 23-parameter mutation tool. However, with no output schema, the description never says what the call returns (e.g., the new memory id needed for later supersede/update), which is a meaningful omission for a create tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: embed is on by default (and why), and type='auto' delegates type choice to the LLM. It does not explain scope/store interactions or the validity/refresh parameters, so it is a modest lift over the schema rather than a full one.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Store a new memory") and immediately scopes it as a write plus default embedding. It explicitly names the two sibling tools it is not (memory_supersede, memory_update), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit selection rule: "For a new fact; to replace a specific memory whose id you know use memory_supersede, and to edit one in place memory_update." The when-to-use and the alternative-with-condition are both stated outright.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
20 tool updates
v0.1.21- Removed
agent_list - Changed
chatlog_search30 fields changed- added
Input schema / properties / agent_id / descriptionAdded value: +"Filter by agent id." - removed
Input schema / properties / agent_id / titleRemoved value: -"Agent Id" - added
Input schema / properties / conversation_id / descriptionAdded value: +"Filter by conversation." - removed
Input schema / properties / conversation_id / titleRemoved value: -"Conversation Id" - removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / host_agent / descriptionAdded value: +"Filter by host agent." - removed
Input schema / properties / host_agent / titleRemoved value: -"Host Agent" - added
Input schema / properties / k / descriptionAdded value: +"Max results." - removed
Input schema / properties / k / titleRemoved value: -"K" - added
Input schema / properties / model_id / descriptionAdded value: +"Filter by model id." - removed
Input schema / properties / model_id / titleRemoved value: -"Model Id" - added
Input schema / properties / provider / descriptionAdded value: +"Filter by provider." - removed
Input schema / properties / provider / titleRemoved value: -"Provider" - added
Input schema / properties / query / descriptionAdded value: +"FTS5 query; empty → filter-only listing." - removed
Input schema / properties / query / titleRemoved value: -"Query" - changed
Input schema / properties / search_mode / defaultPrevious value: -"hybrid"New value: +"keyword" - added
Input schema / properties / search_mode / descriptionAdded value: +"Lexical (FTS5) only; vector modes are refused." - added
Input schema / properties / search_mode / enumAdded value: +[ + "keyword" +] - removed
Input schema / properties / search_mode / titleRemoved value: -"Search Mode" - added
Input schema / properties / since / descriptionAdded value: +"ISO-8601 lower bound on created_at." - removed
Input schema / properties / since / titleRemoved value: -"Since" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - added
Input schema / properties / until / descriptionAdded value: +"ISO-8601 upper bound on created_at." - removed
Input schema / properties / until / titleRemoved value: -"Until" - removed
Input schema / titleRemoved value: -"chatlog_searchArguments"
- Removed
chatlog_status - Removed
chatlog_write - Removed
files_corpus_list - Removed
files_get - Removed
files_health - Removed
files_index - Removed
files_search - Removed
files_stats - Changed
m3_call19 fields changed- removed
Input schema / properties / args / additionalPropertiesRemoved value: -true - added
Input schema / properties / args / descriptionAdded value: +"Arguments object for the target tool." - removed
Input schema / properties / args / titleRemoved value: -"Args" - added
Input schema / properties / batch / descriptionAdded value: +"List of {tool, args} for one-round-trip batch dispatch." - removed
Input schema / properties / batch / itemsRemoved value: -{} - removed
Input schema / properties / batch / titleRemoved value: -"Batch" - removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / dry_run / descriptionAdded value: +"Validate + gate-check only; do not execute." - removed
Input schema / properties / dry_run / titleRemoved value: -"Dry Run" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - added
Input schema / properties / tool / descriptionAdded value: +"Catalog tool name (see m3_index)." - removed
Input schema / properties / tool / titleRemoved value: -"Tool" - added
Input schema / requiredAdded value: +[] - removed
Input schema / titleRemoved value: -"m3_callArguments"
- Removed
m3_help_capabilities - Removed
m3_index - Changed
memory_get10 fields changed- removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / id / descriptionAdded value: +"Memory item id — 36-char UUID or 8-char prefix. Ambiguous prefixes return an error listing the matching ids." - removed
Input schema / properties / id / titleRemoved value: -"Id" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - removed
Input schema / titleRemoved value: -"memory_getArguments"
- Changed
memory_search43 fields changed- added
Input schema / properties / adaptive_k / descriptionAdded value: +"Auto-trim results at the score drop-off point. WARNING: regresses on temporal-reasoning, knowledge-update, and multi-session queries; safe only for sharp-curve queries where most retrievals would be noise. Prefer `auto_route=True` on memory_search_routed for safer multi-signal routing." - removed
Input schema / properties / adaptive_k / titleRemoved value: -"Adaptive K" - added
Input schema / properties / agent_filter / descriptionAdded value: +"Restrict to an agent id." - removed
Input schema / properties / agent_filter / titleRemoved value: -"Agent Filter" - added
Input schema / properties / as_of / descriptionAdded value: +"ISO-8601 time-travel cutoff." - removed
Input schema / properties / as_of / titleRemoved value: -"As Of" - added
Input schema / properties / as_records / descriptionAdded value: +"Return structured records (JSON) instead of the display string. Default false keeps the human-readable output unchanged." - removed
Input schema / properties / as_records / titleRemoved value: -"As Records" - added
Input schema / properties / conversation_id / descriptionAdded value: +"Restrict to a conversation / team session." - removed
Input schema / properties / conversation_id / titleRemoved value: -"Conversation Id" - removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / explain / descriptionAdded value: +"Attach a per-result `_explanation` block (vector/bm25/title_overlap/importance/recency/temporal score breakdown) plus a human-readable `reason` string explaining why each row matched. Same breakdown memory_suggest shows, on the primary search path." - removed
Input schema / properties / explain / titleRemoved value: -"Explain" - added
Input schema / properties / include_bench_data / descriptionAdded value: +"Opt in to LOCOMO / LongMemEval bench rows. Default False hides any row with a variant tag." - removed
Input schema / properties / include_bench_data / titleRemoved value: -"Include Bench Data" - added
Input schema / properties / include_scratchpad / descriptionAdded value: +"Include ephemeral scratchpad items." - removed
Input schema / properties / include_scratchpad / titleRemoved value: -"Include Scratchpad" - added
Input schema / properties / k / descriptionAdded value: +"Max results (1-100)." - removed
Input schema / properties / k / titleRemoved value: -"K" - added
Input schema / properties / query / descriptionAdded value: +"Search query." - removed
Input schema / properties / query / titleRemoved value: -"Query" - added
Input schema / properties / recency_bias / descriptionAdded value: +"Boost newer items (0.0=off, 0.1-0.2=moderate, higher=aggressive). Useful for 'current' or 'latest' queries." - removed
Input schema / properties / recency_bias / titleRemoved value: -"Recency Bias" - added
Input schema / properties / requesting_agent / descriptionAdded value: +"Calling agent's id. When set, ENFORCES cross-agent isolation: private (scope='agent') rows from OTHER agents are excluded; the caller still sees its own private rows plus all shared scopes (org/user/session). Empty = no enforcement (sees all, back-compat)." - removed
Input schema / properties / requesting_agent / titleRemoved value: -"Requesting Agent" - added
Input schema / properties / scope / descriptionAdded value: +"Filter by isolation scope." - removed
Input schema / properties / scope / titleRemoved value: -"Scope" - added
Input schema / properties / search_mode / descriptionAdded value: +"Retrieval mode." - added
Input schema / properties / search_mode / enumAdded value: +[ + "hybrid", + "semantic", + "keyword" +] - removed
Input schema / properties / search_mode / titleRemoved value: -"Search Mode" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - added
Input schema / properties / type_filter / descriptionAdded value: +"Restrict to a memory type." - removed
Input schema / properties / type_filter / titleRemoved value: -"Type Filter" - added
Input schema / properties / user_id / descriptionAdded value: +"Filter by data subject." - removed
Input schema / properties / user_id / titleRemoved value: -"User Id" - added
Input schema / properties / variant / descriptionAdded value: +"Ingest-pipeline filter. '' = real user data only (default, equivalent to IS NULL). Pass a specific variant name (e.g. 'heuristic_c1c4') to scope to that bench ingest." - removed
Input schema / properties / variant / titleRemoved value: -"Variant" - removed
Input schema / titleRemoved value: -"memory_searchArguments"
- Changed
memory_supersede43 fields changed- added
Input schema / properties / agent_id / descriptionAdded value: +"Owning agent id. Injected by the orchestrator." - removed
Input schema / properties / agent_id / titleRemoved value: -"Agent Id" - added
Input schema / properties / change_agent / descriptionAdded value: +"Agent causing the supersede (audit)." - removed
Input schema / properties / change_agent / titleRemoved value: -"Change Agent" - added
Input schema / properties / content / defaultAdded value: +"" - added
Input schema / properties / content / descriptionAdded value: +"Body of the NEW replacement memory (max 50000 chars). Omit when passing replacement_id." - removed
Input schema / properties / content / titleRemoved value: -"Content" - removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / embed / descriptionAdded value: +"Embed the replacement for semantic search." - removed
Input schema / properties / embed / titleRemoved value: -"Embed" - added
Input schema / properties / embed_text / descriptionAdded value: +"Override text used for embedding; falls back to content when empty." - removed
Input schema / properties / embed_text / titleRemoved value: -"Embed Text" - added
Input schema / properties / importance / descriptionAdded value: +"0.0-1.0 relevance of the replacement. Omit (leave at -1) to inherit the old memory's importance." - removed
Input schema / properties / importance / titleRemoved value: -"Importance" - added
Input schema / properties / metadata / descriptionAdded value: +"JSON-encoded metadata object for the replacement." - removed
Input schema / properties / metadata / titleRemoved value: -"Metadata" - added
Input schema / properties / model_id / descriptionAdded value: +"Originating model id." - removed
Input schema / properties / model_id / titleRemoved value: -"Model Id" - added
Input schema / properties / old_id / descriptionAdded value: +"FULL UUID of the memory being superseded (not an 8-char prefix — a prefix is rejected for mutation safety). Must exist and not already be deleted/superseded." - removed
Input schema / properties / old_id / titleRemoved value: -"Old Id" - added
Input schema / properties / replacement_idAdded value: +{ + "default": "", + "description": "FULL UUID of an EXISTING active memory to retire old_id into; nothing is created. Mutually exclusive with content.", + "type": "string" +} - added
Input schema / properties / scope / descriptionAdded value: +"Isolation scope of the replacement. Omit to inherit the old memory's scope." - removed
Input schema / properties / scope / titleRemoved value: -"Scope" - added
Input schema / properties / source / descriptionAdded value: +"Provenance tag." - removed
Input schema / properties / source / titleRemoved value: -"Source" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - added
Input schema / properties / title / descriptionAdded value: +"Title of the replacement. Omit to inherit the old memory's title." - removed
Input schema / properties / title / titleRemoved value: -"Title" - added
Input schema / properties / type / descriptionAdded value: +"Memory type of the replacement. Omit to inherit the old memory's type. One of: auto, belief, chat_log, code, config, conversation, decision, event_extraction, fact, fact_enriched, home, home_automation, infrastructure, knowledge, linux_only, local_device, log, macos_only, message, migration-log, network_config, note, observation, plan, preference, procedure, reference, scratchpad, security, session_note, session_summary, snippet, summary, synthesis, task, to_do, user_fact, windows_only." - removed
Input schema / properties / type / titleRemoved value: -"Type" - added
Input schema / properties / user_id / descriptionAdded value: +"Data subject id." - removed
Input schema / properties / user_id / titleRemoved value: -"User Id" - added
Input schema / properties / valid_from / descriptionAdded value: +"ISO-8601 validity start of the replacement; also the point at which the old memory's validity is closed. Defaults to now." - removed
Input schema / properties / valid_from / titleRemoved value: -"Valid From" - added
Input schema / properties / variant / descriptionAdded value: +"Pipeline identifier for A/B variant tracking." - removed
Input schema / properties / variant / titleRemoved value: -"Variant" - changed
Input schema / requiredPrevious value: -[ - "old_id", - "content" -]New value: +[ + "old_id" +] - removed
Input schema / titleRemoved value: -"memory_supersedeArguments"
- Changed
memory_write48 fields changed- added
Input schema / properties / agent_id / descriptionAdded value: +"Owning agent id. Injected by the orchestrator." - removed
Input schema / properties / agent_id / titleRemoved value: -"Agent Id" - added
Input schema / properties / auto_classify / descriptionAdded value: +"Let the LLM pick the type (forced true if type='auto')." - removed
Input schema / properties / auto_classify / titleRemoved value: -"Auto Classify" - added
Input schema / properties / change_agent / descriptionAdded value: +"Agent causing the write (audit)." - removed
Input schema / properties / change_agent / titleRemoved value: -"Change Agent" - added
Input schema / properties / content / descriptionAdded value: +"Memory body (max 50000 chars)." - removed
Input schema / properties / content / titleRemoved value: -"Content" - added
Input schema / properties / conversation_id / descriptionAdded value: +"Groups this memory with a conversation / team session. Same ID space as conversation_start." - removed
Input schema / properties / conversation_id / titleRemoved value: -"Conversation Id" - removed
Input schema / properties / database / defaultRemoved value: -"" - added
Input schema / properties / database / descriptionAdded value: +"SQLite file for this call only (legacy; prefer store). SQLite backend only." - removed
Input schema / properties / database / titleRemoved value: -"Database" - added
Input schema / properties / embed / descriptionAdded value: +"Embed for semantic search." - removed
Input schema / properties / embed / titleRemoved value: -"Embed" - added
Input schema / properties / embed_text / descriptionAdded value: +"Override text used for embedding; falls back to content when empty." - removed
Input schema / properties / embed_text / titleRemoved value: -"Embed Text" - added
Input schema / properties / importance / descriptionAdded value: +"0.0-1.0 relevance." - removed
Input schema / properties / importance / titleRemoved value: -"Importance" - added
Input schema / properties / metadata / descriptionAdded value: +"JSON-encoded metadata object." - removed
Input schema / properties / metadata / titleRemoved value: -"Metadata" - added
Input schema / properties / model_id / descriptionAdded value: +"Originating model id." - removed
Input schema / properties / model_id / titleRemoved value: -"Model Id" - added
Input schema / properties / refresh_on / descriptionAdded value: +"ISO-8601 timestamp when this memory should be flagged for review (lifecycle / planned obsolescence)." - removed
Input schema / properties / refresh_on / titleRemoved value: -"Refresh On" - added
Input schema / properties / refresh_reason / descriptionAdded value: +"Why this memory needs refreshing (e.g., 'quarterly policy review')." - removed
Input schema / properties / refresh_reason / titleRemoved value: -"Refresh Reason" - added
Input schema / properties / scope / descriptionAdded value: +"Isolation scope." - removed
Input schema / properties / scope / titleRemoved value: -"Scope" - added
Input schema / properties / source / descriptionAdded value: +"Provenance tag." - removed
Input schema / properties / source / titleRemoved value: -"Source" - added
Input schema / properties / storeAdded value: +{ + "description": "Named store for this call only: main, or a [stores.<name>] in m3_config.toml.", + "type": "string" +} - removed
Input schema / properties / timeout / defaultRemoved value: -30 - added
Input schema / properties / timeout / descriptionAdded value: +"Per-call timeout in seconds; <=0 disables." - removed
Input schema / properties / timeout / titleRemoved value: -"Timeout" - added
Input schema / properties / title / descriptionAdded value: +"Short title." - removed
Input schema / properties / title / titleRemoved value: -"Title" - added
Input schema / properties / type / descriptionAdded value: +"Memory type. One of: auto, belief, chat_log, code, config, conversation, decision, event_extraction, fact, fact_enriched, home, home_automation, infrastructure, knowledge, linux_only, local_device, log, macos_only, message, migration-log, network_config, note, observation, plan, preference, procedure, reference, scratchpad, security, session_note, session_summary, snippet, summary, synthesis, task, to_do, user_fact, windows_only." - removed
Input schema / properties / type / titleRemoved value: -"Type" - added
Input schema / properties / user_id / descriptionAdded value: +"Data subject id." - removed
Input schema / properties / user_id / titleRemoved value: -"User Id" - added
Input schema / properties / valid_from / descriptionAdded value: +"ISO-8601 validity start." - removed
Input schema / properties / valid_from / titleRemoved value: -"Valid From" - added
Input schema / properties / valid_to / descriptionAdded value: +"ISO-8601 validity end." - removed
Input schema / properties / valid_to / titleRemoved value: -"Valid To" - added
Input schema / properties / variant / descriptionAdded value: +"Pipeline identifier for A/B variant tracking." - removed
Input schema / properties / variant / titleRemoved value: -"Variant" - removed
Input schema / titleRemoved value: -"memory_writeArguments"
- Removed
task_list - Removed
tools_list_domains - Removed
tools_load_domain
4 tool updates
v0.1.20- Changed
agent_list1 field changed- added
Input schema / properties / as_recordsAdded value: +{ + "default": false, + "title": "As Records", + "type": "boolean" +}
- Changed
m3_help_capabilities1 field changed- added
Input schema / properties / as_recordsAdded value: +{ + "default": false, + "title": "As Records", + "type": "boolean" +}
- Changed
memory_search1 field changed- added
Input schema / properties / as_recordsAdded value: +{ + "default": false, + "title": "As Records", + "type": "boolean" +}
- Changed
task_list1 field changed- added
Input schema / properties / as_recordsAdded value: +{ + "default": false, + "title": "As Records", + "type": "boolean" +}
20 tool updates
v0.1.9- Added
agent_list - Added
chatlog_search - Added
chatlog_status - Added
chatlog_write - Added
files_corpus_list - Added
files_get - Added
files_health - Added
files_index - Added
files_search - Added
files_stats - Added
m3_call - Added
m3_help_capabilities - Added
m3_index - Added
memory_get - Added
memory_search - Added
memory_supersede - Added
memory_write - Added
task_list - Added
tools_list_domains - Added
tools_load_domain
11 tool updates
v0.1.7- Removed
agent_list - Removed
files_corpus_list - Removed
files_get - Removed
files_health - Removed
files_index - Removed
files_stats - Removed
memory_search - Removed
memory_supersede - Removed
memory_write - Removed
task_list - Removed
tools_list_domains
9 tool updates
v0.1.6- Removed
chatlog_search - Removed
chatlog_status - Removed
chatlog_write - Removed
files_search - Removed
m3_call - Removed
m3_help_capabilities - Removed
m3_index - Removed
memory_get - Removed
tools_load_domain
20 tool updates
v0.1.2- Changed
agent_list1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
chatlog_search1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
chatlog_status1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
chatlog_write1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_corpus_list1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_get1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_health1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_index1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_search1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
files_stats1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
m3_call1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
m3_help_capabilities1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
m3_index1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
memory_get1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
memory_search3 fields changed- added
Input schema / properties / explainAdded value: +{ + "default": false, + "title": "Explain", + "type": "boolean" +} - added
Input schema / properties / requesting_agentAdded value: +{ + "default": "", + "title": "Requesting Agent", + "type": "string" +} - added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
memory_supersede1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
memory_write1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
task_list1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
tools_list_domains1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
- Changed
tools_load_domain1 field changed- added
Input schema / properties / timeoutAdded value: +{ + "default": 30, + "title": "Timeout", + "type": "number" +}
TDQS
Scored across 6 tools
The four memory_* tools have distinct roles (write creates, supersede replaces by id, search finds, get retrieves), and chatlog_search targets a separate domain. The main overlap is m3_call, a generic gateway that can invoke any catalog tool including the memory ones, so an agent must decide between a direct tool and the universal escape hatch.
memory_write/supersede/search/get follow a clean prefix_verb pattern, and chatlog_search keeps a second domain prefix with the same convention. m3_call is an outlier prefix but is clearly a distinct gateway rather than an inconsistency in the memory family.
Six tools is a tidy surface for a memory service and each earns its place. The caveat is that m3_call is a proxy for a much larger catalog, so the visible count understates the real surface an agent must navigate.
Write, supersede, search, get and chatlog search cover the core loop, but the descriptions reference memory_update, memory_delete and memory_grade which are not loaded as tools, forcing agents through m3_call for routine update/delete/feedback. That is a notable gap for a CRUD lifecycle.
Maintenance
Related MCP Connectors
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Persistent memory for AI agents across Claude, ChatGPT and any MCP client.
Persistent memory for AI agents. Semantic search, memory graph, W3C DID identity.
Persistent, inspectable memory for AI agents with lineage, correction, and a hosted MCP endpoint.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal-first persistent memory for AI agents via MCP, enabling semantic search and memory sharing across agents with zero cloud cost and full privacy.8 npm1MIT
- AlicenseNot gradedqualityDmaintenanceLocal-first AI memory layer with hybrid retrieval and brain-inspired namespaces. Enables agents to save, search, and manage memories directly via MCP tools.7 npmMIT
- AlicenseAqualityCmaintenanceEmbedded memory and retrieval engine for AI agents, providing local-first memory with MCP support for multi-agent access control.316 PyPI2MIT
- AlicenseNot gradedqualityDmaintenanceLocal-first memory layer for AI agents. Compresses context with a local LLM and serves hybrid search over MCP.732 npmMIT