Skip to main content
total-agent-memory — cover

Featured work

total-agent-memory totalmemory.dev

Persistent memory for AI coding agents over MCP — local, or as an authenticated team server with personal, team and shared memory (v14.9.0).

  • Python
  • SQLite
  • FastEmbed
  • ChromaDB
  • Ollama
  • MCP
  • Three.js

The problem

A coding agent without memory re-asks you the same question every session. Worse, it re-makes the same mistakes. Context windows are not memory — they’re a working set. Vector stores are not memory either — they’re Ctrl+F with embeddings.

I wanted something closer to how a senior engineer works: episodic recall (“we tried that last Tuesday, didn’t work”), semantic recall (“the company convention is to log in JSON”), decay, contradictions, and the right to say “I don’t know”.

Architecture

  • Lexical path: SQLite + FTS5 with BM25 ranking, plus fuzzy matching for typos.
  • Semantic path: FastEmbed embeddings (ONNX, no PyTorch in the default install). SQLite vector storage is the search authority; ChromaDB is a write-side mirror.
  • Graph layer: entities, relations and temporal facts, with cognitive activation spreading.
  • Fusion: results combined with Reciprocal Rank Fusion, then an MMR pass for diversity.
  • Re-rank: optional CrossEncoder / BGE reranker, installed as a separate extra and off in the default fast mode.

Version 14.9.0 (2026-10-13)

  • Memory that works without a memory call. Hooks now do the recall, the rule checking and the saving: every prompt gets the matching rules and a short block of relevant records (400-token budget, 1.5 s limit, never blocking the prompt), a new PreToolUse hook shows a rule right before the command or edit it applies to, and at Stop the turn is checked against the rules shown to the session. A prompt that corrects the agent (“I already told you…”) becomes a draft insight that turns into a rule only after real upvotes. Rule suspension now rests on explicit ratings only; loading rules used to suspend helpful ones after ten session starts.
  • One warm server for every client. tam daemon runs one server per memory directory and clients connect through tam proxy: the first memory_recall of a session takes 0.18 s instead of 1.51 s. Relative dates (“last month”, “three weeks ago”) now give recall a date window, “what was it before?” questions rank the older value first (0/48 → 48/48), and LongMemEval-S held-out reached 88.0 on 400 questions. Results.
  • Import, export, CI. tam import chatgpt|claude|mem0|markdown keeps original timestamps; tam export --encrypted moves a store between machines as an AES-256-GCM bundle. The catalogue grows from 77 to 79 tools, and every pull request runs the full suite on Ubuntu, macOS and Windows with Python 3.11–3.13.

Version 14.8.0 (2026-10-08)

  • Every recall tier measured, two of them fixed. The weights that fuse the retrieval tiers are now configuration, and a new ablation harness measures what each tier is worth on LoCoMo, LongMemEval-S or a copy of an installed store. On a copy of the author’s store it found a graph tier that had never fired (it read a table nothing writes) and a representation tier that compared the query with an arbitrary subset of rows; both are fixed. Same 150 queries: R@10 0.133 → 0.167, p50 recall 336 ms → 128 ms. Results.
  • Questions the ranking used to miss. Advice-shaped questions also search the project’s conventions and favour the user’s own turns (LongMemEval-S preference questions: MRR 0.460 → 0.509); session_end keeps its summary as a record that later recalls find.
  • Operations. A fallback chain of LLM providers, so a stopped Ollama no longer leaves the enrichment queues pending in silence, and the hourly reflection job now consolidates idle projects on personal installs. The 77 tool schemas are pinned by a test; nothing in the plugin, the hooks or the skill changed.

Version 14.7.0 (2026-09-30)

  • Whole records fill the context budget. memory_recall(mode="context", fill_budget=true) searches up to 100 hits deep and keeps whole records, in rank order, until the character budget is used, instead of cutting the top hits to excerpts. With it the context holds the gold evidence more often: LoCoMo 0.815 → 0.890 at 8,000 characters, LongMemEval-S (every gold turn) 0.766 → 0.904 at 40,000. Off by default. Results.
  • AMA-Bench, full test set. As the memory of a gpt-5-mini agent, TAM scores 0.658 over the 24 domain × capability cells of all 208 episodes (judge gpt-5.2); GPT-5 mini reading the whole trajectory scores 0.656 on the published board. The result is submitted to the leaderboard and is self-reported until the board verifies it. Method and run.

