The declarative context engine for AI agents.
Define agent memory in versioned YAML — like Terraform for infrastructure. Memseek learns from everything you record and gives your agents cited, current, budget-cut context from a Postgres you run.
No retrieval pipeline. No opaque notebook. Every fact is dated, cited, and traceable.
$ git clone https://github.com/memseekai/memseek && cd memseek # Add OPENAI_API_KEY to .env, then: $ docker compose up -d --build --wait # postgres → migrate → api + worker → setup: # # published agent_memory@0.3.0 — 20 files of YAML, no code # MCP ready — 7 tools at http://127.0.0.1:8000/mcp # # point Claude Code or Codex at it, and the next session # remembers the rules you set weeks ago — with the message # each one came from
- 92.6% MemBukkit · LongMemEval accuracy Reproduce it yourself →
- 7 frozen recipes LongMemEval · LoCoMo · BEAM See every result →
- Runs on open weights 88.8% in the MemBukkit showcase See the eval harness →
History goes in.
Current context comes out.
Your apps and agents leave behind an ever-growing history of messages, events, documents, tool results, and outcomes. Memseek turns it into a maintained, evidence-backed model of what the agent should know, then compiles a cited context package for the exact task and token budget.
You define what to remember, how it changes, and what each task should see — in versioned YAML. Memseek runs the entire lifecycle on your Postgres.
retrieves what looks relevant.
maintains what is true now.
Search is one primitive. Memseek also derives and reconciles knowledge, supersedes stale facts without erasing history, preserves the evidence behind every claim, replays any point in time, and assembles agent-ready context to a declared token budget.
A catalog is a folder of YAML. Memseek runs it.
One mental model: you declare what your agent should remember, derive, keep true, and see — Memseek does the running. Four stages, all described in files you review like a schema migration.
Versioned YAML you review like a schema migration.
- ✓Every derived fact carries citations back to the message it came from.
- ✓Supersession, not string replacement — old claims are retired, never silently overwritten.
- ✓Point-in-time replay and recursive erasure built in, not retrofitted.
- ✓Your data stays yours — queryable, exportable rows in a Postgres 16 you deploy.
- ✓Gated changes land as reviewed drafts. Nothing updates itself without an audit trail.
agent_memory_catalog/ # 20 files, no code ├── collections/ messages · memories · scenes · persona ├── conf/ models · processors · ranking · search ├── derivations/ l1_extract · scene_synthesis · persona ├── views/ recall — one search across all layers ├── artifacts/ agent_context · maintained_procedure ├── mcp/ the 7 tools an agent may see └── packages/ agent_memory@0.3.0 — what you publish
What you store. Two append-only layers: what was said, and the reusable claims extracted from it. Neither is ever edited — a claim that stops being true is superseded by a later one that cites it.
collections: - name: messages # L0 — what was literally said version: 1 # a change ships v2; v1 keeps serving mode: event # immutable, append-only schema: # enforced at ingest, not at read required: [text, role, session_id, ordinal] properties: role: {enum: [user, assistant, tool]} additionalProperties: false # no stray keys, ever required_processors: [embedding_v1] - name: memories # L1 — one atomic claim per record version: 1 mode: event schema: required: [text, memory_kind, priority, decision] properties: memory_kind: {enum: [persona, episodic, instruction]} priority: {minimum: 0, maximum: 100} decision: {enum: [store, merge]} # what dedup concluded supersedes: {items: {format: uuid}} # the claims it replaces # … plus priority, the dedup decision, and what it supersedes
How a message becomes a claim. New messages arrive, one job reads them, checks each candidate against the memory that already exists, and writes only what is new. Citations are a required field, so a claim without evidence is dropped.
name: l1_extract trigger: {write: {collections: [messages]}, debounce_s: 2} sources: # all the run may see — every one capped new_messages: {kind: changes, collections: [messages], max_records: 40, max_tokens: 18000} background: {kind: view, view: recent_messages@1, max_tokens: 5000} current_scenes: {kind: current, collections: [scenes], max_records: 15} model: strong # an alias you repoint, not a model id limits: {max_llm_calls: 4, max_total_tokens: 50000, max_wall_s: 180} tasks: # read, then decide — never both in one prompt - id: claims # 1 · propose atomic claims from the messages - id: candidates # 2 · which existing memory is nearby? - id: decide # 3 · store · merge · skip, and what it supersedes output_schema: required: [text, memory_kind, decision, citations] properties: citations: {minItems: 1, items: {format: uuid}} # … three tasks: propose claims, retrieve what is nearby, then decide # store / merge / skip — with citations required, so no evidence, no write emit: {from: "{{decide.records}}", collection: memories, type: atom}
“Can I rewrite billing in Fastify and deploy it tonight?”
- Persona — the durable traits 1,200
- Standing rules, by priority 1,500
- Scene blocks for this work 2,500
- Relevant claims 2,500
Each block has its own ceiling, so a long scene can never crowd out a priority-100 rule.
## Persona Ships new Node services on Fastify. [9f1c…] ## Standing rules (priority ≥ 90) Billing needs explicit approval to ship. [b704…] Telemetry before removing a compat path. [4d18…] ## Relevant claims (2 of 41, by relevance) Billing stays on Express for mobile. [c221…] Legacy fields go in mobile release 7. [7ee0…]
This is the object that goes into the model before it reasons.
Three tabs, three files — and the artifact on the last one is
a single file, artifacts/agent_context.yaml, with no assembly code
behind it. Run the example →
One command. Your data stays yours.
Everything runs on your machine: the API, the worker, and plain Postgres. Docker brings up the full stack — with a working memory already loaded and ready to query. Point your coding agent at it, or start defining memories of your own in YAML.
no account to create · no cron to schedule · no queue to manage
One command brings up the whole stack.
Five services: Postgres (with pgvector), a one-shot migration, the
API your app and agents talk to, the worker that embeds, scores and
derives in the background, and a setup step that mints a workspace key and
publishes the four-layer agent-memory catalog. Docker is the only thing you need
installed. After cloning, add your OPENAI_API_KEY to
.env in the repository root, then start the stack.
$ git clone https://github.com/memseekai/memseek && cd memseek
Add your OPENAI_API_KEY to .env in
the repository root. Then start the stack:
$ docker compose up -d --build --wait # postgres → migrate → api + worker → setup, in that order: # # published agent_memory@0.3.0 (20 files) from examples/agent_memory_catalog # MCP interface ready — 7 tools: context, recall, standing_rules, # replay_session, remember, record, answer # # API http://127.0.0.1:8000 # MCP http://127.0.0.1:8000/mcp # Key export MEMSEEK_API_KEY=$(cat .memseek/api_key) $ export MEMSEEK_URL=http://127.0.0.1:8000 $ export MEMSEEK_API_KEY=$(cat .memseek/api_key)
Docker is the whole install, and the key is the only thing
you supply: embeddings and the memory passes are real model calls.
docker compose logs setup shows what was published,
docker compose logs -f worker shows it thinking, and
docker compose down -v removes all of it. Prefer to run the processes
yourself? uv run uvicorn memseek.api:app and
uv run memseek worker are the two ordinary processes the containers
are running for you — the same two you deploy later, unchanged.
Give your agent memory with receipts.
Step 01 published one already: the four-layer agent-memory catalog, 20 files of YAML and no code. Attach it and a fresh session knows the rules you set weeks ago — and can show you the message each one came from. It sees the seven tools the catalog declares and nothing else.
In Claude Code, install the plugin: it runs on the session lifecycle, so it captures the conversation and hands Claude a bounded memory brief on every turn, with no tool for the model to remember to call. Any other client — Codex, your own agent — connects to the same memory over MCP and asks for it explicitly.
# step 01 published the memory. two commands give claude code a # memory that runs on its own — no tool for it to remember to call. # the repo you cloned in step 01 is itself the plugin marketplace: $ claude plugin marketplace add ./ $ claude plugin install memseek-memory@memseek --scope local \ --config MEMSEEK_URL=http://127.0.0.1:8000 \ --config MEMSEEK_API_KEY="$(cat .memseek/api_key)" \ --config MEMSEEK_CAPTURE_MODE=conversation # 5 skills, 5 lifecycle hooks, and the memory MCP server: # ✔ Successfully installed plugin: memseek-memory@memseek (scope: local) $ claude # a new session: the plugin loads on start Memseek connected for project:memseek:2f77b8026b767ade. > billing deploys always need my explicit approval Understood — I'll ask before any billing deploy. # no tool call, and nothing for you to run. a hook captured both # messages; the worker turned them into a rule that cites them. # … a new session, days later, in the same repo: > rewrite billing in Fastify and ship it tonight ⏺ memseek · memory brief (supplied before claude answered) ## Standing rules (priority ≥ 80) Billing needs explicit approval to ship. [b704…] ## Relevant claims Billing stays on Express for the mobile app. [c221…] I'll write the change, but I'm not shipping it tonight: billing deploys need your explicit approval, and mobile still depends on the Express response format. Want me to open the PR instead? > /memseek-memory:memseek-explain # → the exact message you typed days ago, as the evidence behind # the rule it just applied.
# the same endpoint; the key stays in the environment [mcp_servers.memseek] url = "http://127.0.0.1:8000/mcp" bearer_token_env_var = "MEMSEEK_API_KEY" startup_timeout_sec = 20 tool_timeout_sec = 180 default_tools_approval_mode = "writes" # or, equivalently: $ codex mcp add memseek --url "$MEMSEEK_URL/mcp" \ --bearer-token-env-var MEMSEEK_API_KEY $ codex mcp list # then /mcp inside the TUI
# watch the same catalog build itself from one conversation $ export OPENAI_API_KEY=sk-... # conf/models.yaml names the variable $ uv run python examples/agent_memory.py # examples/agent_memory_catalog — 20 files, no code — then: # # L0 messages what was literally said, immutable # L1 memories atomic claims, each citing its messages # L2 scenes one keyed block per project or situation # L3 persona the traits that stayed true across scenes # # then renders one bounded context prompt for a request that must be # refused, and opens a single trait back down to the message behind it.
One tool writes; the rest only read. remember
is declared kind: ingest against one named collection, so the agent
appends evidence there and nowhere else — it cannot edit, retract, or aim a
write at another drawer, and it is annotated as a write so your host can prompt on it.
Five of the seven are deterministic reads answered straight from Postgres; only
answer calls a model. The plugin adds five slash commands over the same
surface — status, search, explain, remember, feedback — and its capture mode is yours
to pick: conversation, explicit, or off, all
three keeping recall on. Test the plugin end to end →
A context engine is a directory.
Collections, processors, derivations, views, artifacts, an MCP interface and a package manifest — a few files of versioned YAML you review like a schema migration, not code you maintain. This is the whole four-layer memory from step 01, exactly as it ships.
agent_memory_catalog/ # 20 files, no code ├── collections/ messages · memories · scenes · persona · … 7 ├── conf/ models · processors · ranking · search 4 ├── derivations/ l1_extract · scene_synthesis · persona · … 4 ├── views/ recall — one search across all four layers 1 ├── artifacts/ agent_context · maintained_procedure 2 ├── mcp/ agent_memory — the 7 tools an agent may see 1 └── packages/ agent_memory@0.3.0 — what you publish 1
Write events. Memseek maintains the memory.
Ingest returns immediately. In the background the worker embeds each message and, once a conversation has enough in it, extracts the atomic claims that become scenes and persona. Your application never orchestrates a pipeline.
from memseek.sdk import MemseekClient TEXT = "Every new Node service goes out on Fastify now. Billing " "stays on Express until mobile drops the legacy fields." async with MemseekClient(BASE_URL, API_KEY) as memseek: await memseek.catalog.publish( package="agent_memory@0.3.0", directory="examples/agent_memory_catalog", ) await memseek.records.ingest_many([{ "collection": "messages", "entity": "agent.alice", # the memory this belongs to "type": "message", "text": TEXT, "content": {"text": TEXT, "role": "user", "session_id": "s1-platform-review", "ordinal": 0}, "dedupe_key": "msg:s1:0", # replay-safe }])
Read the same memory four ways.
Whatever your agent needs: the current profile, a bounded cited answer over everything ever recorded, a context artifact assembled under a token budget, or a small MCP tool surface. Same catalog, no second pipeline.
# the durable traits, each one citing the messages behind it doc = await memseek.document( entity="agent.alice", collections="persona", ) for belief in doc["beliefs"]: print(belief["key"], belief["text"], belief["citations"]) # stack Fastify for new Node services; billing stays on… [9f1c…] # approval Billing deploys need explicit sign-off [b704…] # evidence Wants telemetry before removing a compat path [4d18…] doc["freshness"] # has the worker caught up with what you wrote?
# one bounded, cited synthesis — with the gaps named res = await memseek.answer( question="What do I need approval for before deploying?", entities=["agent.alice"], ) res["answer"] # "Billing changes: writing them is fine, shipping…" res["citations"] # ["9f1c…", "b704…"] — every claim traceable res["gaps"] # what it could not find, named rather than guessed # save=True writes the answer back as a provenance-carrying record.
# the bounded prompt block: persona + scenes + rules + relevance brief = await memseek.render_artifact( "agent_context", entity="agent.alice", task="rewrite billing in Fastify and deploy tonight", skill="deploy", ) brief["rendered"] # drop straight into your prompt brief["manifest"]["tokens"] # measured, against the declared budget brief["manifest"]["input_record_ids"] # exactly what went in brief["manifest"]["rendered_sha256"] # same inputs → same bytes
# mcp/agent_memory.yaml — the ONLY tools the agent can see. # nothing becomes a tool just because it exists. tools: - {name: context, kind: artifact, artifact: agent_context@1} - {name: recall, kind: view, view: memory_recall@1} - {name: standing_rules, kind: view, view: standing_instructions@1} - {name: replay_session, kind: view, view: session_window@1} - {name: remember, kind: ingest, collection: messages@1} - {name: record, kind: record} - {name: answer, kind: answer} # these are the seven tools the plugin and any MCP client saw in step 02.
github.com/memseekai/memseek
Two processes + PostgreSQL/pgvector — deploy them wherever you already deploy things
Runnable catalogs ship in examples/
Python SDK, HTTP API, or MCP over stdio and Streamable HTTP
Swap models by alias, not by redesign
Ordinary tables: query, export or replay it with psql
Run entire memory architectures from YAML.
gbrain, TencentDB Agent Memory, the Generative Agents paper, Anthropic's Dreams — each is a different arrangement of the same eight primitives. There is no plugin to write, no service to fork and no pipeline to maintain: you publish a folder of YAML and the design is running. Between 10 and 27 files, reviewed in a pull request like a schema migration.
You only meet two of them to get started — a collection and a derivation. Every design below is built out of these eight and nothing else.
If you have a memory design of your own, this is the point: you are writing definitions, not a system. Six of these seven ship as a runnable example in the repo — open them, or publish one locally in one command.
92.6% on LongMemEval-S.
When LongMemEval judges, MemBukkit leads.
Some higher reported numbers use a different judge. MemBukkit is scored by LongMemEval's official gpt-4o judge, and its frozen recipe ships in the open — rerun it before you believe the chart.
Answer accuracy
published best claimsLongMemEval-S · 500 questions. Solid bars use the benchmark's official gpt-4o judge. Patterned bars use another judge and are shown for context, not as like-for-like rankings. See who judged what ↗
Accuracy vs. cost per answer
better and cheaper ↖88.8% · $0.0004
82.0% · $0.0005
92.6% · $0.015
85.2%
71.2%
60.2% · $0.29
89.2% · $0.16
94.4% · alternate judge
91.4% · alternate judge
Query-time model list-price floors on measured answer context; write-time distillation and hidden reasoning tokens are excluded. Unpriced comparison points are positioned from their published model configuration. Gemini full-context is the independent 122.9k-token measurement cited in the methodology. Sources and protocol →
Don't take the chart's word for it.
The MemBukkit repo contains the full eval harness and frozen recipe. Run the exact agent-memory configuration behind the official-judge result.
You can build retrieval in a weekend. Memory is what comes after.
Postgres + pgvector gets you surprisingly far. The hard part starts when facts change: deciding what still holds, preserving what used to hold, tracing every claim to evidence, rebuilding historical state, and deleting data all the way through derived knowledge. That's the infrastructure Memseek gives you.
three honest alternatives below · each opens with the case for not buying us
Build it yourself if retrieval quality is the whole problem. pgvector and a table really are enough.
Two weeks gets you embed → store → retrieve that works, on a schema you wrote, with nothing new in the request path.
The next six to twelve engineer-months aren't retrieval — they're supersession, citations, point-in-time replay, and recursive erase. Easy to defer, expensive to add once your app reads its history through the shape you picked in week two.
Use the memory tool if one agent keeping its own notes is the job. It costs nothing and it's already there.
$0 beyond tokens, and the files stay in your infrastructure — the model issues file commands your handler executes, so the vendor stores nothing.
It's the model's notebook, not your system of record. str_replace overwrites, so last quarter's value is gone — and there's no schema refusing a bad write, no citation naming the event a line came from.
Keep CLAUDE.md if you have fewer than 40 rules and no audit requirement. A context engine would be overhead.
Free, in version control, reviewed in a pull request, and every agent tool already reads it. A human wrote every line, so a human can delete any line.
Four things break as it grows: nothing supersedes, so changed rules sit next to the old ones; it's a prompt rather than a store, so every rule competes for context on every task; no provenance, so stale and live constraints look identical and nobody deletes either; and it only learns by hand.
plain RAG vector search
- ✕Returns chunks that look similar — no idea which one is current.
- ✕Contradictions arrive side by side and the model guesses.
- ✕Dumps the whole history into the prompt to be safe.
- ✕Sources and dates fall off along the way.
memseek declared context
- ✓Serves the few facts that hold now, with what they superseded still on record.
- ✓Reconciles sources into one coherent picture, and flags real contradictions as events.
- ✓Compact context — ~32× fewer tokens than the full history.
- ✓Every belief cites its evidence or is rejected. Point-in-time replay included.
You already know RAG isn't memory, and memory isn't context — hybrid retrieval is one primitive inside memseek, not the product. The category, in full: what a context engine is. The failure it comes from: Your agent doesn't need more context. It needs the current context.
The questions we actually get asked.
How do Memseek and MemBukkit relate?+
What does it cost to run?+
max_llm_calls, max_total_tokens, max_wall_s. Reading is the cheap part: roughly 3,200 tokens of assembled context per question instead of ~101,000 for raw history. Several adapters run at max_llm_calls: 0 and cost nothing but Postgres. Separately, the MemBukkit open-weight benchmark recipe scores 88.8% on LongMemEval-S.Where does my data live?+
Will it change anything without asking?+
How do I get access?+
docker compose up without talking to anyone. Hosted Memseek is in early access: join the waitlist and tell us what your agent keeps getting wrong. If you are running agents in production today, say so; those teams go first.Your agent already has a model. Give it a memory you can inspect.
Run Memseek on your own Postgres today, or join the hosted early access.