Recall by Polign
OfficialEnables LangGraph agents to resume from their own records by persisting and retrieving agent state through Recall.
Allows using MongoDB as a storage backend for memories, supporting persistent and shared memory across processes.
Supports OpenAI models for extraction and embedding, including text-embedding-3-small for semantic search over memories.
Allows using PostgreSQL with pgvector as a storage backend for memories, supporting persistent and shared memory across processes.
Polign Recall
Memory for agents whose facts change. When a user corrects something, Recall replaces the old fact, tells the agent what it replaced, and keeps the old value in a history you can read back. Nothing is deleted, and no model decides on its own what to forget.

The demo is a real run: one user over nine months, with three homes, three employers, and three work emails, then six questions about her now. Opus 5.5 extracted, answered, and judged for all three systems, three runs each. Right answers: Recall 18/18, mem0 18/18, Zep 12/18. Tokens to save one message: Recall 3.0k, mem0 12.7k, Zep 14.7k.
Install
pip install polign-recall # Python client; brings the server with it
go get github.com/Polign/recall # Go
recall mcp -write # MCP over stdio: remember(text), recall(question), forget(text)The Quickstart runs without a model or an API key.
Related MCP server: widemem-ai
What a correction looks like
Every change is kept. Three commands read that record:
$ recall history "which editor do I use"
user preferred editor
believed now: user preferred editor: zed
2026-09-01 10:00 stated, user_stated
+ user preferred editor: vim
2026-09-20 10:00 replaced, user_stated
- user preferred editor: vim
+ user preferred editor: emacs
2026-10-05 10:00 replaced, user_stated
- user preferred editor: emacs
+ user preferred editor: zed
$ recall ask -as-of 2026-09-25 "which editor do I use"
Believed as of 2026-09-25 00:00:
user preferred editor: emacs (since 2026-09-20)
replaced: vim (since 2026-09-01)
$ recall diff -from 2026-09-15 -to 2026-10-31
Changed between 2026-09-15 00:00 and 2026-10-31 00:00:
- user home city: Lisbon
+ user home city: Porto
- user preferred editor: vim
+ user preferred editor: zedWhy Recall
Corrections are records. A new value replaces the old one by a rule you can read, and the answer arrives with what it replaced.
Ask about any moment.
as_of,history, anddiffanswer what the agent believed then, and when that changed.Every answer has a source.
recall explainshows the message a fact came from, the rule that decided it, and its history.Shared and resumable. Agents in different processes read and correct the same memory, and a crashed agent resumes from its records.
Your storage. polign_db, PostgreSQL with pgvector, MongoDB, or Qdrant. Apache 2.0.
Benchmark
LongMemEval user-facts subset (267 questions about a user's own facts, preferences, updates, and dates), Recall 0.19.0, Sonnet 5.5 as reader and judge, upstream prompts:
What the reader is given | Score |
Nothing | 6.0 |
The full chat history | 88.0 |
BM25 over sessions, top 10 | 89.9 |
Recall, built-in word search | 88.8 |
Recall with a model embedder (OpenAI text-embedding-3-small, 512 dims) | 92.9 |
Only the sessions that hold the answer | 96.6 |
With its built-in word search, Recall is about even with BM25 overall and behind it on preference questions (70.0 against 83.3). A model embedder puts it ahead, and it is the default since 0.20.0 when the extractor is an OpenAI model. Recall hands the reader about 36k tokens per question, against about 168k for the full history.
Choose an integration
Integration | Get started |
Python | Follow the quickstart below, then see the client guide. |
Go | Run |
MCP | Connect an agent to tools for remembering, recalling, and forgetting facts. |
LangGraph |
|
LiveKit |
|
The Claude Code plugin is a ready-made MCP integration for memory across coding sessions.
Quickstart
You'll need Python 3.10+. Install the client:
pip install polign-recallpip also brings the polign_db package, which holds the polign and
polign-server binaries, so there is nothing else to download or start. This
example needs no model or embedding API key.
One process saves an editor preference and then changes it:
python - <<'PY'
from polign_recall import Client
with Client(local_dir="./recall-data") as memory:
memory.remember("user", "prefers_editor", "vim")
memory.remember("user", "prefers_editor", "neovim")
PYRun a second process in the same terminal. It reads the current preference, the full history, and what was believed before the correction:
python - <<'PY'
from polign_recall import Client
with Client(local_dir="./recall-data") as memory:
print(memory.recall("user", "prefers_editor")[0].value) # neovim
events = memory.history("user", "prefers_editor")
print([event.value for event in events]) # ['vim', 'neovim'] in a fresh directory
# Ask what was believed at the moment of the first statement.
before = memory.recall("user", "prefers_editor", as_of=events[0].observed_at)
print(before[0].value) # vim
PYThe correction did not erase vim. It is still there to read, which is how you
answer "what did the agent believe yesterday, and when did that change?"
The first client to open ./recall-data starts a local polign-server for it
in the background, and later clients share it. The memories stay in that
directory after your program exits. Managed local databases work on Linux and
macOS.
To share memory between machines, run polign-server yourself (requires
Polign v0.8.0 or later), leave
local_dir out, and set POLIGN_URL, POLIGN_COLLECTION, and
POLIGN_API_KEY when authentication is required.
For examples covering forgetting as well, see the Python session example or Go session example.
How memory works
A memory has a subject, a predicate, and a typed value:
Subject | Predicate | Value |
|
|
|
|
|
|
|
|
|
Predicates live in a registry that declares each one's value type, whether it
holds one value or several, and which predicates it contradicts (dislikes
excludes likes, gave_away excludes owns). Recall includes
starter registries for coding, personal
assistant, support, sales, and voice agents. Add your own predicates
(the registry), and the extractor files
statements under them; you can
change the registry later without
changing what the agent remembered before. A value can be text, a number, a boolean, an enum,
a date, or a reference to another subject.
For a single-valued predicate such as prefers_editor, a new assertion replaces
the current value. A multi-valued predicate such as uses_technology can hold
both Python and Go. Corrections preserve earlier statements, so you can read
current values, inspect their history, or query what was known at an earlier time.
Forgetting records a withdrawal and removes the affected fact from current answers. It does not permanently delete the record.
An agent can also propose facts from text.
Recall validates those proposals against the registry before writing them. A
statement that fits no predicate is kept as a note
instead of being dropped. Once you add a predicate for that kind of fact,
Promote files each note under it and keeps the note in history.
Without a registry
You don't have to define predicates at all. With an
open vocabulary, a write may name any
predicate and its first use defines it, starting from the coding and personal
starters. recall explain "<question>" shows, for each answer, the text it
came from, the predicate it was filed under, the rules that decide it, and its
history.
With a model configured, the MCP server goes one step further and takes plain text, with no predicates in any tool or answer:
recall setup -extract-model anthropic:claude-haiku-4-5-20251001remember("I switched from helix to zed last week")
recall("which editor do I use?") -> "user prefers editor: zed" (before: helix)
forget("my editor")The model decides how each statement is filed: which predicate, and whether a
new value replaces the old one or adds to it. Once filed, replacement follows
the predicate's rule as before, every filing is recorded, and a wrong one is
corrected with one event (Redefine, Merge, Split) that every answer
follows. The model is called on every remember and forget, and the text is
sent to its provider. See text-only tools.
The benchmark above uses these text tools with an open vocabulary seeded from the personal starter.
Typed tools
recall mcp -write -typed serves tools over a fixed vocabulary instead, such
as remember(subject, predicate, value). A session with the personal starter
registry:
remember(user, likes, mangoes)
remember(user, dislikes, mangoes)
-> superseded: [likes: mangoes] # the registry says dislikes excludes likes
recall(user, dislikes)
-> mangoes replaced: [likes: mangoes] # the correction arrives with the answer
remember(user, goal, "run a marathon")
remember(user, did, "run a marathon")
recall(user, goal)
-> run a marathon elsewhere: [did: run a marathon] # no rule joins goal and did,
# so the read shows both
remember(user, did, "run a marathon",
replaces=[goal: "run a marathon", goal: "learn piano"])
-> replaced: [goal: run a marathon]
-> unreplaced: [goal: learn piano] # never believed, so reported, not droppedNo model reconciles memory on its own. Recall applies the rules the registry declares, shows the candidates that may conflict, and lets your agent confirm the rest, so every correction can be read back to the rule or the statement that made it.
Reading the record
Each step of a history is the log folded just before and just after that
statement, so it agrees with a read at that instant. Agents get the same
record through the history and diff MCP tools (timeline and diff with
-typed), recall serve answers them over HTTP at /v1/history,
/v1/timeline and /v1/diff, and the Python client has history_text,
timeline and diff.
Resuming an agent
Resume gives an agent back the context it should start from, built from what
it wrote down while it worked. The new process resumes from records, not from a
process or container snapshot:
Working state: its goal, plan, progress, focus, and open questions.
Pointers to where its work lives, such as a git branch or an object key.
Turns, verbatim, and large tool outputs stored by reference.
The next process gets those records, plus memories that match its focus, sized to a token budget and rendered as one briefing for the model. A lease keeps one process per agent, so a second copy cannot write over the first. Leases need Polign v0.8.0 or later.
agent, err := client.Resume(ctx, recall.ResumeRequest{AgentID: "coder-1", TokenBudget: 8000})
if err != nil {
return err
}
defer agent.Release(context.Background())
briefing := agent.Resumed().Briefing // hand this to the modelResume and actions are a beta surface: the calls around the records may still change in a minor release, with the change and what to do about it in the changelog. The records themselves are stable. See STABILITY.md.
The resume example crashes an agent partway through a task
and continues it in a new process. See Resuming an agent
for the full API, and the Python client guide for resume
in Python.
Serving many agents
recall mcp is one agent, one process, one store. recall serve is the same
memory for many agents at once, over HTTP, each inside the namespace its key
names. The server holds the store's credentials; agents hold Recall keys.
recall -url http://polign:23000 serve -bootstrap-key-file admin.key # admin.key holds one rcl_... line
recall -url http://polign:23000 key create -namespace acme:agent-7 -expires 168hEach namespace gets its own collection, so nothing a caller sends can reach
another namespace's records. Keys are stored hashed, expire if asked, renew at
POST /v1/keys/renew, and are revoked by a tombstone that nothing can
overwrite. POST /mcp is MCP over streamable HTTP; POST /v1/remember,
/v1/recall, /v1/forget and /v1/history take a tool's arguments as the
body. Any MCP client that speaks stdio reaches the server through
recall connect, with RECALL_URL and RECALL_API_KEY set.
On Kubernetes a pod needs no key at all. With recall serve -kubernetes, it
posts its projected service account token (audience recall) and gets a
short-lived key for <tenant>:<pod name>, fixed to that agent, which recall connect and the Python client obtain and renew by themselves from
RECALL_TOKEN_FILE. The Helm chart is charts/recall in
Polign/polign; the
agent-sandbox demo runs it on kind. The contract every
client is written against is docs/memory-api-v1.md.
Storage and search
Recall provides memory rules, validation, and history; the backend provides persistence and access to the data. Agents share memory by using the same backend, collection, and namespace, with compatible Recall versions and memory definitions. Search also requires compatible embedding methods.
Concurrent reads and writes follow the backend's consistency guarantees. Recall does not add transaction isolation or replication.
Backends
polign_db (default) | PostgreSQL + pgvector | MongoDB | Qdrant | |
Package | ||||
| default |
|
|
|
URL and key variables |
|
|
|
|
Server version | 0.8.0 or later | PostgreSQL 13 or later with pgvector 0.6.0 or later; 0.8.0 or later recommended | 6.0 or later, Atlas or self-hosted | 1.10 or later |
Remember, recall, forget, history, as-of | yes | yes | yes | yes |
Evidence links, audit export | yes | yes | yes | yes |
Keyword search | yes, BM25 | yes, PostgreSQL full-text search | yes, MongoDB text search | no, vector search only |
Cached reads | yes | yes | yes | no, every read refolds the history |
Agent leases ( | yes | yes | yes | no; Go |
Agent writes fenced on the server | yes | yes, in the write's transaction | yes on a replica set or Atlas, in the write's transaction; checked just before the write on a standalone server | no |
| yes | no, add | no, add | no, add |
To run Recall on a PostgreSQL database:
export DATABASE_URL=postgres://user:password@localhost:5432/mydb
recall -backend pgvector mcp -writeThe first write creates a recall schema with one table per collection and
two bookkeeping tables. The role needs CREATE on the database, and the
vector extension must be installed or creatable by that role.
Pitfalls on PostgreSQL:
A collection takes its vector size from the first write. Changing embedders needs a new collection.
Every write to a collection takes a row lock on that collection's revision, so writes to one collection are serialized. That is fine at conversation pace but slows a bulk import.
Keyword search uses the
englishtext search configuration unless the GoConfig.TextSearchConfigsays otherwise. It is fixed when a collection is created.On pgvector older than 0.8.0, a filtered vector search can return fewer hits than asked for, because the index stops scanning at
ef_searchcandidates before the filter applies.
To run Recall on MongoDB:
export MONGODB_URI=mongodb://user:password@localhost:27017/recall
recall -backend mongodb mcp -writeThe database is the connection string's path, recall when it has none. The
first write to a collection creates a MongoDB collection named rc_ and the
collection's name, and two bookkeeping collections, recall_collections and
recall_leases. The user needs readWrite on the database.
Pitfalls on MongoDB:
Vector search is exact: the similarity is computed in the server over the events a filter keeps. No Atlas Search index is needed and the answer is the true nearest events, but each search reads the whole filtered collection. Agent memory collections hold thousands of events, which is fast; a collection of millions is not what this backend is for.
Run a replica set (Atlas always is) for agents. On a standalone server there are no transactions, so a fenced agent write is checked just before it lands rather than with it, and listings are not read from one snapshot. A single-node replica set is enough.
A collection takes its vector size from the first write. Changing embedders needs a new collection.
Keyword search uses MongoDB's
englishtext index, fixed when a collection is created.
Pitfalls on Qdrant:
Use a collection only Recall writes to. A point without the
_recall_idpayload field makes reads fail.A collection takes its vector size from the first write. Changing embedders needs a new collection.
Unleased: trueis safe only when something else keeps one process per agent. Without a lease, a crashed process that comes back can overwrite its replacement.With the built-in lexical embedder, exact-word queries rank worse than on polign_db. A model embedder (
-embed-model) helps paraphrases, not keywords.
To add a backend, implement Put, List and Search
(contract), register it with
recall.RegisterBackend in init, pass backendtest, and import
it in cmd/recall/backends.go.
The Go library has no external module dependencies. The pgvector backend uses pgx and the MongoDB backend the official MongoDB driver, which a program pulls in only by importing that package. Its built-in lexical embedder supports word-overlap search; applications can supply a model-based embedder for semantic search. See the embedding guide.
Repository layout
Path | Contents |
Public Go API at | |
Memory implementation and unit tests | |
polign_db backend | |
PostgreSQL + pgvector backend | |
MongoDB backend | |
Qdrant backend | |
Conformance suite for backends | |
Python package and tests | |
Command-line tools, including | |
Runnable Go and Python examples, including a crash-and-resume demo | |
Guides and API reference | |
Shared audit fixtures |
See the development guide for the implementation map and test commands.
Documentation
What is stable and what is beta · Developer reference · Resuming an agent · Connecting through MCP · Caching memory reads · Exporting and replaying history
Support the project
If Recall kept your agent from acting on a stale fact, a star on this repository helps other people find it. Bugs, questions, and ideas go in issues.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent memory for AI agents, for code, research and everyday life. Stale facts retire.
- GoMindOAuthcom.gominddb
Persistent knowledge graph for AI agents. Remember, recall, and forget facts.
Persistent memory for AI agents. Search, store, and recall across sessions.
Private memory for AI agents: save and recall facts across Claude Code, Codex, Cursor and ChatGPT.
Related MCP Servers
- AlicenseAqualityCmaintenancePersistent semantic memory for AI agents. SQLite-backed, local-first, zero config. Semantic search via Ollama embeddings with keyword fallback. Tools: remember, recall, history, forget, stats.1737 npm1MIT
- AlicenseNot gradedqualityAmaintenanceOpen-source AI memory layer for LLM agents. Importance scoring, temporal decay, hierarchical memory (facts, summaries, themes), YMYL prioritization, and active retrieval with contradiction detection. Supports OpenAI, Anthropic, Ollama. Local-first with SQLite + FAISS.51 PyPI49Apache 2.0
- FlicenseNot gradedqualityAmaintenanceLocal 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.2-
- AlicenseNot gradedqualityCmaintenanceSelf-hosted long-term memory for AI agents on your own Postgres. Facts are dated, versioned and superseded rather than silently overwritten, every recall ships with an inspectable trace, and agents can correct wrong memories from inside the conversation.2Apache 2.0