mgi-mind
Officialmgi-mind is a local, private long-term memory server for AI assistants: it stores and semantically recalls memories, facts, procedures, and skills, all running locally with no cloud dependency.
Semantic search & browsing:
mind_searchruns hybrid (dense + sparse) search with reranking and filters by library, author, source, or date window;mind_browselists memories by metadata without a query.Unified recall:
mind_recall_allpulls facts, memories, and error→fix procedures in one call;mind_should_searchadvises whether memory should be consulted before answering.Storing memories:
mind_addwrites a memory to a library;mind_ingestauto-extracts candidates (memories, facts, procedures) through a relevance gate with quarantine for low-signal items.Source provenance:
mind_provenance_addpersists externally-sourced snippets (code, docs, RFCs) with a mandatory cited URL and search tool.Knowledge graph:
mind_factadds/queries/invalidates subject→predicate→object facts, with point-in-time (as_of) and superseded-history queries;mind_predicateregisters cardinality so contradictions get resolved by the duel rule.Procedural memory:
mind_learnrecords error→fix lessons,mind_recallretrieves them,mind_procedure_outcomerecords whether a fix worked, andmind_outcomeattaches typed external signals (test passed, code compiled, user confirmed, cited).Skills:
mind_skillstores and matches the "house way" of doing a task (match/set/list/show/remove/outcome) before work starts.Core memory:
mind_blockpins small always-injected notes (persona, user, current project).Sessions & context:
mind_sessionmanages per-agent session logs;mind_contextrenders a compact session-start briefing.Libraries & maintenance:
mind_librarycreates/lists/deletes libraries and memories;mind_historyshows recent additions;mind_consolidatepreviews duplicates and cold entries;mind_restoreun-archives soft-forgotten memories;mind_statsreports counts.Quarantine management:
mind_quarantinelists, shows, promotes, or expires gate-filtered entries.Visualization & web:
mind_visualizeopens a local 3D brain graph;mind_webreads a webpage as Markdown and optionally saves it.Import/export:
mind_exportandmind_importmove data to/from JSON, Markdown, or Obsidian vaults.Secrets & health:
mind_vaultgives terminal-only instructions for the encrypted vault (secrets never cross MCP);mind_doctorchecks system health and can fix missing components.
MGI-Mind
Latest release: v2.10.0 · CHANGELOG · Discussions · Issues · Contributing
Local long-term memory for AI assistants. One Rust binary, a local Qdrant vector database, local ONNX models. Speaks MCP, so Claude Code and other assistants read and write memory on their own. Also a normal CLI.
The same exchange inside an assistant:
You: what was the deploy server again?
Assistant (calls mind_search "deploy server"):
-> "Deploy server is 10.0.0.5:8080, SSH as deploy@, key in vault" (source: infra.md)
You: right, thanksNothing leaves the box. Embeddings, search, reranking and the vault are all local. No cloud account, no API key, no telemetry.
Contents
Related MCP server: memkeeper
What it is
MGI-Mind sits between you and your assistant. The assistant writes short notes ("memories") and facts as a conversation goes, and pulls the relevant ones back when they matter.
Retrieval, not just storage:
Hybrid search. Each memory is stored as two vectors: a dense vector (multilingual-e5-base, 768 dims) for meaning, and a sparse term-frequency vector (TF-IDF, BM25-style) for exact words. A query runs both arms and fuses them with Reciprocal Rank Fusion. "The server box" finds "deploy host" through the dense arm;
fossilize_replayfinds the one note that contains that exact token through the sparse arm.Cross-encoder reranking. Fused top candidates are re-scored by bge-reranker-base, which reads the query and each passage together and is more accurate than comparing vectors. On by default and English-tuned; see Languages and the reranker for the trade-off on other languages.
One warm process.
mgimind mcpis the MCP server itself: it runs for the whole session, models load once and stay warm in memory, so a lookup costs milliseconds instead of reloading on every call.
Around retrieval there's a knowledge graph for structured facts, per-agent session logs for cross-session continuity, and an encrypted terminal-only vault for secrets.
The validity model
Hybrid search is table stakes; most memory tools have some version of it. The part that is harder to find is what keeps the store from ossifying as it fills with old, contradictory, or self-reinforcing beliefs. These run mostly on their own:
Duel rule. When a new fact contradicts an existing one on the same subject and predicate, the second write resolves against the first instead of piling up a second "truth". An entrenched fact (many dependants, confirmations, age) holds; a strong fresh fact flips it and dampens the loser to a hidden
stalestatus; a borderline one is marked contested or diverted to quarantine. Confirmations accrue live: re-asserting the same triple raises its ownconfirmations_count, so a fact confirmed a few times resists a single fresh contradiction (contested, not flipped) while an unconfirmed young fact still flips as easily as before.dependantsstill only comes from themigrate-v14 dependants --applybackfill - a cheap live producer (it would mean walking the graph on every write) is not implemented. Nothing is deleted, so the audit log keeps the loser; a re-proposedstaleloser gets a fair new duel against whatever is current, keeping its own originalcreated_atand confirmation history rather than starting over. A loser re-asserted withinflip_back_window_hoursof losing (config.json, default 24,0turns it off) landscontestedinstead of flipping the winner back, so two values cannot trade places on every write; after the window it gets the normal duel. Automatic, inside a normalmind_fact add.Doubt window. An entrenched fact has to keep re-justifying itself. Every fact query measures how far the current context has drifted from the context the fact was written in; after five consecutive drifted retrievals the fact stops outranking facts that still hold up, and any single in-context retrieval resets the count. Nothing is hidden or deleted. Drift is measured on vectors with the corpus mean removed, because raw cosine cannot separate topics in an anisotropic embedding space (see
mgimind calibratebelow). The current context is the running process's own recent queries, so this applies inside a warmmgimind mcporserve-httpsession; a one-shot CLI command has no context yet and no fact is penalised for that. This ships in shadow: drift is measured and recorded, and no fact changes, until you setdoubt_drift_thresholdfrom your own store's numbers and switchdoubt_drift_modeto"enforce". A background pass separately re-tests entrenched facts that have gone quiet, under hard guarantees: never during a tool call, a per-tick cap, and a load-aware cadence.Inheritance discount.
mind_context's briefing (what a session sees at start) marks every fact it surfaces as inherited for that process. If a duel challenger is a re-proposal of one of those inherited facts - the agent echoing back what it was told rather than independently reconfirming it live - that challenge counts at half weight. The flag clears the moment the agent actually re-asserts the fact live and it lands without a conflict. Single-source decay (repeated confirmation from the same source counting for less each time) has the formula (diversity_weighted_count) but no live caller yet - not implemented, no "cannot co-confirm" guarantee today. The inherited mark lives in the memory of the process that rendered the briefing:mgimind contextrun from a terminal marks nothing for a separatemgimind mcpserver. In normal use the agent's own MCP server renders its briefing, so the mark and the duel are in the same process.Two time axes on facts. Record-time (
created_at/valid_until: when the store learned/retired a value) is bi-temporal with the superseded chain: a predicate can be registered (mind_predicate) as single-valued, temporal-single (one current value, but the previous ones are kept and queryable by date viamind_history), or multi-valued, and a superseded value is hidden from default ranking, not erased. An optional second axis, world-time (valid_from, settable on add), records when a fact became true in the world instead of when the store heard about it;mind_fact action=querywithas_of+world_time=trueresolves point-in-time queries against it, falling back to record-time per fact when it has novalid_from. When a successor that carries avalid_fromdisplaces a value, the old value's world-time end (world_until) is set to thatvalid_from, so a backdated successor does not overlap its predecessor on the world axis. Existing facts need no migration - they simply have novalid_fromand behave exactly as before.Explicit invalidate is final.
mind_fact action=invalidateis a one-way door: re-adding the same triple afterward refuses (verdictinvalidated) instead of silently reviving it. A re-add that differs only in case or whitespace (Berlinvsberlin) is refused the same way, and the refusal names the invalidated fact's id.mind_fact action=restoreis the only way back.Typed outcome signals.
mind_outcomerecords that a remembered fix actually worked (test_passed,code_compiled,user_confirmed,cited_by). A real success raises a memory's weight and marks a procedure verified; a failure pulls the weight down rather than being ignored.
These are research-shaped mechanisms, and their tuning constants are still
being calibrated (the TODO(phase-4-calibration) markers in duel.rs /
doubt.rs are honest). The shape is the point: a memory that argues with
itself and demotes what stops holding up, instead of accreting forever.
mgimind calibrate measures whether that shape behaves as intended. It runs a
corpus of realistic conflict situations through the live duel formulas and
reports how many land on the outcome a person would expect: a fresh unsupported
claim cannot overturn an entrenched belief, a CI signal can, repetition alone
coexists rather than overwriting. Today 14 of 15 scenarios match intent; the one
that does not is printed with its reason, not hidden, and the suite runs in CI.
It also reports the doubt window's drift distribution, and that report exists
because of what it found. The drift threshold was 0.4, picked in 384-dim MiniLM
space and left in place when the default model became 768-dim multilingual-e5.
Measured on a live store, 400 memories and all 79800 pairs, raw cosine ran from
0.666 to 0.972: the threshold could not fire once. The corpus mean vector had
norm 0.884, so almost all of that cosine was a component every embedding shares.
Centering fixes the measurement, and calibrate proposes a threshold from the
drift your own store produces rather than from a constant that travelled between
embedding spaces.
This measures the shape of the validity model, separate from retrieval recall (R@k, see BENCHMARKS.md). The two are different numbers and never belong in the same table.
Why bother
An assistant without memory asks for the same context every session and can't build on yesterday's work. The usual workaround is you keeping notes, tags, and folders, which the assistant still can't read by meaning.
The thing MGI-Mind does that Obsidian and Notion don't: the system decides what to write down, you don't. The MCP server reads what the assistant is doing in real time and routes facts, decisions, and fixes into the store through a relevance gate. You don't file, you don't tag, you don't decide what's worth saving. Low-signal candidates land in a quarantine layer (recoverable on re-assertion) instead of polluting retrieval.
How it compares to the obvious alternatives:
Plain notes (Obsidian, Notion). Strong as your personal notebook, but the assistant can't search them by meaning, and every keystroke is equally important to a folder of
.mdfiles.Bare vector database. Semantic search, but no exact-term matching, no reranking, no dedup, no sessions, no facts, no secrets handling, no relevance gate, no procedural memory. You assemble all of that.
Hosted memory API. Your data on someone else's servers. Closes the box on inspection, dedup behaviour, and what the relevance gate is actually doing.
MGI-Mind is the assembled local version: hybrid + reranked retrieval, the relevance gate, dedup, facts, sessions, procedural memory ("error → fix" playbooks), and a terminal-only vault, all behind one binary you run yourself.
A note on evaluating it. BENCHMARKS.md reports retrieval recall (R@k on LongMemEval-S, zero-API, no LLM judge): given a question, did the gold session land in the top-k. On the default CPU config that is R@5 ≈ 98%. This is not the same metric as the QA-accuracy numbers other memory tools publish (they run an answerer and a judge over their retrieval), so do not put it in the same table. It measures whether the evidence was retrievable, not whether an LLM then answered correctly. mgi-mind has no answering step, so retrieval recall is the number it actually owns.
The honest gap: the validity model (duel rule, doubt window, supersession)
is the differentiator, and retrieval recall does not test it. Two things test
it instead. mgimind calibrate checks behavioral shape against intent
(14/15 today, run it yourself); it proves the mechanism does what a reader
expects, not that the constants are tuned against real data. The external
belief-revision benchmark is STALE, and there only a preliminary partial run
exists (N=155, ~32%, raw verdicts under benchmark/results/), produced by the
harness on a branch rather than the scaffold on main, on a reduced haystack,
possibly while the duel rule was still broken. See
BENCHMARKS.md for the full caveats. Treat the validity model as
a designed mechanism whose shape is verified and whose constants are not yet
tuned, not a proven win on external data.
Quick start
Docker (the whole brain in one command)
The image bakes the binary, a bundled Qdrant, the ONNX runtime, and the models, so it runs offline with nothing to install:
docker run -p 8765:8765 madgodinc/mgi-mindIt prints a bearer token on startup. Point the Python client
or any agent at http://localhost:8765 with that token. Persist memory across
restarts with a volume, and pin a stable token:
docker run -p 8765:8765 -e MGIMIND_TOKEN=your-token \
-v mgimind-data:/data madgodinc/mgi-mindPlug it into an agent
Give an agent two tools, recall and remember, and its memory survives the process. With the server running and the Python client installed:
from mgimind import Memory
mem = Memory() # MGIMIND_URL / MGIMIND_TOKEN from the env
mem.add("Prod DB is Postgres 16 on db-prod:5432")
for hit in mem.search("prod database"): # structured results: id, score, author
print(hit["score"], hit["content"])That wrapping is the whole integration. Copy-paste examples for LangGraph,
Pydantic AI, the OpenAI Agents SDK, and raw HTTP (any language) are in
docs/integrations. MCP and stdio still work for editor
clients; the HTTP surface is the door for agent frameworks.
npm (any MCP client)
With Node.js 18 or newer, the npm package installs the prebuilt binary for your platform, checked against the release's SHA-256:
npx -y mgi-mind init # creates ~/mgimind
npx -y mgi-mind doctor --fix # downloads Qdrant and the models
claude mcp add mgimind -- npx -y mgi-mind mcpOther clients take the same command in their MCP config:
"command": "npx", "args": ["-y", "mgi-mind", "mcp"].
Native install
One command. The installer drops the binary on PATH and runs init +
doctor --fix (which pulls Qdrant, ONNX Runtime, and the models). Or just tell
your coding agent to install mgi-mind using AI_INSTRUCTIONS.md:
it covers the install itself, not only how to use it once installed.
Linux / macOS:
curl -fsSL https://raw.githubusercontent.com/madgodinc/mgi-mind/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/madgodinc/mgi-mind/main/install.ps1 | iexWhen it finishes, the printed command wires the server into Claude Code:
claude mcp add mgimind -- /home/you/.local/bin/mgimind mcpmgimind mcp IS the MCP server; it runs for the whole session with the
models warm and brings up the bundled Qdrant on first use. Point your
assistant at AI_INSTRUCTIONS.md once so it knows
the protocol (log a session, search before answering, use the vault for
secrets).
doctor --fix downloads the models into ~/mgimind/: the embedder
(multilingual-e5-base, quantized ONNX, ~270 MB) and the reranker
(bge-reranker-base, quantized ONNX, ~280 MB). ONNX Runtime and the Qdrant
binary land next to the mgimind binary itself, so a doctor that reports
a missing library is telling you about <install dir>/, not ~/mgimind/.
Installer flags
INSTALL_DIR=/opt/mgimind curl ... | sh: install somewhere other than~/.local/bin.MGIMIND_TAG=v2.10.0 curl ... | sh: pin a specific release instead oflatest.SKIP_DOCTOR=1 curl ... | sh: just drop the binary; runinit+doctor --fixyourself later.
Manual install (no installer)
If you'd rather not pipe a script to a shell, grab the release tarball
for your OS from Releases,
put mgimind on your PATH, then:
mgimind init
mgimind doctor --fix
claude mcp add mgimind -- /absolute/path/to/mgimind mcpTry it from the CLI (the same binary works without an assistant):
mgimind create work
mgimind add work "Deploy server is 10.0.0.5:8080, SSH as deploy@"
mgimind search "how do I reach the deploy box"Per-OS notes
Linux x86_64, macOS arm64 and x86_64, Windows x86_64: prebuilt binaries in every release. The installer picks the right one.
macOS PATH: zsh does not include
~/.local/bin, so the installer appends theexport PATHline to your~/.zshrcand tells you it did. Open a new terminal before typingmgimind. SetMGIMIND_NO_PROFILE=1to keep the installer out of your dotfiles and add the line yourself.macOS Intel and ONNX Runtime: 1.24 dropped
osx-x86_64, so Intel Macs get ONNX Runtime 1.23.0 while everything else gets 1.24.2. The binary requests C API 23, which both runtimes serve.macOS first-run quarantine: the installer clears it, but a binary downloaded through a browser needs
xattr -d com.apple.quarantine /path/to/mgimind. Releases are ad-hoc signed, not notarized; on Sequoia and later the right-click → Open trick no longer works for command-line binaries, so usexattr, or approve it once under System Settings → Privacy & Security.Windows: SmartScreen may warn on the unsigned
mgimind.exe("Windows protected your PC"); choose More info → Run anyway. Antivirus can also quarantine the binary or the models it downloads; ifmgimind doctorreports a file as downloaded but missing, allowmgimind.exeand the%USERPROFILE%\mgimindfolder in your AV, then re-runmgimind doctor --fix. Code signing to remove the SmartScreen prompt is on the roadmap.
Build from source
Rust toolchain (rustup); no other dependencies.
git clone https://github.com/madgodinc/mgi-mind.git
cd mgi-mind
cargo build --release # binary: target/release/mgimindThen run target/release/mgimind init && target/release/mgimind doctor --fix
and wire it in with
claude mcp add mgimind -- /absolute/path/to/target/release/mgimind mcp.
Using it
By hand (CLI):
mgimind add notes "Mom's birthday is March 14, she likes peonies" --source personal
mgimind search "when is my mother's birthday"
# 1. [notes] (score: 0.94) Mom's birthday is March 14, she likes peonies
# source: personal
mgimind fact add "user" "prefers" "Rust"
mgimind fact query "user"
# user -> prefers -> Rust
mgimind history --limit 3 # the three most recent memories
mgimind stats # counts per library, facts, sessionsDuel rule on contradictions. When two facts contradict and the
predicate is Single or TemporalSingle, the second add resolves
against the first instead of piling up:
# Tell the system this predicate has one current value at a time:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"mind_predicate","arguments":
{"action":"register","predicate":"lives_in",
"cardinality":"TemporalSingle"}}}' \
| mgimind mcp
mgimind fact add "Alice" "lives_in" "Prague"
mgimind fact add "Alice" "lives_in" "Dublin"
mgimind fact query "Alice"
# Alice -> lives_in -> Dublin
# (Prague is preserved as history, queryable via mind_history / audit log
# but hidden from default ranking.)If you migrated from a pre-v1.7 install where the duel rule wasn't
firing at the read path, run mgimind migrate-v14 redo-duels --apply
once to collapse legacy contradictions to canonical answers. The
walk is idempotent and dry-run by default.
Through your assistant (MCP). Once connected, you just talk:
You: remember that the staging DB password is in the vault under "staging-db"
Assistant: (mind_add) saved. The secret itself stays in your terminal vault, not here.
You: what database are we using on staging?
Assistant: (mind_search "staging database") Postgres 16, host db-staging.internal:5432Search returns results in tiers so the assistant spends tokens carefully:
--tier 1 is a ~100-character snippet, --tier 2 (default) is ~500,
--tier 3 is the full text.
Seeing the store
mgimind brain renders the memory as a graph: cores for memories, facts,
and regions, wired by the links between them, pulsing as the store changes.
It binds to loopback only and needs the token printed alongside its URL.
Treat it as a control surface. An unrestricted viewer also serves
DELETE /api/memories/:id, PATCH /api/node/:id and quarantine promotion,
so whatever reaches that port with that token can change the store. For a
viewer that cannot write, start it confined to an allowlist:
mgimind viewer --libraries work,personalThat fail-closes every mutating route with a 403, along with the routes that
span all libraries (graph, audit, pulse, the ingest feed). mgimind brain
takes no flags, so it is always the unrestricted form.
How it works
your AI assistant
| MCP (JSON-RPC over stdio)
v
mgimind mcp (one Rust process: MCP server + embedder, models stay warm)
| starts on first use
v
Qdrant (local, loopback only)
|
one "memories" collection, two vectors per point:
dense (e5, meaning) + sparse (TF-IDF, exact terms)Storage. All memories live in one Qdrant collection. A library field
on each point separates namespaces (work, personal, a project), and a
query can filter to one library or search across all. A point's ID is a
UUIDv5 of library + content, so adding the same text twice overwrites
the same point, with no duplicates and no race. A created_at datetime index
lets history return the newest N directly without scanning.
Embeddings. Text is embedded locally through ONNX Runtime. Default is
multilingual-e5-base (768 dimensions), strong on English and handles
mixed languages. The embedder is model-aware: pooling (mean or CLS),
token_type_ids input, query/passage prefixes are all config, so
switching models doesn't need a code change. Inputs cap at 512 tokens;
add splits long text into chunks so nothing past the cap silently
disappears.
Search. The query is embedded once. Qdrant runs a dense nearest-
neighbor search and a sparse search in a single Query API call and fuses
them with RRF. If reranking is on, the top rerank_top_k candidates are
re-scored by the cross-encoder and reordered. A library filter, when
given, applies to both arms.
Safety. Downloads check against pinned SHA-256 hashes (fail-closed). Qdrant binds to loopback only and can require an API key. The vault is terminal-only, and the master password and decrypted secrets never travel over the MCP channel. File writes are atomic (temp file, fsync, rename, fsync the directory), so a crash leaves the old file or the new one, never a corrupt one.
Command reference
Memory
Command | What it does |
| Store a memory. Long text is chunked; prints how many chunks were stored. |
| Hybrid search, then rerank. Tier sets how much text comes back. |
| Most recent memories, newest first. |
| Delete one memory by id (id is shown in search results). |
| A compact session-start briefing: last session, recent facts, libraries. |
Libraries
Command | What it does |
| Register a library. |
| List libraries. |
| Delete a library and all its memories. |
| Counts per library, facts, sessions, vault state. |
Knowledge graph
Command | What it does |
| Store a fact triple. Re-adding the same triple raises its confirmation count instead of piling up a duplicate; refuses (does not revive) a triple that was explicitly invalidated. |
| Find facts matching a term in subject, predicate, or object; |
| Soft-delete a fact (kept on disk, marked invalid, hidden from queries). |
| Undo an invalidate - the only way back. |
Human review
Some facts wait on a person. A write that contradicts a value on record and
lands contested waits on its own; an agent can also put a fact to the user
with mind_review action=ask when it matters and the agent is not sure. Until
the user answers, the fact is labelled as disputed wherever it is read, no duel
can unseat it, and an agent cannot invalidate it.
The agent holds no verb that answers. mind_review has list and ask only.
Answers come from two places, each gated on something an agent's process does
not have:
Command | What it does |
| The open questions, with the values each one contradicts. Works anywhere. |
| Answer a question. Refuses unless stdin and stdout are a terminal, then asks you to type the fact's short id back. |
| Set the PIN the viewer asks for (terminal only, hidden input, stored as an Argon2id hash). |
The viewer has a review tab that sends the PIN with each answer; its bearer
token alone is refused, since an agent that opened the viewer holds the token.
Five wrong PINs lock answers for fifteen minutes. An answer is final for
agents: an accepted value stays, a rejected triple is refused when written
again, and the audit log records review_answer with the surface
(human:terminal or human:viewer-pin).
The limit: an agent that can write files in $MGIMIND_HOME could replace the
PIN hash, as it could replace the store itself. The gate keeps the agent's own
tools from closing its own questions; it is not a sandbox.
Skills
A procedure answers "this broke, what fixed it last time". A skill answers "I am about to do X, is there a house way to do X". Same storage and the same outcome signals, matched at a different moment: against the task, before the work. A context render carries the catalogue (names and triggers), so an assistant knows what exists without searching, and pulls the body only for the skill that applies.
Command | What it does |
| Write a skill. The name is its identity, so writing it again edits it and keeps the history. |
| The skills that apply to a task, ranked by relevance and by how they have worked out. |
| The catalogue, or one skill in full. |
| Record how applying it went. |
| Delete a skill and its outcome history. |
Sessions
Command | What it does |
| Begin a session log for an agent. |
| Close it with a summary. |
| Show the last session (optionally for one agent). |
Vault (terminal only)
Command | What it does |
| Store an encrypted secret. |
| Retrieve a secret (prompts for the master password, then confirms). |
| List key names (values never shown). |
| Delete a secret. |
Service and data
Command | What it does |
| Run as the MCP server over stdio (what your assistant connects to). One warm process; starts Qdrant automatically. |
| Start / stop the bundled Qdrant by hand (rarely needed, |
| Re-embed legacy per-library collections into the single |
| Move memories to a different library. Point ids are content-addressed, so a move recomputes the destination id, carries over the exact vectors and payload, repoints any |
| gzip+tar of the data directory. When Qdrant answers, each collection is captured through its own snapshot API instead of a raw copy of |
| Export memories to files. |
| Import a folder of markdown (recursively, chunked). |
| Health check; |
Configuration
Config lives at ~/mgimind/config.json. Fields that affect retrieval:
Field | Default | Meaning |
|
| Embedding model directory under |
|
| Embedding dimension. Must match the model. |
|
|
|
|
|
|
|
| e5 needs these; empty for models that don't. |
|
| Cross-encoder reranking. See the language note below. |
|
| Reranker directory under |
|
| How many candidates to fetch and rerank before returning |
|
| Qdrant gRPC port. |
| none | Qdrant's REST port, for |
| none | If set, Qdrant starts with it and the client authenticates. |
Languages and the reranker
The default stack is tuned for English, because that's where the assistant itself reasons best and where the models are strongest. It's the recommended setup for an English-first project.
A few honest details:
The embedder (multilingual-e5-base) is genuinely multilingual. An English query finds a Russian note and vice versa, and search alone works well across languages.
The default reranker (bge-reranker-base) is English-tuned. It improves English ranking, but it lowers ranking quality on Russian (and other non-English languages). This is the one place the defaults favor English.
If your content is mostly Russian (or another non-English language): set
rerank_enabled = false. Hybrid dense+sparse search on its own ranks those languages well; the English-tuned reranker is what hurts them. Or swap in a stronger multilingual reranker.Reranking costs cross-encoder inference per query: roughly one to two seconds for 20 candidates on a CPU-only box. Lower
rerank_top_kor turn reranking off for snappier search.
Changing the embedding model
Switching models usually changes the vector dimension, so existing memories must be re-embedded:
Back up first:
mgimind backup ~/mgi-backup.tar.gz.Set
model_name,vector_size,pooling,uses_token_type_ids, and the prefixes inconfig.jsonfor the new model.mgimind doctor --fixto download it. Only the bundled defaults are pinned; a custom model downloads with an "integrity not verified" warning, so pin its SHA-256 inintegrity.rsif you want strict verification.mgimind migrateto re-embed everything from the stored text under the new model.
Troubleshooting
"Model not found ... run doctor --fix": the model is not in
~/mgimind/models/. Runmgimind doctor --fix."invalid expand shape" / inference errors: usually an input far over 512 tokens.
addchunks automatically; if you call the library directly, chunk first.Searches are slow: that's the reranker on CPU. Lower
rerank_top_k, or setrerank_enabled = false. Models stay warm for the life of themgimind mcpprocess, so only the first lookup of a session pays the load cost.A tool fails right after install: run
mgimind doctor(the assistant can callmind_doctor); it reports exactly what's missing (Qdrant not running, a model not downloaded, ONNX Runtime absent, a file quarantined by AV) and--fixdownloads what it can.Dimension mismatch warning: a collection's vectors don't match
vector_size, usually after a model change. Re-embed withmgimind migrate.Russian results feel off: set
rerank_enabled = false(see the language note above).A VPN, tunnel or proxy breaks while mgimind is running: run
mgimind doctorand read the network footprint. Every mgimind port is loopback-bound, and mgimind changes no route, DNS or firewall setting, so it cannot pull traffic out of a tunnel. Look at what starts alongside it: Docker Desktop and WSL2 add virtual adapters of their own, and TUN clients with strict routing can drop the tunnel when an adapter appears or disappears.
Security
Downloads verify against pinned SHA-256 (fail-closed) for ONNX Runtime (linux-x64), Qdrant, and the default models (e5 and the reranker). Other platforms and custom models warn instead of trusting blindly.
Qdrant binds to
127.0.0.1only and supports an API key.The vault is AES-256-GCM with an Argon2id-derived key (parameters pinned so a library upgrade can't lock you out). Terminal-only, so the master password and decrypted secrets never travel over the MCP channel. The
mind_vault_*MCP tools return terminal instructions, never the secret value.File writes are atomic and directory-fsynced, so a crash leaves the old file or the new one, never a corrupt one.
Network footprint
Every socket mgi-mind opens is bound to loopback:
Component | Port | Bind |
Qdrant HTTP |
|
|
Qdrant gRPC |
|
|
| 4173 |
|
| random, printed at startup |
|
| random, or |
|
serve-http --host is the one way to bind another interface (a Docker -p
mapping needs it), and a non-loopback host is refused unless you also pass
--agent-token.
mgimind installs no driver, adds no network adapter, and changes no route,
DNS or firewall setting. mgimind doctor prints this footprint with a live
probe of every port, so the claim is something you can check rather than
trust.
Status and audit
Current version: 2.10.0 (semver-stable since v1.0.0). The 0.x line built
the foundation: the audit log and ephemeral viewer (0.10), the quarantine
layer and best-effort retrieval policy (0.11), the viewer wave (0.12),
session liveness (0.13), and procedural memory (0.14, benchmarked on
LongMemEval-S plus a 227-pair error→fix dataset from 20 public repos). The
1.x line added the validity model: the duel rule, the doubt window and its
background re-test, bi-temporal fact supersession, the confidence score, and
typed outcome signals (mind_outcome), plus install-mode CPU/GPU profiles.
The MCP surface is additive-only until a 2.0 bump: 30 live tools plus 15
deprecated aliases kept for compatibility. Nothing is renamed or removed inside
2.x; new verbs (most recently mind_review) may be added. The other 1.0 contracts
are the asymmetric "Qdrant now → md says" reconcile diff and the
MGIMIND_MODEL_VARIANT={cpu|gpu|auto} switch.
The project went through a code audit; AUDIT_STATUS.md
accounts for every issue one by one with where it was fixed or why it was
deferred. CHANGELOG.md has the per-release history for the 1.x
line plus the v1.7 candidate section (pre-1.0 releases are in
CHANGELOG-ARCHIVE.md), and
ROADMAP.md names what is committed for the next releases and
which directions are still candidate at the v3.0 horizon.
Project layout
src/
cli.rs command dispatch and output rendering
storage.rs Qdrant: single collection, hybrid search, history, stats, migrate, chunking
embedder.rs ONNX embedding (model-aware pooling, prefixes, 512-token cap)
reranker.rs cross-encoder reranking
knowledge.rs knowledge-graph facts + cardinality + supersession
duel.rs duel rule: resolve contradicting facts (flip / contested / quarantine)
doubt.rs doubt window + background active re-test of entrenched facts
activity.rs recent-query buffer, corpus mean (centering), origin-context store
confidence.rs per-fact confidence score (dependants / confirmations / signals)
outcome.rs typed external signals (test_passed, code_compiled, ...) into weight
procedure.rs procedural memory: learn / recall / outcome
ingest.rs auto-extract & ingest candidates
relevance.rs relevance gate (length, blacklists, decision markers, token novelty)
retrieval_policy.rs search-before-answer classifier
provenance.rs cited external snippets with mandatory source
extractor.rs optional local LLM extraction (off by default)
consolidate.rs merge duplicates, report cold entries
md_reconcile.rs md import as reconcile with "md wins"
audit.rs append-only audit log for memory/fact/procedure/skill
writes, updates, deletes and quarantine transitions (not
pinned blocks, kv, vault, or sessions yet)
http_api.rs loopback HTTP surface for multi-agent access
viewer.rs ephemeral local HTTP viewer (axum, static frontend baked in)
pulse.rs live graph pulses for the viewer
session.rs per-agent session files
secrets.rs secret-scrub on the write path
vault.rs encrypted secret vault (terminal only)
mcp.rs MCP server over stdio (hand-rolled JSON-RPC; warm in-process models)
config.rs configuration + install-mode profiles
integrity.rs pinned SHA-256 hashes for downloads
util.rs atomic writes, verified downloads
(plus migrate, install-mode, access/decay, and bench harnesses)
tests/
cli_integration.rs black-box tests against a real Qdrant (CLI + MCP round-trip)
http_integration.rs the multi-agent HTTP surface end to endLicense
Apache-2.0. See LICENSE.
Available Tools
44 toolsmind_addC
Add a memory entry
Inputs: content (required), library (required), source.
mind_blockA
Pinned core-memory blocks (persona / user / current-project): a few small, named notes that are ALWAYS injected at the top of the session context, not ranked retrieval. Use for stable, always-relevant facts the agent must not have to search for. action=set overwrites, get/list read, remove deletes. Content is capped (4KB/block, 32 blocks); this is core memory, not a second store: put searchable knowledge in mind_add instead.
Inputs: action (required), name, content.
mind_browseA
Browse/list memories by metadata WITHOUT a search query: inventory, not ranking. Newest first. Use to answer 'what did agent X write recently', 'everything from this source', 'all memories since a date'. Same filters as mind_search.
Inputs: limit, author, source, library, +4 more.
mind_consolidateA
Preview what mgimind consolidate would do: count of exact duplicates, near-duplicates, and cold (old + unused) entries. Always dry-run on the MCP surface; destructive consolidation stays on the CLI where the user types --apply explicitly. Use this when the user asks 'how much duplicate memory do I have?' or before suggesting they run the CLI command.
Inputs: library.
mind_contextB
Generate compact context briefing for session start
Inputs: no named parameters.
mind_createA
DEPRECATED: use mind_library(action="create"). Removed in v2.0. (Create a new library)
Inputs: name (required).
mind_deleteA
DEPRECATED: use mind_library(action="delete"). Removed in v2.0. (Delete a specific memory by ID)
Inputs: id (required), library (required).
mind_doctorC
Check system health
Inputs: fix.
mind_exportB
Export all data to JSON or Markdown files
Inputs: format, output.
mind_factA
Knowledge-graph facts (subject -> predicate -> object). Single tool with action: add (insert a new fact), query (list facts about a subject), invalidate (soft-delete a fact by id when a single-valued fact has been superseded). Replaces mind_fact_add / _query / _invalidate.
Inputs: action (required), id, as_of, object, +3 more.
mind_fact_addA
DEPRECATED: use mind_fact(action="add"). Removed in v2.0. (Add a knowledge graph fact)
Inputs: object (required), subject (required), predicate (required).
mind_fact_invalidateA
DEPRECATED: use mind_fact(action="invalidate"). Removed in v2.0. (Soft-delete a fact by ID (for superseding a changed single-valued fact))
Inputs: id (required).
mind_fact_queryA
DEPRECATED: use mind_fact(action="query"). Removed in v2.0. (Query facts about a subject)
Inputs: subject (required).
mind_historyC
Show recent additions chronologically
Inputs: limit.
mind_importC
Import markdown files from a directory (Obsidian, etc.)
Inputs: path (required), source, library.
mind_ingestA
Auto-ingest memory. PRIMARY: pass a candidates array of already-extracted items you judged worth keeping. BACKSTOP: omit candidates and pass raw text for marker-based heuristic extraction. Each candidate is secret-scrubbed and near-dup-checked before writing.
Inputs: raw, library, candidates.
mind_learnA
Record a procedural-memory lesson (error -> fix). Stored unverified by default (a manual lesson has no truth signal); surfaced with low weight until confirmed. Pass verified=true ONLY with a deterministic signal (test green / exit 0).
Inputs: fix (required), error (required), context, verified, +1 more.
mind_libraryA
Library namespaces. Single tool with action: create (new library by name), list (all libraries with counts), delete (remove a specific memory by id within a library: destructive). Replaces mind_create / mind_list / mind_delete.
Inputs: action (required), id, name, library.
mind_listA
DEPRECATED: use mind_library(action="list"). Removed in v2.0. (List all libraries)
Inputs: no named parameters.
mind_outcomeA
v1.5: Record a typed external-signal outcome on any memory (not only procedures). Use this when a test passed/failed, code compiled, a user explicitly confirmed/denied a fact, or a citing memory referenced this one. Idempotent on (memory_id, signal_type, source): re-posting the same triple updates the existing entry rather than appending a duplicate. Signals contribute to the fact's external_signal_score, which feeds the duel rule and the §3 Mechanism 2 doubt-window guardrail. When memory_id is a PROCEDURE and signal_type is test_passed or code_compiled, this also bumps the procedure's success/fail counters: so a green test after a mind_learn fix marks that playbook verified without a separate mind_procedure_outcome call. Pass the procedure id returned by mind_learn.
Inputs: memory_id (required), signal_type (required), source, success.
mind_predicateA
v1.4: register and inspect predicate cardinality (single | temporal-single | multi). Cardinality controls how mind_fact(action="add") detects conflicts: Multi predicates never conflict; Single/TemporalSingle flag a conflict_pending event when a second distinct object is asserted. Default for unregistered predicates is Multi.
Inputs: action (required), predicate, cardinality.
mind_procedure_outcomeA
Record whether a recalled procedure worked when reused. worked=false raises its fail count and demotes it, so the store self-corrects instead of ossifying on a bad fix.
Inputs: id (required), worked (required).
mind_provenance_addA
Persist an externally-sourced snippet (code, doc, RFC quote, commit message, etc.) into mgi-mind with a mandatory provenance citation. The agent supplies the snippet AS PLAIN UTF-8: no HTML, no markup. Call this ONLY when the snippet was just produced by a code-search or doc-search MCP in the same session; do NOT fill provenance fields from memory.
Inputs: snippet (required), origin_url (required), search_tool_used (required), file, +5 more.
mind_quarantineA
Inspect, promote, or expire entries that the relevance gate filtered into the quarantine layer. Single tool with action: list (newest first, optional library filter), show (full content + gate reason by id), promote (the gate was too strict: move to ordinary memory by id), expire (the gate was right: delete by id; only ever touches quarantined points, never live memory, and stays recoverable from the audit log). Replaces mind_quarantine_list / _show / _promote.
Inputs: action (required), id, limit, library.
mind_quarantine_listA
DEPRECATED: use mind_quarantine(action="list"). Removed in v2.0. (List entries the v0.11 relevance gate filtered into the quarantine layer. These are not surfaced by mind_search by design: use this tool when you suspect a fact was filtered (e.g., the user keeps repeating something the gate would reject as low-signal). Newest first.)
Inputs: limit, library.
mind_quarantine_promoteA
DEPRECATED: use mind_quarantine(action="promote"). Removed in v2.0. (Explicitly promote a quarantined entry to ordinary memory by id. The automatic promotion path is re-asserting the same content via mind_ingest; use this when you know the entry should be live without re-ingesting.)
Inputs: id (required).
mind_quarantine_showA
DEPRECATED: use mind_quarantine(action="show"). Removed in v2.0. (Show a single quarantined entry with its full content and the gate reason. Returns 'not in quarantine' for regular memory ids: the surface is honest about what it can see.)
Inputs: id (required).
mind_recallA
Recall error->fix playbooks for an error and/or a task context. Ranking blends relevance with trust: a verified or proven fix gets a boost, a repeatedly-failing one is demoted, but a strongly-matching unverified fix still surfaces.
Inputs: error, limit, context.
mind_recall_allA
Unified recall across all memory types at once (facts + memories + procedures) for one query. Current facts first, then semantic memories, then matching error->fix procedures. One call instead of three separate searches.
Inputs: query (required), limit.
mind_restoreA
Restore an ARCHIVED (soft-forgotten) memory by id, returning it to search. Archiving (consolidate --archive-cold) reversibly hides cold memories instead of deleting them; this is the undo.
Inputs: id (required).
mind_searchC
Semantic search across memories, with optional metadata filters (author, source, date window, multiple libraries).
Inputs: query (required), tier, limit, author, +7 more.
mind_sessionA
Manage the agent's session record across runs. Single tool with action: start (open a new session for an agent), last (read the previous session's summary), end (close the active session with a hand-written summary). Replaces mind_session_start / _last / _end.
Inputs: action (required), agent, summary.
mind_session_endA
DEPRECATED: use mind_session(action="end"). Removed in v2.0. (End the active session for an agent)
Inputs: summary (required), agent.
mind_session_lastA
DEPRECATED: use mind_session(action="last"). Removed in v2.0. (Get last session summary)
Inputs: agent.
mind_session_startA
DEPRECATED: use mind_session(action="start"). Removed in v2.0. (Start a new session)
Inputs: agent.
mind_should_searchA
Decide whether to search memory BEFORE answering a user query. Returns priority (must-search / should-search / answer-directly), the reason, and which libraries to search first. Call this on a turn when unsure; it implements the search-before-answer trigger policy (named project, meta-cue like 'did I tell you', negation to verify, cross-session reference). Advisory: it cannot force a search.
Inputs: query (required).
mind_skillA
Skills: the house way of doing a kind of work, matched against the task you are ABOUT TO START (mind_recall is the other half: it answers an error that already happened). action=match takes a task description and returns the playbooks that apply, ranked by relevance and by how they have actually worked out. Call it before starting non-trivial work, the way you would check for a house rule. action=set writes one (name is the identity, so writing the same name edits it and keeps its history), list/show read, remove deletes, outcome records whether applying it worked (verify=true only for a deterministic signal, never a hunch).
Inputs: action (required), body, name, task, +4 more.
mind_statsB
Show memory statistics
Inputs: no named parameters.
mind_vaultA
Vault is terminal-only by design. This tool explains how the user runs the equivalent mgimind vault command: secret values never cross the MCP channel. Single tool with action: store (instructions for storing a secret), get (instructions for retrieving), list (instructions for listing keys). Replaces mind_vault_store / _get / _list.
Inputs: action (required), key.
mind_vault_getA
DEPRECATED: use mind_vault(action="get"). Removed in v2.0. (Explain how to retrieve a secret (never returns plaintext over MCP))
Inputs: key (required).
mind_vault_listA
DEPRECATED: use mind_vault(action="list"). Removed in v2.0. (Explain how to list stored secret keys (terminal-only; needs the master password))
Inputs: no named parameters.
mind_vault_storeB
DEPRECATED: use mind_vault(action="store"). Removed in v2.0. (Explain how to store a secret (never accepts the secret over MCP))
Inputs: key (required).
mind_visualizeA
Open the 3D memory visualization in the user's browser: the brain as glowing cores (memories, facts, regions) wired by neurons, with live pulses. Call this when the user asks to SEE or SHOW their memory / 'the brain' / how memory looks. Spawns a local viewer and returns the URL.
Inputs: no named parameters.
mind_webB
Read a webpage as Markdown, optionally save to library
Inputs: url (required), save.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 44 tools
There are genuine clusters of near-synonymous tools: mind_search/mind_browse/mind_recall/mind_recall_all, mind_add/mind_ingest, and mind_outcome vs mind_procedure_outcome (the former explicitly subsumes the latter). Worse, ~15 deprecated aliases (mind_fact_add, mind_quarantine_list, mind_vault_get, mind_session_start, etc.) directly duplicate the newer action-based tools, so an agent can easily pick the wrong one. Descriptions are unusually careful, which keeps this from scoring lower, but the overlap is real.
Nearly everything is snake_case under a shared mind_ prefix and follows a predictable verb_noun style (mind_search, mind_add, mind_learn). The main deviation is the new action-based noun-only tools (mind_fact, mind_library, mind_vault, mind_session, mind_quarantine) plus stateless names like mind_doctor and mind_context. Readable, but the mixed verb-style/noun-with-action convention is a minor inconsistency.
44 tools is far beyond the reasonable band for this domain, and the count is inflated by ~15 deprecated tools that still appear in the surface alongside their replacements. Even the ~29 active tools is heavy for what is essentially a memory store. Deprecation flags help, but shipping both generations at once bloats the set.
The lifecycle is unusually thorough: add/ingest, semantic search, browse, cross-type recall, knowledge-graph facts, procedures, skills, pinned blocks, sessions, vault, quarantine, provenance, outcome signals, export/import, consolidate, restore, stats and health checks. The only minor gap is that there is no clear in-place edit/update path for an ordinary memory (append + invalidate/delete are the only mutations).
Maintenance
Related MCP Connectors
Persistent memory for AI agents. Semantic search, memory graph, W3C DID identity.
Persistent memory and knowledge graphs for AI agents. Hybrid search, context checkpoints, and more.
Persistent memory for AI agents. EU-hosted, privacy-first, hybrid recall, contradiction detection.
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal-first memory for Claude & AI agents with hybrid search, Graph-RAG, and time-travel, runs entirely on your machine.43 npm1Apache 2.0
- AlicenseAqualityCmaintenanceLocal-first memory for AI agents. On-device hybrid retrieval over a single SQLite file.164Apache 2.0
- AlicenseAqualityCmaintenanceHermetic memory for AI agents — one Rust binary, one SQLite file, zero network. Recall returns evidence with provenance or abstains: no code path for making things up.229AGPL 3.0
- AlicenseNot gradedqualityBmaintenanceLocal memory for AI agents in one SQLite file on your own machine. Facts carry a validity window and a confidence score, so an outdated one is superseded and downweighted rather than deleted, and retrieval fuses BM25, vector similarity and a knowledge graph.4Business Source 1.1