Version 14.6.0 (2026-09-28)

  • A company memory server you can run. tam setup asks “Just me” or “Company server”. The team server gets a web dashboard with invite codes, roles (member, department head, company viewer, superadmin), an audit log and provider settings with encrypted keys. It adds department onboarding with quizzes, activity reports (memory_report) and offboarding, and it can keep all its data in PostgreSQL. On the parity benchmark both backends return the same top 10.
  • Settings and privacy for personal installs. The local dashboard has a Settings page. API keys are stored encrypted and no longer written into client configs. Credentials are redacted on every write path. tam redact-existing cleans stores saved by older versions, and memory_delete(hard=true) erases a record with every copy of it.
  • Hermes Agent plugin. hermes-tam-memory makes TAM a native memory provider for Nous Research’s Hermes Agent: it saves each turn, recalls relevant memories before the next one and adds tam_recall / tam_save, locally or against the team server.

Version 14.5.1 (2026-09-24)

  • A record stays below its own later update. The cross-encoder added in 14.5.0 knew the real-world value and could lift it above the recorded update (“Windows Vista” → Microsoft above the later “Raytheon”). After re-ranking, values of the same statement are now ordered newest first. On MemoryAgentBench FactConsolidation the newest value ranks first for 98 of 100 questions instead of 45; LoCoMo and LongMemEval do not change. Findings.

Version 14.5.0 (2026-09-23)

  • No significant difference from Mem0 Platform. Mem0 publishes the answers behind its LoCoMo and LongMemEval figures. Graded next to total-agent-memory’s answers on the same held-out questions, with the same judge model and prompt for both systems in each grading configuration: LongMemEval-S 92.25 vs 91.00, LoCoMo 88.02 vs 88.46. No difference is statistically significant on these questions, which is not the same as proven equivalence — with retrieval running locally and no LLM call on write or search. Report and how to reproduce it.
  • Better context for the reader. The cross-encoder also reads each candidate with its neighbouring turns, relative dates (“last Thursday”) come with the date they denote, and the context budget goes by rank, so a long top hit is no longer cut to an excerpt.

Version 14.4.0 (2026-09-22, shipped in 14.5.0)

  • A record can retire the value it replaces. memory_save(supersede=true) marks older records of the same project and type that start with the same words and end in a different value (“citizenship is Argentina” → ”… is Armenia”) as superseded. It is opt-in, because the rule would also retire “likes rock” when “likes jazz” arrives. On MemoryAgentBench FactConsolidation single-hop, gpt-4o-mini goes from 82 to 99 (6k) and from 85 to 93 (262k).
  • Cheaper writes at a million records. A save no longer makes the vector cache reload everything: the next unscoped recall takes 0.37 s instead of 4.2 s. The concept name refresh that stalled one save a minute now takes 2.6 ms, so save p99 drops from 1.4 s to 0.14 s.

Version 14.3.1 (2026-09-21)

  • Updates are no longer dropped. 14.3.0 treated near-identical records as repeats, so “Messi’s citizenship is Argentina” followed by ”… is Armenia” kept Argentina; on MemoryAgentBench FactConsolidation it lost 36 of 455 facts. A record is now a repeat only when it says exactly the same thing, and a repeat replaces the stored one, so “A, B, A” leaves A as the latest.
  • Fast at a million records. Project-scoped recall no longer slows down with the whole store: 25 ms instead of 781 ms at 100k records, 105 ms instead of 6–64 s at 1M (200 tenants, one machine). MCP_HTTP_WORKERS runs several HTTP server processes on one port for services with many clients.

Version 14.3.0 (2026-09-21)

  • Jev as the contradiction checker. memory_answer can check retrieved facts for contradictions with TypeSafe’s Jev, a model that answers typed questions with probabilities instead of generating text: every pair becomes one question, all in a single request. Against the Claude Haiku 4.5 checker on the same questions, accuracy is unchanged (35/78 vs 36/78 on LongMemEval knowledge-update), the check drops from 3.1 s to 1.9 s, and Jev billed $0.04 for all 78 questions. Opt-in: MEMORY_CONTRADICTION_SCORER=jev.
  • API key hygiene. Empty keys and keys with control characters are rejected before any request, without echoing the key. The same flaw in the official TypeSafe SDKs is reported upstream.

