Meaning
An in-crate HNSW index over your embeddings. Bring your own vectors, or let the engine call OpenAI, Gemini, or a local sentence-transformers server.
Memory infrastructure for AI agents
A memory engine in Rust that answers “what do I know about this?” — not “which vectors are nearest?”
Dana Whitfield leads Project Phoenix
the Billing Service rate limits at 100 requests per second
That second memory never mentions Phoenix. It surfaced on graph — one hop through a shared entity — with lexical at zero.
The missing layer
Models, orchestration, tools, evals — each has infrastructure built for it. Memory got a vector index and a shrug. So every team building agents writes the same layer by hand: a vector store, a keyword index, fusion logic, a graph for relationships, a scheduler for expiry and summarization, access control between agents, and a protocol shim to expose it all.
memrust is that layer as one binary. Not a database an agent queries — memory an agent has.
The ceiling nobody talks about
Agents ask for exact things constantly: error codes, ticket IDs, commit SHAs, customer names, function names. Embeddings can't separate INC-90312 from INC-90319 — near-identical strings make near-identical vectors.
The telling part: exact brute-force vector search scores the same 27%. This isn't an index-quality problem a faster ANN fixes. It's the ceiling of the embedding itself, and every pure vector store inherits it.
memrust runs BM25 and an entity graph over the same memories and fuses the rankings. Same embeddings, same corpus — different architecture.
hit@5 on 60 identifier lookups · 500 memories · identical all-MiniLM-L6-v2 embeddings for every engine · benches/agent_recall.py
Four signals, one call
Every hit comes back with its score broken out by signal. An agent can tell a strong semantic match from a lucky keyword hit — and so can you, when something surfaces that shouldn't have.
An in-crate HNSW index over your embeddings. Bring your own vectors, or let the engine call OpenAI, Gemini, or a local sentence-transformers server.
A BM25 inverted index for the identifiers, error codes and names that embeddings blur together.
Entities extracted at ingest, linked by co-occurrence. Finds what's connected to a thing, not just what resembles it. No external graph database.
Exponential decay as a first-class ranking term, because "what did we decide recently" is not a similarity question.
Measured, not claimed
What you'd otherwise assemble
The usual answer to agent memory is a vector DB, a keyword index, fusion code, a graph store, a scheduler for expiry and summarization, access control, and an MCP shim. That's the stack memrust replaces.
| Capability | memrust | Qdrant | Chroma | FAISS | pgvector | LanceDB |
|---|---|---|---|---|---|---|
| Vector search | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Keyword fused into one query | ✓ | setup | — | — | DIY | ✓ |
| Entity graph as a signal | ✓ | — | — | — | DIY | — |
| Per-signal score explanation | ✓ | — | — | — | — | — |
| Agent API + memory kinds | ✓ | — | — | — | — | — |
| TTLs & automatic consolidation | ✓ | — | — | — | cron | — |
| Multi-agent private/shared memory | ✓ | filters | filters | — | policies | filters |
| MCP server for agent runtimes | ✓ | — | — | — | — | — |
| One endpoint every agent shares | ✓ | — | — | — | — | — |
| Tenants as fully separate indexes | ✓ | collections | collections | — | schemas | tables |
| API keys scoped per tenant | ✓ | one key/JWT | — | — | ✓ | — |
| Prometheus metrics | ✓ | ✓ | — | — | exporter | — |
| Built-in dashboard | ✓ | ✓ | — | — | — | — |
✓ built in · anything else in that column = possible, you build it · — not available
20,000 vectors, 384 dims, identical HNSW settings, recall against exact ground truth. Query latency is second-best among the servers and recall ties the field. Ingest is slower on purpose: memrust fsyncs every write, where the others buffer. For a memory layer that's the right trade — an agent quietly losing what it was told is worse than writing a little slower.
| Engine | Ingest/s | Query p50 | recall@10 |
|---|---|---|---|
| FAISS in-process | 35,625 | 0.06 ms | 1.000 |
| LanceDB embedded | 99,238 | 8.60 ms | 1.000 |
| Chroma in-process | 5,907 | 0.49 ms | 1.000 |
| pgvector server | 5,017 | 0.46 ms | 1.000 |
| Qdrant server | 2,475 | 2.08 ms | 1.000 |
| memrust server | 988 | 0.64 ms | 1.000 |
Two minutes to first recall
# the engine — dashboard and HTTP API on :7700 cargo install memrust memrust serve # or the official image — multi-arch, 36 MB, non-root docker run -p 7700:7700 -v memrust-data:/data aianytime/memrust
# pip install memrust from memrust import MemrustClient memory = MemrustClient("http://127.0.0.1:7700", agent_id="planner") memory.remember("Deploy 47 failed with error E1234", kind="episodic") for hit in memory.recall("what went wrong with the deploy?"): print(hit["score"], hit["record"]["text"], hit["signals"])
// npm install memrust-client import { MemrustClient } from "memrust-client"; const memory = new MemrustClient("http://127.0.0.1:7700", { agentId: "planner" }); await memory.remember("the Billing Service rate limits at 100 rps"); const hits = await memory.recall("Project Phoenix", { strategy: "relational" });
// cargo add memrust use memrust::{MemoryEngine, RememberRequest, RecallRequest}; let mut memory = MemoryEngine::open("./data".as_ref())?; memory.remember(RememberRequest { text: "user prefers concise answers".into(), ..Default::default() })?; let hits = memory.recall(&RecallRequest { query: "what does the user prefer?".into(), ..Default::default() });
# give Claude Code persistent memory claude mcp add memory -- memrust mcp --data-dir ~/.memrust --agent-id planner # the agent gets three tools: # memory_remember · memory_recall · memory_forget # recall returns the per-signal breakdown, so the agent can # reason about why something surfaced.
From here, the developer documentation covers the full HTTP API, MCP setup for Claude Code and Cursor, LangGraph and CrewAI recipes, embeddings, the memory lifecycle and operations.
Run it for real
The demo path needs no keys and no config. The production path is the same binary with flags — tenants that can't see each other, keys scoped to them, and metrics your existing Prometheus already knows how to scrape.
A namespace is a separate engine — its own indexes, WAL, checkpoint, embedding dimension and directory. One tenant's ingest can't slow another's recall, and dropping one deletes a directory instead of scanning a shared index.
Keys can be pinned to specific namespaces, arrive as a bearer token or header, and compare in constant time. Admin routes need an unscoped key. Leave keys off and it stays open — but says so, loudly, on a non-loopback address.
Request counts and latency histograms by matched route, plus per-namespace gauges for memories, index size, entities and WAL depth — read live at scrape time, so they can't drift. One JSON line per request for your log shipper.
Official multi-arch image for amd64 and arm64, 36 MB, non-root, /data as a volume. Liveness is an unauthenticated /healthz, so probes never need to hold a credential.
# one admin key, one tenant key pinned to its own namespaces docker run -p 7700:7700 -v memrust-data:/data aianytime/memrust:0.6.1 \ serve --addr 0.0.0.0:7700 --data-dir /data --log-format json \ --api-key "$ADMIN_KEY" \ --api-key "$ACME_KEY:acme,acme-staging" # every request picks its tenant; the key decides if that's allowed curl localhost:7700/v1/recall \ -H "Authorization: Bearer $ACME_KEY" \ -H "X-Memrust-Namespace: acme" \ -d '{"query":"what did we decide about pricing?"}'
Upgrading from a single-tenant deployment is safe: a data directory written before namespaces existed is adopted as default in place, and new namespaces are created alongside it.
Hosted · private beta
Self-hosting stays free and uncapped forever — that is the whole point of an Apache-2.0 engine. memrust Cloud is for teams who would rather not operate a stateful service: sign up, create a project, get a key, and point every agent at one URL.
Every project is its own engine — own indexes, own WAL, own directory. The namespace is pinned by your key, so a request cannot reach another tenant's memory even if it asks to.
Keys are shown once and stored as hashes. Revoking one stops it on the next request. Every account, project and key change lands in an audit log.
One HTTPS endpoint instead of a binary on every machine — which is what lets claude.ai and hosted agents share the same memory as your laptop.
Requests, recalls and stored memories per project per month, with live index stats and a recall playground that shows the per-signal breakdown.
Free tier: 3 projects · 25,000 requests/month · 10,000 memories. Cloud from $49/month. Self-hosted: unlimited, because you run it.
Where this is going
memrust is Apache-2.0 and will stay that way — an engine you can read, fork and run on your own hardware. Isolation and authentication are in the open engine, because you need them to self-host. What you pay for is the part a single node can't solve: fleets of agents sharing memory across machines, with quotas, replication and operations someone else runs. Open core, hosted control plane.
Hybrid retrieval, memory lifecycle, multi-agent visibility, namespaces, scoped API keys, metrics, MCP, dashboard, SDKs, Docker image.
Hosted memory: projects, scoped keys, metering, audit, and MCP over HTTP so every agent shares one endpoint.
Backup and restore to object storage, read replicas over WAL streaming, LLM entity extraction, hierarchical summarization.
Straight answers
That stack is two systems: the memory semantics live in Python, the storage lives somewhere else, they talk over a network, and an LLM sits in the loop deciding what to keep. memrust implements the memory semantics inside the storage engine.
That's why filters apply during index traversal instead of after it, why it runs with no API keys at all, and why durability is something you can reason about rather than inherit from whatever store you configured underneath.
There's one inside it — HNSW, scalar quantization, a write-ahead log, checkpoint recovery. But that index is one of four retrieval signals, and it isn't the API.
A vector database stores an embedding with a metadata blob attached. memrust stores a memory: typed as episodic, semantic, working or procedural; owned by an agent; able to expire; linked to extracted entities; and carrying provenance when it was distilled from older memories.
No. The default embedder and summarizer run offline with zero keys — enough to try every feature on this page, including the notebooks.
For production quality, point it at OpenAI, Gemini, or a local sentence-transformers server through Ollama, TEI, LM Studio or vLLM. Or skip the embedder entirely and pass your own vectors.
You can — and if you do, you'll rebuild what memrust already is: two indexes, rank fusion, a graph for relationships, jobs for expiry and consolidation, per-agent access rules, and a protocol shim so agents can reach it.
The parts that resist bolting on are pre-filtering inside index traversal and per-signal score explanation. Both have to live in the engine; neither can be added by a layer sitting above it.
Yes, and it's the common path. Pass embedding on write and query_embedding on recall, and memrust never calls a model — BGE, E5, OpenAI, Voyage, whatever you already run.
The first vector fixes a collection's dimension. Mixing models afterwards is rejected with a clear error rather than silently returning nonsense similarities.
It's young and single-node, so be deliberate. What's there: API keys scoped to namespaces, isolated stores with their own indexes and directories, Prometheus metrics and JSON request logs, an official multi-arch image, and durability tested under kill -9 with concurrent writers and checkpoints racing — 1,000 acknowledged writes, 1,000 recovered — plus recall@10 of 1.000 against exact ground truth and a suite that runs on every commit.
The hosted control plane is in private beta: projects, scoped keys, metering, audit and MCP over HTTP all work and are covered by an end-to-end suite that specifically tries to break cross-tenant isolation. Billing and email are not wired yet, which is exactly why it is beta and not GA.
What it isn't: distributed, multi-writer, or scarred by years in production. Run it where a single node fits, which covers most agent workloads today.
Three ways. As an MCP server, which is how Claude Code and Claude Desktop pick it up — the agent gets remember, recall and forget as native tools. Over HTTP with the Python or TypeScript SDK, for LangGraph, CrewAI, the OpenAI SDK or anything else. Or as a Rust library, embedded with no server at all.
Apache-2.0, permanently. The engine is meant to be read, forked and self-hosted, and nothing on this page is behind a paywall.
The commercial layer is hosted memory — projects, scoped keys, metering, audit and one MCP endpoint every agent shares — for teams who would rather not operate a stateful service. Free tier is 3 projects and 25,000 requests a month; Cloud starts at $49. Self-hosting stays unlimited, because you are the one running it.
Yes, and that is the point. Claude Code, Claude Desktop, claude.ai, Cursor, Windsurf and Codex all speak MCP, so they take the same URL and key. LangGraph, CrewAI and anything else take the HTTP API or an SDK. They read and write one project, so a fact Cursor learns is one your LangGraph agent can recall a week later.
Where agents should not see each other, they don't: a memory owned by an agent is private unless it is published, and that rule is applied inside the index traversal rather than as a filter over results — so it cannot leak through ranking either.
Because this is a storage engine. Cache-friendly layouts, SIMD-friendly distance kernels, and predictable latency with no garbage collector pausing in the middle of a recall.
It's also why the whole thing ships as one static binary with no runtime to install — the same reason Qdrant is written in Rust.
Get in touch
Whether you're wiring memrust into an agent today, hitting an edge we haven't, or looking at the memory layer as a market — the fastest way to reach us is directly.
A live walkthrough: hybrid recall on your own data, then the same memory wired into Claude Code and an agent in front of you.
Bugs & questions GitHub IssuesFastest for anything reproducible. Benchmarks and tests are in the repo.
Using it in production EmailTell us the workload. Scale, latency budget and agent count shape what we build next.
Investors & partners EmailHappy to walk through the architecture, the benchmarks and where the hosted layer goes.