Recall by Polign
OfficialThis server provides a memory API for agents: store facts, query current or past beliefs, forget, and inspect change history.
remember: Save a preference, fact, decision, or correction from text or a conversation; newer statements replace older ones while preserving history.recall: Ask what is currently believed, get a profile, view changes since a time, or query beliefs as of an earlier instant.forget: Stop believing something described in words; returns what was withdrawn without deleting history.history: Trace every statement about something, oldest first, with what was believed before and after each change.diff: Compare what was believed at two instants and list what began or stopped being believed in between.
Enables 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
Recall is a memory for agents. The memory that avoids hallucinations, proposes facts and does not do guesswork. The recall functionality builds the current belief of the system based on how a user corrects their facts, backtracks or changes their understandings. Recall replaces the old fact and informs the agent what it replaced. It keeps the old value in a history for auditing and replaying.

The demo is a real run with one user over nine months. User chaned three homes, three employers, and three work emails. The demo queries six questions about her with current understanding. It is using Opus 5.5 to extract facts, answer, and judge for all three systems. The answers are at 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, the recall binary, and the database it runs
brew install polign/tap/recall # the same for Homebrew
recall mcp -write # MCP over stdio: remember(text), recall(question), forget(text)Without a named database, recall keeps memory in a
local database in ~/.local/share/recall, started on first use and shared by
every agent on the machine. The Quickstart runs without a model
or an API key. see Backends to keep the memory in the currently integrated locations.
Today that local database is polign_db, so recall needs the polign-server
binary next to it. pip and Homebrew install both. go get and
go install github.com/Polign/recall/cmd/recall give you the library and the
binary but not the database: name one with -backend and -url, or install
polign_db (pip install polign-db or brew install polign/tap/polign). In
0.23.0 a recall mcp with nothing configured and no polign-server exits
before the MCP handshake; the next release serves the tools and reports the
missing database on the first memory call instead. A local database that needs
no second binary is being built.
Related MCP server: engram-mcp
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. Since 0.20.0 one follows the extraction model: OpenAI's text-embedding-3-small with an OpenAI extractor, Ollama's nomic-embed-text with an Ollama one, and the all-MiniLM model built into the binary with an Anthropic one. With word search, Recall handed the reader about 28k tokens per question, against about 44k for BM25 and 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 |
|
Vapi |
|
Pydantic AI |
|
The Claude Code plugin
is a ready-made MCP integration for memory across coding sessions, and the
OpenClaw plugin
(@polign/openclaw-recall on npm) gives OpenClaw agents the same memory.
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. A bare Client() does the same in
~/.local/share/recall, the memory every agent on the machine shares, the
Claude plugin included. Managed local databases work on Linux and macOS.
To share memory between machines, run polign-server yourself (requires
Polign v0.8.0 or later) or any
other backend, leave local_dir out, and name the database with
Client(backend=, backend_url=, backend_key=) or with RECALL_BACKEND,
RECALL_BACKEND_URL and RECALL_BACKEND_KEY in the environment.
RECALL_COLLECTION names the collection. Client.database says which
database the binary resolved.
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 serve -backend polign -url http://polign:23000 -bootstrap-key-file admin.key # admin.key holds one rcl_... line
recall key create -backend polign -url http://polign:23000 -namespace acme:agent-7 -expires 168hWith no database named, recall serve runs on the local database like every
other command, and recall key create -namespace team:agent-1 against the
same default mints a key for it: a shared memory server for several agents on
one machine, with nothing configured. Its first log line says where memory
is, so a container that meant to name a database and did not is told at once.
Each 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/<tool>
(remember, recall, forget, history, explain, diff, timeline,
predicates) takes that 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
Three things say where memory lives, the same three for every backend and every command:
Flag | Variable | What it is |
|
|
|
|
| Where the database is, in the backend's own form: a directory, |
|
| The credential, when the backend takes one and the URL does not carry it: the API key of polign and qdrant, the password of pgvector and mongodb |
Each resolves in the same order: the flag, the variable, the setup recall setup saved, the default. The flags go before the command or after it. A
backend's other options are query keys on the URL, listed in the table below;
anything else in the query goes to the driver as it is
(postgres://host/db?schema=memory&sslmode=require).
Nothing else about the database has a variable. The names each backend had
before 0.23.0 (POLIGN_URL, POLIGN_API_KEY, DATABASE_URL, PGPASSWORD,
MONGODB_URI, MONGODB_PASSWORD, QDRANT_URL, QDRANT_API_KEY) keep
working as aliases, with one line on stderr naming the new one, and so does a
polign_db already answering at http://localhost:23000 when nothing names a
backend, which is where 0.22 looked. See STABILITY.md for
when they go away.
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
local (default) | polign_db | PostgreSQL + pgvector | MongoDB | Qdrant | |
Package | |||||
|
|
|
|
|
|
| a directory (default |
|
|
|
|
| not used; a key is generated in the directory | the polign_db API key | the password, when the URL has none | the password, when the URL has none | the Qdrant API key |
Options on the URL |
| none |
|
|
|
Server version | the | 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 | yes |
Evidence links, audit export | yes | yes | yes | yes | yes |
Keyword search | as polign_db | yes, BM25 | yes, PostgreSQL full-text search | yes, MongoDB text search | no, vector search only |
Cached reads | yes | yes | yes | yes | no, every read refolds the history |
Agent leases ( | yes | yes | yes | yes | no; Go |
Agent writes fenced on the server | yes | 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 | yes | yes | yes | yes |
To run Recall on a PostgreSQL database:
export RECALL_BACKEND=pgvector RECALL_BACKEND_URL=postgres://user:password@localhost:5432/mydb
recall 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?text_search=on the URL (Go:Config.TextSearchConfig) says 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 RECALL_BACKEND=mongodb RECALL_BACKEND_URL=mongodb://user:password@localhost:27017/recall
recall 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 core package, github.com/Polign/recall, imports nothing outside the
standard library. The pgvector backend uses pgx,
the MongoDB backend the
official MongoDB driver, and the
model package the Anthropic SDK and hugot
for the embedding model that runs inside the binary. A program pulls each in
only by importing that package.
Two embedders ship with Recall: lexical word search, which needs nothing, and
local:all-minilm-l6-v2, a model that runs in the binary with no key and no
service. -embed-model names an OpenAI, Ollama or Voyage model instead. See
the embedding guide.
Repository layout
Path | Contents |
Public Go API at | |
Memory implementation and unit tests | |
The default backend: a polign_db recall runs itself | |
polign_db backend | |
PostgreSQL + pgvector backend | |
MongoDB backend | |
Qdrant backend | |
Conformance suite for backends | |
Python package and tests | |
Extraction models and embedders, including the one built into the binary | |
Starter predicate registries | |
The | |
Runnable Go and Python examples, including a crash-and-resume demo | |
Container image and the agent-sandbox demo | |
Evaluation harnesses: LongMemEval, corrections, predicate matching | |
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
Available Tools
5 toolsdiffDiffARead-only
What was believed differently at one instant than at another: each thing that began or stopped being believed in between. Use it to say what changed over a period, such as since the last session or during an incident.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | the later RFC3339 instant; omit for now | |
| from | Yes | the earlier RFC3339 instant, e.g. 2026-09-01T00:00:00Z |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and openWorldHint=false, so safety is covered. The description earns its place by defining what the result actually contains (both things that began and things that stopped being believed), which matters because there is no output schema. It says nothing about ordering, volume, or handling of the open-ended 'to' default beyond what the schema notes.
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 sentences, no filler: the definition comes first, the usage scenario second. Every clause carries meaning and nothing repeats the name or title.
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 two-parameter read-only tool with full schema coverage and no output schema, the description supplies the one thing structured data cannot: what a 'diff' means in this belief model and what the result enumerates. Only the ordering/shape of the returned set is left implicit.
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% and both parameters already document the RFC3339 format and the 'omit for now' behavior for `to`. The description reinforces the notion of two instants but adds no syntax or edge-case detail beyond the schema, so the baseline of 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?
The description states a specific operation with a precise semantic definition: the set of things that began or stopped being believed between two instants. This distinguishes it in substance from remember/recall/forget, though it never names the closest sibling (history) so the agent must infer the boundary.
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 concrete when-to-use framing — 'to say what changed over a period, such as since the last session or during an incident' — which maps real scenarios onto the tool. It stops short of stating exclusions, e.g. when to prefer history over diff.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
forgetForgetA
Stop believing what a description names, such as "my editor" or "that I live in Lisbon". Returns what was withdrawn. Nothing is deleted: it stays in the history, and remembering it again brings it back.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | what to forget, described in words |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does meaningful work: it discloses that nothing is deleted, that the belief remains in history, that the operation is reversible via `remember`, and that it returns what was withdrawn. It omits what happens on a miss (forgetting something not held) and any auth/permission expectations.
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 short sentences, each doing distinct work: what it does, what it returns, and the reversibility guarantee. No redundancy and the core action is front-loaded.
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?
No output schema exists, and the description compensates by stating the return value and the non-destructive persistence semantics. For a one-parameter tool this is nearly complete; only edge-case behavior for a non-existent belief 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 single `text` parameter is already documented; the description adds real meaning by showing the expected form is a natural-language belief description rather than an ID or key, with two worked examples. That is more than the schema conveys.
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 verb phrase "stop believing what a description names" plus concrete examples ("my editor", "that I live in Lisbon") makes the operation identifiable, and the closing clause implicitly contrasts it with the sibling `remember` which restores the belief. It is clear but phrased metaphorically rather than as a plain verb+resource statement, which costs a point.
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: an agent can infer you call this when a stored belief should no longer be held, and the description notes that remembering it again reverses the effect. There is no explicit when-to-use/when-not-to-use guidance and no direct routing against siblings like `recall` or `history`.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
historyHistoryARead-only
How something remembered changed, in words: every statement about it, oldest first, each with what it began and ended believing, and what is believed now. Use it when the user asks what changed, when, or why something is believed, and to show a correction whole. Something since forgotten still has its history.
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes | what to trace, in words, such as "my editor" |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and openWorldHint annotations, the description discloses return behavior in useful detail: every statement is returned oldest first, each with its beginning and ending beliefs, plus the current belief. It also adds the non-obvious edge case that forgotten items still retain history.
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 short and front-loads the core behavior before usage guidance and the forgotten-item edge case. The first sentence is dense and slightly abstract, but no sentence is clearly wasted.
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 simple one-parameter read-only tool with no output schema, the description is complete: it explains the return ordering and content, gives usage conditions, and covers the forgotten-item case. An agent has enough information to call it correctly.
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?
There is only one required parameter and the schema already has full description coverage, including an example. The main description does not add syntax or format details beyond the schema, so the baseline of 3 is appropriate.
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 states a specific resource and scope: a chronological history of statements about something remembered, including past and current beliefs. It is clear enough to distinguish from a simple recall, though it does not explicitly name or contrast with the sibling tools.
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 clear usage cues: when the user asks what changed, when, or why something is believed, and when showing a correction whole. It also notes that forgotten items still have history. It does not explicitly say when to prefer a sibling like diff instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallRecallARead-only
Ask what is remembered, in words, before assuming anything about the user. Answers are what is believed now, as sentences. Each lists under before what it replaced and when, so a correction comes with the answer, and under elsewhere anything else believed about the same thing in other words, such as a later dislike beside a like; the newer statement usually holds. days_ago says how long ago it was stated. A time named in the question, such as "last week", is searched first. Each also gives under said the sentence it was drawn from, as the user said it. Pass as_of to ask what was believed at an earlier instant. Leave out question to get everything believed about the user, a profile to start a conversation with. Pass since to get only what changed after then, newest first: at the start of a session, since the last one, it says what is new.
| Name | Required | Description | Default |
|---|---|---|---|
| as_of | No | RFC3339 instant, e.g. 2026-09-01T00:00:00Z. Answers as of then rather than now. | |
| since | No | RFC3339 instant. Only what was stated after then, each with what it replaced. | |
| question | No | what you want to know; omit for the user's profile, or with since for everything that changed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint=true, openWorldHint=false), yet the description goes far beyond them: it discloses the returned fields (before, elsewhere, said, days_ago), the resolution heuristic that the newer statement usually holds, that a time named in the question is searched first, and that 'since' results come newest first. With no output schema, this disclosure is doing essential work.
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 opening sentence front-loads purpose and the key usage trigger, which is good, but the middle devolves into long run-on clauses ('Each lists under before what it replaced and when, so a correction comes with the answer, and under elsewhere anything else believed...') that are hard to parse. Some points are restated, e.g. 'since' is explained twice with slightly different framing.
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 zero-required-parameter read tool with no output schema, the description is substantially complete: it explains both intent variants and the shape of returned data. Gaps are the lack of sibling differentiation (history/diff) and no indication of result size, limits, or ordering for the default profile call.
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 all three parameters are already documented, but the description adds intent-level meaning: 'as_of' asks what was believed at an earlier instant, 'since' narrows to only what changed and returns newest first, and omitting 'question' yields the full profile. That is genuine value beyond the schema, though the RFC3339 format itself is left to the schema.
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 makes clear this is a retrieval operation over what the system believes about the user, returning those beliefs as sentences with provenance (before/elsewhere/said). The verb phrasing 'Ask what is remembered, in words' is idiosyncratic but the resource and output shape are unambiguous. It does not distinguish itself from siblings like history or diff, which likely overlap with the 'since' changed-since-last-time behavior.
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 contexts are explicit and actionable: call before assuming anything about the user, omit 'question' to get a profile to start a conversation, pass 'since' at the start of a session to see what is new, pass 'as_of' for a historical view. What's missing is any exclusion or named alternative — nothing says when to prefer history or diff over this tool, which matters given the overlap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rememberRememberA
Keep something worth remembering about the user or their work: a preference, a fact, a decision, or a correction. Pass the passage as text, in the user's words where you can, or pass the conversation as messages with their roles, so that only what the user said or agreed to is kept and nothing the assistant suggested. The server works out what it says. A newer statement replaces an older one about the same thing, and the older one stays in the history. Restating something already known changes nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | what to remember; or pass messages | |
| messages | No | a conversation to remember instead of text, in order: only what the user said or agreed to is kept | |
| observed_at | No | when it was said, as an RFC3339 instant like 2023-05-20T02:21:00Z; omit for now. Use it only for something said earlier, such as an imported conversation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses that only user-attributed content is kept, that newer statements supersede older ones about the same subject, that superseded entries remain in history, and that redundant restatement is a no-op. These deduplication and idempotency semantics are exactly the behavioral traits an agent cannot infer from the schema.
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?
Purpose and content types are front-loaded, followed by parameter guidance and then behavioral rules, so structure matches reading order. It is a dense paragraph with no wasted clause, though splitting the deduplication rules into their own sentence group would aid scanning.
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 mutation-style tool with no annotations and no output schema, the description covers write semantics, attribution rules, conflict resolution, and idempotency. The remaining gap is what a successful call returns (confirmation, identifier, or nothing), which the agent may want to know for follow-up calls.
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 baseline is 3, but the description adds real meaning: it explains the text-vs-messages tradeoff and the filtering behavior of messages ('only what the user said or agreed to is kept'), plus the intent behind observed_at. It stops short of clarifying what happens when both text and messages are passed, which the schema also leaves open.
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?
Opens with a specific verb and object: 'Keep something worth remembering about the user or their work,' then enumerates the acceptable content types (preference, fact, decision, correction). The write-side framing clearly separates it from recall/forget/history/diff siblings without relying on the name alone.
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 concrete usage guidance: prefer the user's own words for text, use messages when you want role-filtering, and reserve observed_at for earlier/imported statements. It never explicitly excludes a sibling tool by name, but the write-vs-read boundary is unambiguous from context.
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.
5 tool updates
v0.22.1- First observed
diff - First observed
forget - First observed
history - First observed
recall - First observed
remember
TDQS
Scored across 5 tools
The five tools cover clearly different operations: storing, querying, withdrawing, tracing one item's history, and comparing beliefs across time. The only mild overlap is between recall's `since` mode and diff, which both answer 'what changed', though their descriptions differentiate instants versus periods.
All names are single, lowercase words with a consistent terse style. However, remember/recall/forget are verbs while history and diff are nouns, a minor deviation from a pure verb convention.
Five tools is well scoped for a focused memory service, with each tool earning its place across the read/write/history lifecycle. No tool feels redundant or missing from the core set.
The surface covers the full memory lifecycle: write (remember), read (recall with profile, point-in-time, and delta views), soft delete (forget), per-item history, and cross-instant diff. No dead ends are apparent for the stated purpose.
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
- 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.49Apache 2.0
- AlicenseNot gradedqualityDmaintenanceIntegrates an Engram brain with Claude Code via MCP, providing tools for searching, retrieving, and adding memories.5 npmMIT
- AlicenseNot 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.2Business Source 1.1
- 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