Version 14.2.0 (2026-09-21)

  • Facts that change over time. memory_answer now answers with the latest value: “Mary loves red”, saved in May, and “Mary no longer likes red; she has fallen for green”, saved in August, give green, previously red. The reader sees when each record was saved, and a value stays current until a later record changes it. On LongMemEval knowledge-update the correct answers rose from 12/78 to 35/78 with Claude Haiku 4.5.
  • Contradictions are resolved, not refused. Both sides go to the reader with their dates; MEMORY_CONTRADICTION_POLICY=abstain restores the 14.1.0 refusal. A conflict about someone else no longer blocks the answer.
  • Russian word forms and one timestamp format. “Маша” in a question finds “Маше” in a record. Timestamps are stored in one UTC format, and older rows are converted on upgrade.

Version 14.1.0 (2026-09-21)

  • Negative retrieval in memory_answer. Before answering, a second search looks for facts that would contradict the likely answer: a small model inverts the question, and every (supporting, opposing) pair — at most 5 × 5 — is scored in one batched call. A score of 0.60 or more returns Not enough information instead of picking a side; 0.30–0.60 answers with a caveat.
  • memory_answer on Anthropic and Ollama: both providers now return schema-constrained output, so the grounded reader no longer fails on markdown-fenced JSON.

Version 14.0.0 (2026-09-15)

  • One authenticated server for personal, team and shared memory. Each scope has its own database, graph and index; search covers every scope the token can access.
  • Authorship and revision history. The author and client come from the personal token; edits create revisions, and revision checks stop one person from overwriting another’s change.
  • Team web interface for search, browsing, saving, editing and history.
  • Remote MCP bridge exposing eight core tools; the local catalogue has 76 tools.
  • Configurable internal LLM providers: Ollama, OpenAI-compatible endpoints or Anthropic.
  • Scoped retrieval and model-aware vector search: each embedding space is queried with its own model and dimensions; incompatible stored vectors are excluded instead of being compared silently.
  • Privacy-safe write intents: private sections are redacted before anything is written to the durable outbox.
  • Optional grounded reader (memory_answer) that rejects contradictory claims. It is not the default recall path.

Validation: the CI release matrix passed — native installs on Ubuntu 24.04, Windows 2022, macOS 15 Intel and macOS 15 arm64 with Python 3.11, 3.12 and 3.13, plus Docker Compose, Chromium / Firefox / WebKit browser tests, the package build and the full test suite from the source archive, where 2,145 tests pass.

Implementation highlights

  • Multi-representation storage — a record can be embedded as raw text, summary, keywords, questions and a compressed form; search runs across these representations.
  • Self-extracting knowledge graph — entities and relations are extracted automatically, and a fact merger handles contradictions.
  • Temporal facts — facts carry valid_from / valid_to, and kg_at answers what was true at a given moment.
  • Local dashboard — includes a 3D WebGL (Three.js) view of the knowledge graph.

Retrieval measurements

Measured on 13.x and cited by the v14 README. These are retrieval recall figures — whether the right evidence is in the top five — not answer accuracy:

  • LongMemEval (public, longmemeval_s, 470 questions, v13.0.0, default fast profile): recall@5 (any) = 95.1 %.
  • LoCoMo (1,536 questions): R@5 = 0.607.
  • BEAM at 1M scale (625 probes): R@5 = 0.448.

No ranking against other memory products is claimed.

Results

MIT-licensed, Python 3.11+, MCP-native. Runs as a local stdio server for one person or as a team server behind an HTTPS reverse proxy. Works with Claude Code, Codex CLI, Cursor and other MCP clients, and with Hermes Agent through a memory provider plugin. Version 14.6.0 is published as a GitHub Release with wheel and source archive, on PyPI, through the npm wrapper 1.9.0, as a ghcr.io image for linux/amd64 and linux/arm64, in the official MCP Registry and in a Homebrew tap. Product site: totalmemory.dev.

Lessons

  • Recall is a stack, not a service. Lexical, semantic and graph retrieval miss different things; fusion is where they pay off.
  • Forgetting is a feature. Without decay the store fills with stale facts that crowd out current ones.
  • Benchmarks need the same scrutiny as code. In 13.0.0 I withdrew an earlier, higher LongMemEval figure after finding that the runner measured its own self-contained ranking rather than the path an agent takes; the numbers above come from the real store and search path.