Continuum
Production-grade memory infrastructure for AI agents. Tiered storage (STM / MTM / LTM), first-class supersession and bi-temporal queries, cost-efficient retrieval. Plugs in under whatever reasoner you're using — LangGraph, AutoGen, custom — and provides the memory layer they all lack.
git clone https://github.com/Genkryptos/Continuum.git && cd Continuum
make demo-chat # 60-second walkthrough, no infrastructure, no API key
make bench-all # the four benchmarks Continuum is built to win
What it is
Most "memory" for LLM agents is one of:
- a vector database (great recall, no notion of "current" vs "stale" facts),
- an append-only chat history (no organization, gets expensive fast),
- a manually-curated profile object (works until the user changes their mind).
Continuum is the operational memory layer: tiered storage so recent conversation, mid-term summaries, and long-term facts are addressable separately; supersession — superseded LTM facts are stamped invalidated_at (never deleted), so every read filters on invalidated_at IS NULL and the system always knows which version is current; and bi-temporal columns — valid_from/valid_to (world-time) plus created_at/invalidated_at (system-time) — so it can answer "what did the user say about X as of date Y?", including retroactive corrections.
It is not a reasoning engine. The framework's value-prop is what the layer below the reasoner should have been doing all along, with benchmark numbers below to back it up.
Why this exists — the headline measurements
The robust, reproducible wins are the deterministic ones (they don't move between runs); the LongMemEval number is honest but carries reader variance.
| benchmark | Continuum | naive baseline |
|---|---|---|
| Supersession correctness (50 scripted updates) | 100 % | 38 % |
| Bi-temporal "as of date Y" (20 scripted timelines) | 100 % | 75 % |
| LongMemEval-S (500 Q, judged, gpt-oss-120b) | ~74 % (73.6 – 75.6 % across repeated runs) | 60.8 % (v1.0) · 34.4 % (May ceiling) |
| ↳ same-setup per-category (control run) | multi-session 62 % · temporal 75 % · KU 64 % · assistant 96 % · user 91 % | — |
| Retrieval recall @ 4 (200-session synthetic corpus) | 55 % | 55 % (tied — recency signal absent) |
| Ingest p50 / session (1 user turn) | 0.18 ms + 6 LLM-extraction calls | 0.00 ms (raw list) |
Sources: LongMemEval-S numbers are documented in the v1 findings report and regenerated with make repro-everything (raw run outputs are gitignored, not committed); synthetic benchmarks from bench/, reproducible via make bench-all (~60 s, no infra, no API key).
Honest headline — read this. On LongMemEval-S the judged number is ~74 % (73.6 – 75.6 % across repeated same-setup runs).
gpt-oss-120bhas ~±3–5 pp per-category run-to-run variance, so a single run is not a stable estimate: the 76.4 % in earlier v2.0 notes was a favorable draw, and read-side additions (a bounded reflect pass + vote-of-3) are within that noise of the no-additions baseline (73.8 %) — approximately accuracy-neutral overall. Per-category figures swing between runs and should not be read as fixed. The reproducible wins are the two deterministic benches above — supersession and bi-temporal "as of date Y", both 100 % — which don't move. We also disproved four "have the memory layer fix the reader" levers (synthesis, router, distillation, temporal code-math — all net-negative), and learned the methodology lesson that measuring gains only on known failures overstates them. Full write-up: docs/limitations.md · docs/report.md.
v2.0 — retrieval reranking (architecture-native — no new model, no compression). Over-fetch the candidate pool, then a cross-encoder (
continuum/retrieval/reranker.py) reorders it and keeps the best 24:
- Lifts recall on the retrieval-bound category — multi-session 57.9% → 69.9% (+12pp, n=133 A/B) — with a +2.3pp temporal bonus; knowledge-update flat; gated off for single-session-preference (it reorders away the rubric turns).
- Honest note: this improves retrieval recall, but on the full-500 judged aggregate it lands within
gpt-oss-120b's run-to-run noise of the baseline. The judged number is ~74 % (see the honest headline above), not the 76.4 % an earlier favorable single draw reported. The win here is multi-session retrieval quality, not a lift in the headline accuracy.v1.1 — 60.8% → 72.8% judged (confirmed full-500, gpt-oss-120b), from two memory-attributable fixes — no new model, no reasoning loop, just surfacing data the schema already had:
- Temporal date-surfacing (the driver): temporal questions were answered with the turn dates stripped from the prompt (the model literally replied "no dates available"). Surfacing each turn's date + the reference "now" lifted temporal 41.4% → 72.9% (+32pp) — confirmed by an n=133 A/B (signal +33pp vs a 0.8pp A/A noise floor).
- Supersession-recency: mark the current (non-invalidated) LTM facts and prefer them over stale turns → knowledge-update ~+4.5pp (n=78 A/B).
Both gated to their categories, so the solved ones (single-session 96–98%) didn't move. Honest note: 90%+ on this benchmark needs a frontier reader — our gains are what the memory layer earns at a fixed mid-tier model. The aggregation-prompt and preference levers were tested and cut as net-neutral / unmeasurable (see
findings/roadmap_v1.1.md).
v1.0.0 — Continuum broke the May 2026 ~34% LongMemEval-S ceiling to 60.8% judged — and did it without the iterative reasoning we predicted we'd need. What actually moved the number (a stronger answerer + clean direct retrieval + honest scoring), and the reasoning loop we built and cut as net-negative, are documented in findings/reasoning_loop_2026-06.md. A LOCOMO head-to-head vs Mem0 is preliminary (clean run pending) and not yet a published claim.
The supersession + bi-temporal wins aren't tunable parameters — they're consequences of the schema. Append-only stores and vector databases cannot reach these numbers without re-implementing this architecture on top.
The 60-second demo
make demo-chat
Runs a scripted walkthrough where the user:
- introduces themselves with
I live in NYC and just adopted a dog named Rex→ Continuum extractsuser.location = NYCanduser.pets.dog = Rexinto LTM. - updates:
I just moved to Boston→ the NYC fact is markedsuperseded_bythe Boston one. Both are still in storage; only Boston is "current". - queries
/show ltm→ current facts only (Boston + Rex). - queries
/show ltm --all→ full history with the supersession edge visible. /query "where do I live"→ returns Boston, not NYC, by construction.
The full demo runs in 63 ms with the canned LLM (no API key). It's the canonical show of what bench-supersession proves as a number.
See examples/chat_agent/ for source + the interactive REPL.
Architecture in one diagram
┌────────────────────────────────────────────────────────────────────┐
│ ContinuumSession │
│ │
│ process_turn(user_msg) │
│ │ │
│ ▼ │
│ ┌────────┐ ┌──────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ STM │ → │ Retriever│ → │Optimizer│ → │ Responder │ │
│ │ recent │ │ cosine + │ │ chain │ │ your LLM │ │
│ │ turns │ │ composite│ │ (compress│ │ + ctx │ │
│ │ │ │ scorer │ │ budget) │ │ │ │
│ └────┬───┘ └──────────┘ └─────────┘ └──────┬───────┘ │
│ │ │ │
│ │ promotion (background queue) │ reply │
│ ▼ ▼ │
│ ┌────────┐ to caller │
│ │ MTM │ ← session summaries (LLM-generated) │
│ └────┬───┘ │
│ ▼ │
│ ┌────────┐ │
│ │ LTM │ ← atomic facts + entities + supersession │
│ │ pgvector│ + bi-temporal columns (valid_from, invalidated_at)│
│ └────────┘ │
└────────────────────────────────────────────────────────────────────┘
Each box is a swappable component. The retriever and optimizer chain are protocol-based; the stores live behind STMProtocol / MTMProtocol / LTMProtocol so the in-memory variant works for local dev and the Postgres variant scales to production.
Quick start (no infra)
Use it in Python — the library API (pip install continuum-mcp):
import asyncio
from continuum import Memory
async def main():
mem = Memory.in_memory() # zero-config — no Postgres, no model download
async with mem:
await mem.add("I moved to Boston")
await mem.add("Actually I'm in NYC now") # supersession handles the update
print(await mem.recall("where do I live?"))
print(await mem.current("user", "residence")) # the resolved, current value
print(await mem.timeline("residence")) # bi-temporal history, oldest→newest
asyncio.run(main())
On the Postgres path there is a sixth verb, forget — maintenance for a store
that would otherwise only ever grow:
report = await mem.forget(unused_for=timedelta(days=180)) # dry run by default
print(report.matched, report.samples) # see it before you mean it
await mem.forget(unused_for=timedelta(days=180), dry_run=False)
It is deliberately timid: only facts that are no longer true (superseded)
and untouched for unused_for are eligible, it is scoped to the namespace,
capped by limit, and it retires rows the same way supersession does —
invalidated_at is set, nothing is deleted, so a policy you regret is
recoverable. Nothing prunes on a timer, and it is not exposed as an MCP tool:
an agent should not be able to decide to forget things about you.
Use it as an MCP server — plug it into any MCP client (Claude Code, Claude
Desktop, Cursor) with zero glue. Memory becomes four tools: remember, recall,
current, timeline.
pip install "continuum-mcp[mcp,postgres,embed]"
# point it at a Postgres + pgvector database — migrate once
python -m continuum.db.migrate --dsn "$CONTINUUM_DB_DSN"
# register with Claude Code over stdio (any MCP client works the same way)
claude mcp add continuum -e CONTINUUM_DB_DSN="$CONTINUUM_DB_DSN" -- continuum-mcp
# …or serve over HTTP and connect by URL instead:
# continuum-mcp --http --port 8000
# claude mcp add -t http continuum http://127.0.0.1:8000/mcp
Embeddings run locally on bge-m3 — no API key is needed for memory itself.
Full transport, backend, and client-config reference: docs/mcp.md.
Supersession + bi-temporal history are strongest on the Postgres path (below);
Memory.in_memory()is the zero-setup path for demos and tests. Honest scope and known limits: docs/limitations.md.
From source (demo + benchmarks):
git clone https://github.com/Genkryptos/Continuum.git && cd Continuum
# 1. Install Continuum + its dev tooling
pip install -e .
# 2. See the 60-second story
make demo-chat
# 3. Reproduce the benchmarks
make bench-all
# 4. (Optional) reproduce the v1 LongMemEval-S numbers
# answerer = gpt-oss-120b via OpenRouter; non-reasoning judge.
# The dataset is fetched on demand (not committed to the repo).
export OPENROUTER_API_KEY=sk-or-…
make repro-everything
That's the complete loop. No Postgres needed for the demo or any of the benchmarks. The full production path with Postgres+pgvector is documented under continuum/stores/postgres/ and exercised by the integration tests under tests/integration/.
Production path (Postgres) + verifying your .env
cp .env.example .env # fill in a provider key and/or CONTINUUM_DB_DSN
make db-up # start Postgres + pgvector (docker-compose), wait until ready
make db-migrate # create the pgvector extension + LTM schema
make check-env # ✓/✗ report: config loads, provider key, DB reachable + schema, smoke
make run # interactive chat REPL on a real Postgres-backed session
make run (i.e. python -m continuum.chat) starts an interactive you> REPL on a real ContinuumSession — PostgresSTM + PostgresLTM + the hybrid Retriever + an OpenRouter responder. Every turn persists to Postgres and is indexed for recall, so quitting and re-running with the same --session remembers the conversation. make run keeps the embedder off (LTM sparse/trigram + STM recency, no model download); use make run-full for dense semantic recall (downloads bge-m3, ~2.3 GB, once). Useful flags: --session <id> (named persistent session), --model <id> (OpenRouter model, default openai/gpt-4o-mini), --in-memory (no DB — also make run-mem), --mock (deterministic, no LLM call). Inside the REPL: /help, /search <q>, /stats, /session <id>, /exit. Pass extra flags via make run ARGS="--session alice".
make check-env (i.e. python -m continuum.doctor) is the "did I set this up right?" command — it loads your config, detects which LLM provider key is present (in .env or your shell), probes the configured Postgres DSN for the pgvector extension, and runs one in-memory turn end-to-end. A missing key or unreachable DB is a warning (the offline path still works); a broken config or a session that won't start is a failure (non-zero exit, so it works in CI too). Add --ping to validate each provider key against a live read-only API call, or --full to actually load the embedder.
The compose defaults match
.env.example's DSN (postgresql://postgres:postgres@localhost:5432/continuum). If your.envuses different credentials, setPOSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB(env or shell) beforemake db-upso the two agree.
Make targets
| target | what |
|---|---|
make demo-chat |
scripted 60-second chat-agent walkthrough (in-memory) |
make run |
interactive chat REPL on a real Postgres-backed session (embedder off) |
make run-full |
same, with the embedder for dense recall (downloads bge-m3) |
make db-up / make db-down |
start / stop local Postgres+pgvector (docker-compose) |
make db-migrate |
apply migrations (pgvector ext + LTM schema) |
make check-env |
verify your .env: config, provider key, DB+schema, smoke |
make bench-ingest |
ingest throughput (Continuum vs raw list vs mem0) |
make bench-retrieval |
retrieval recall@k vs naive cosine |
make bench-supersession |
the killer feature — 100 % vs 38 % |
make bench-bitemporal |
"as of date Y" lookups — 100 % vs 75 % |
make bench-all |
run all four benchmarks in sequence |
make bench-locomo |
LOCOMO + Mem0 head-to-head (preliminary) |
make repro-longmemeval |
reproduce the LongMemEval-S evaluation |
make repro-everything |
reproduce both headline runs (LongMemEval + benches) |
make test |
full test suite (unit + integration) |
make test-fast |
unit tests only — no infra required |
make check |
format + lint + mypy strict |
make build |
build wheel + sdist into dist/ |
make build-verify |
build, then install + smoke-test in a fresh venv |
Documentation
Four focused docs under docs/:
- Quickstart — five commands to a working
ContinuumSession. - Architecture — the three tiers, promotion lifecycle, supersession, bi-temporal.
- Config reference — every env-var and YAML knob with defaults.
- Operations — Postgres setup, scaling, observability, common production issues.
If you're new, the recommended path is: this README → make demo-chat → docs/architecture.md → docs/quickstart.md. About 30 minutes if you read everything; 10 if you skim.
Honest evaluation — the LongMemEval-S reports
Two reports, read in order — the second corrects the first, which is the point:
findings/longmemeval_2026-05.md (May) — seven full sweeps across four model families and six retrievers found a hard 32-34% substring ceiling, even at 100% recall, and concluded the bottleneck was multi-hop reasoning: a single-shot retrieve → answer pipeline couldn't exceed it "without an external reasoning loop."
findings/reasoning_loop_2026-06.md (June, v1) — we built that reasoning loop (the IterativeReasoner), A/B'd it, and it was net-negative — so we cut it. v1 broke the ceiling to 60.8% judged with a single-shot pipeline anyway. What actually moved the number:
- a stronger answerer (the dominant lever — we say so plainly),
- the LLM judge revealing substring under-counted paraphrases by +12.4 pp,
- session-aware retrieval + fixing two silent truncation bugs (multi-session ~16% → 55%),
- LTM supersession making knowledge-update work (98.7% recall).
The June report is deliberately honest about what we got wrong (the reasoning-loop prediction), which lever bought which points, where we still lose (temporal-reasoning at 41%), and why the LOCOMO/Mem0 head-to-head is still preliminary rather than a published win. Reproduce both headline runs with make repro-everything.
The throughline that informs Continuum's positioning: a strong model fed clean, complete context beats elaborate scaffolding — be the memory layer that surfaces the right context cheaply; don't try to out-reason the reasoner.
Project layout
continuum/ the framework itself
├── core/ session orchestration, types, config
├── stores/ STM / MTM / LTM implementations
│ ├── stm/ in-memory + thread-safe + Postgres
│ ├── in_memory/ in-memory LTM with supersession (eval + local dev)
│ └── postgres/ pgvector-backed MTM + LTM with supersession + bi-temporal
├── retrieval/ composite scorer + BM25 + reciprocal-rank-fusion hybrid
├── extraction/ entity / fact / LLM extractors + cached SmallLLM helper
├── promotion/ Mem0Promoter, triggers, IdleStmFlush
├── optimizer/ token-budget compression chain (5 strategies)
├── scoring/ composite scorer (relevance / importance / recency / confidence)
├── policies/ policy engine + 8 default policies (migration 004)
├── reasoning/ IterativeReasoner — shipped but cut from v1 (tested negative result)
├── embeddings/ embedding service (sentence-transformers)
└── db/ pgvector upgrade helpers
memory/ legacy STM engine the framework re-exports (ConversationSTM)
bench/ memory-operation benchmarks (make bench-all)
├── ingest_throughput.py Continuum vs raw list vs mem0
├── retrieval_quality.py recall@k vs naive cosine
├── supersession_correctness.py 100% vs 38%
└── bi_temporal.py "as of date Y" — 100% vs 75%
evals/ reproduction harness (datasets fetched on demand)
├── longmemeval/ LongMemEval-S driver (the v1 60.8% result)
└── locomo/ LOCOMO + Mem0 head-to-head (preliminary)
findings/ evaluation reports + reproducibility
├── longmemeval_2026-05.md the May "32% ceiling" report
├── reasoning_loop_2026-06.md the v1 correction (supersedes it)
└── charts/ summary-generation scripts
docs/ quickstart · architecture · config · operations
examples/chat_agent/ the 60-second CLI demo (make demo-chat)
scripts/ diagnostic-sample + bench-regression + install-verify helpers
migrations/ numbered Postgres migrations (pgvector, lexical search, policies)
tests/
├── unit/ per-component unit tests
├── integration/ cross-tier flows + Postgres pgvector
└── acceptance/ phase-completion gates
This
releasebranch ships the essential library + reproduction harness only. Vendored datasets, raw run outputs (results/,bench/results/*.json,.wiki_cache*), and earlier prototype code are intentionally excluded — they're regenerated on demand and gitignored. Full history lives onmain.
What Continuum is not
- Not a vector database. It uses pgvector under the hood but adds tier semantics, supersession, and bi-temporal queries that pgvector alone doesn't provide.
- Not a reasoning engine. No agentic loop, no multi-hop retrieval, no chain-of-thought orchestration. Use LangGraph, AutoGen, or your own loop on top — Continuum is what they should plug into for memory.
- Not a managed service. It's an open-source Python framework. Self-host on your own Postgres.
- Not a leaderboard-tuned LongMemEval contender. We measured honestly; see the report.
Status
Phase 1 (storage + protocols + tests), Phase 2 (extraction + promotion + policies + retrieval), and Phase 3 (benchmarks + demo + findings) are complete. The framework passes strict mypy + full unit / integration / acceptance test gates.
Production readiness (deploy scripts, observability, multi-tenant testing) is the next phase if and when there's interest.
License
MIT.
Citation
If Continuum's supersession or bi-temporal benchmarks are useful in your work:
Continuum: production-grade memory infrastructure for AI agents.
https://github.com/Genkryptos/Continuum, 2026.
Metadata
Release files for continuum-mcp 2.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| continuum_mcp-2.0.4.tar.gz | 676.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| continuum_mcp-2.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.0 MB
Release files / continuum_mcp-2.0.4.tar.gz
| Download URL | continuum_mcp-2.0.4.tar.gz |
|---|---|
| Size | 676.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
47df1811292c76f7a2099b6a0d9068164dcc852640cf562ee9add8a917ef4c93
|
|
BLAKE2b-256 checksum How to use checksums |
b5ced0d8c7bc7713ec21a628101bd09d23dbc0fcadf4f469bc88895bc00da19d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.8
|
Release files / continuum_mcp-2.0.4-py3-none-any.whl
| Download URL | continuum_mcp-2.0.4-py3-none-any.whl |
|---|---|
| Size | 330.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eed30a305aa22d769b0add7062a085173631a85fa152e05e1db900609476b2f8
|
|
BLAKE2b-256 checksum How to use checksums |
b8eef8f48d729118121b9708b95016d4934ecea9259df2ff700fa970a8f2136b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.8
|