Skip to main content

Proactive, local-first memory for AI coding agents - it acts before your agent repeats a mistake. Formerly Anamnesis.

Project description

Nevertwice: proactive, local-first memory for AI coding agents that acts before your agent repeats a mistake · plain Markdown + Git · zero dependencies · private by default

🧠 Nevertwice

Proactive, local-first memory for AI coding agents - it acts before your agent repeats a mistake.

Your coding agent forgets everything when a session ends. Nevertwice remembers: the bug you hit last week, the pattern that worked, the reason you picked Postgres over Mongo. Then it does what other memory tools don't. Instead of padding every prompt with recalled text, it stays quiet until it has something useful, then acts by catching the mistake before your agent repeats it - measured live, a fired guard cut a real model's repeat-error rate by 86% (the harness is in the repo). Memory that earns its tokens.

No database. No server. No account. No telemetry. Zero pip dependencies.

The core is stdlib-only and recall works fully offline (lexical fallback, no model). Lesson extraction wants a local Ollama or one optional cloud key. Claude Code is wired natively by install.py; Cursor, Codex, Zed and the rest connect via MCP or the watch daemon (details).

Formerly Anamnesis - renamed 2026-07 (same project, same store, old env vars still work).

tests CodeQL OpenSSF Scorecard Python Core deps License LongMemEval Active Memory

$ # days ago, a different session, your agent hit a CUDA OOM and Nevertwice recorded the lesson.
$ # now, a fresh agent, a new prompt:
$ python nevertwice/memory_search.py "training crashes out of gpu memory" myproject

⚠ 1 relevant lesson recalled (confidence 0.68):
  • [mistake] CUDA OOM at batch=64 on this GPU
    → lower batch size or enable gradient checkpointing; it recurred twice.

▶ See a guard fire: python examples/guard_demo.py · the whole machine on one project: python examples/scenario_demo.py · the 25-second recall demo: python examples/demo.py (any OS). All use a throwaway store; your real vault is untouched. Recording the GIF: docs/DEMO.md


Overview

Every morning your agent starts from zero. It re-reads the same files, rediscovers the same gotchas, and now and then repeats the exact mistake it made on Tuesday. You are paying tokens to re-teach it your own project on a loop.

Nevertwice gives it a memory. It watches each session, distils the durable lessons into short Markdown notes, commits them to git, and feeds the relevant ones back at the start of the next session and again as you type each prompt. The agent stops re-learning and starts recollecting.

The part most memory tools get wrong is the store itself. Here it is just files: your agent's memory is a folder of Markdown notes in a git repo (a vault), and you own every byte of it. You can open it in Obsidian, grep it, diff it, git pull it to another machine, or delete a note you disagree with. There is no vector database to run and no service to trust. That is the part no cloud competitor can copy without giving up their business model. Embeddings run locally on Ollama by default, or on a single cloud key if you would rather not run a local model.

And it is not a toy. On the public LongMemEval benchmark, with the same local embedder for every system, Nevertwice out-retrieves the funded hosted leaders (Mem0, LangMem, A-MEM) on every metric, and you can reproduce that in one command. The numbers, and an honest account of what we tried and cut to get there, are below.

Want more than coding memory? Flip on the opt-in Brain layer and the same captured sessions self-wire into a knowledge graph of papers, methods, and datasets, tracking how your thinking on each one evolved. It is pull-only, read on demand, so your token budget never notices it is there.

git clone https://github.com/DonPlaton/nevertwice && cd nevertwice
python install.py

install.py detects your backend, prints what it chose, and wires Claude Code (Anthropic's terminal coding agent). Using something else? Cursor, Cline, Codex, and Zed connect through the MCP server or the watch daemon instead (INTEGRATIONS.md). Your next session starts with its memory already loaded. The five-minute walkthrough is in QUICKSTART.md.

Why not Mem0, Zep, or Letta? Those are a hosted service plus a vector database you ship your data to. Nevertwice is plain files on your disk that you can read, grep, and diff, and nothing leaves the machine by default. The honest, benchmarked comparison is further down.

Memory that acts

Every other memory system is a better library. It retrieves text and injects it into the prompt, taxing every single turn. We measured that axis to its end and found it is reader-bound and commoditizing: the LLM, not the memory, is the variable. So Nevertwice does something no other memory does. It treats memory as a set of token-budgeted interventions that stay silent until they have something worth saying.

  • Guards. A guard is a tiny pattern distilled from a past mistake, stored as one line in a JSON ledger (not your prompt). Before your agent writes code, the pattern is checked against the edit; on a match, a one-line warning fires, at zero context tokens until it does. Concrete: the mistake cursor.execute(f"SELECT ... '{name}'") becomes the guard execute\(\s*f["'], and the next time the agent reaches for an f-string SQL query it sees "past mistake: build SQL with query parameters, never an f-string." The design is Popperian: a guard is advisory until corroborated across sessions, retires itself after false positives, and is always overridable. Memory proposes, reality disposes, and the agent is never boxed in.
  • Anticipation. Predicts the failure your current plan is heading toward by resemblance to past ones, and surfaces one precise warning. Spend is proportional to risk, not paid per turn.
  • Counterfactual. "What breaks if I change X?" answered from an induced causal graph in a few lines rather than an episode dump, at about 7× fewer tokens than recalling every related note.

Every intervention is explainable (it cites the note it was born from), overridable in one line, and off by default where it could be noisy. A memory that acts must earn the right to.

These are measured on real tasks, with the harness to reproduce each one. The samples are small and run by one person; the point is that the harness is in the repo and the numbers are checkable, not that they are the last word.

claim result evidence
a fired guard changes a real model's output real error rate 0.36 → 0.05 (−86%) on DeepSeek (12 tasks × 8 trials) LIVE_VALIDATION.md
memory that acts vs always-injecting recalled text same error-prevention for ~31× fewer tokens ACTIVE_MEMORY.md
answer-accuracy on the standard benchmark 0.788 LongMemEval-oracle (open reasoner) QA_ACCURACY.md
retrieval vs the funded leaders R@5 0.80 › Mem0 0.76, one shared embedder COMPARISON.md

One honest caveat we measured rather than hid: the payoff scales with the agent's own capability. A strong model applies a delivered lesson and captures most of the benefit; a small 3B model captures about half. Memory removes the knowledge bottleneck, not the reasoning one (LIVE_VALIDATION.md).

All three interventions are on the Python API and the MCP server (Model Context Protocol, the open standard agents use to call tools), so this works on every agent: Claude Code, Cursor, Cline, Codex, Zed, and anything else that speaks MCP or writes session logs to disk (INTEGRATIONS.md).1 The moat isn't a better database. It's plain files you own, plus a memory that acts and costs almost nothing until it does.

Why Nevertwice

Nevertwice Mem0 / Zep / Letta / Cognee / memanto / Hindsight
Acts before the mistake ✅ guards + anticipation + counterfactual, 0 tokens until they fire ✗ retrieve-and-inject only (taxes every turn)
Runs your machine, local files a service, vector DB, or cloud (memanto: closed engine)
Store format human-readable Markdown + Git opaque DB rows and embeddings
Dependencies 0 Python packages (stdlib core), local Ollama for embeddings (or an optional cloud embedder) many, usually a server plus a DB
Your data leaves the machine? never by default (local embeddings; cloud embedder is opt-in) usually, via cloud APIs
Auto-capture ✅ native for Claude Code, always-on daemon for the rest manual API calls
Knowledge graph ✅ entity + typed-relation graph over the Markdown, traversable, no DB a separate graph database (Neo4j / FalkorDB)
Open in Obsidian ✅ it is your vault
Honest about what works ✅ we publish the negative results rarely

You own every byte of your agent's memory, and you can read it.

See it work

Nevertwice full tour: a guard fires before a recorded SQL-injection mistake repeats, then recall returns far fewer tokens than dumping the store (5.9x on this small demo project, and it grows with the store - 9.1x and up on a larger one), anticipation on a new endpoint, a counterfactual answered from the causal graph, and a contradiction resolved by supersession

Recorded from the real system (examples/guard_demo.py + examples/scenario_demo.py, throwaway vault) - every number on screen is measured live, nothing is mocked. The 5.9x recall saving shown is for this small demo project; it grows with the store (9.1x on the default, 44x at ~220 notes).

$ # session 1: you hit a CUDA OOM, Nevertwice quietly records the lesson
$ # ...days later, session 2, a fresh agent, new prompt:
$ python nevertwice/memory_search.py "training crashes out of gpu memory" myproject

⚠ 1 relevant lesson recalled (confidence 0.68):
  • [mistake] CUDA OOM at batch=64 on this GPU
    → lower batch size or enable gradient checkpointing; it recurred twice.

In Claude Code this happens automatically at session start and on each prompt. The agent simply already knows.

Review what it knows

Two read-only commands surface the store for a human or an agent, with no embedder, no LLM, and no network:

$ python -m nevertwice.digest --days 7      # what was added / revised this week, per project & type
$ python -m nevertwice.digest --conflicts   # the supersession ledger: every fact the memory revised

digest is the daily/weekly "what's new"; conflicts is the audit trail behind "contradictions don't pile up", pairing each retired note with the one that superseded it. Both are also nevertwice.api.digest() / nevertwice.api.conflicts() and MCP tools (memory_digest, memory_conflicts), so an agent can ask too.

Prefer a visual? One command writes a single self-contained HTML file (no server, no account, no external asset) that you open in a browser:

$ python -m nevertwice.dashboard --days 30      # → memory_dashboard.html, then opens it

It is a snapshot of the whole store (stats, per-project, recent, the contradiction ledger, top entities) that you can mail, commit, or read offline. The file is the UI, the same way the notes are the database, with no serve process to run. (For live editing, the vault opens in Obsidian as-is.)

How it works

  your session (any agent)
        │  Claude Code hook  ·  MCP call  ·  ingest.py  ·  watch daemon
        ▼
  extract → mistakes · patterns · decisions     (local Ollama, or one cloud key; secrets redacted)
        │  + a per-project "card" (status · stack · open gotchas · decisions)
        │  + local embeddings (bge-m3, multilingual)   + git auto-commit
        ▼
  Markdown + Git store   (open in Obsidian if you like)
        │  SessionStart     → inject the project card and the relevant lessons
        │  UserPromptSubmit → task-aware recall by the prompt text
        │  anytime          → memory_search "<query>"  ·  MCP  ·  CLI
        ▼
              the agent recollects

Retrieval is hybrid: semantic search over local embeddings, fused with lexical search, behind a calibrated abstention gate. A nonsense query gets back "no confident match" instead of a confident wrong answer, which matters more for a memory than chasing one extra point of recall. When a newer lesson contradicts an older one, supersession retires the old note (it moves to a Superseded/ folder, kept for history but out of the recall pool) so the agent only ever sees the current truth, and a fix links back to the bug it resolved.

Memory for any agent

Claude Code is the zero-config case. install.py wires five hooks (four for capture and recall, plus a PreToolUse guard that fires before a repeat mistake) and capture is automatic from then on, with nothing to configure.

Every other agent that writes its sessions to disk (Codex, Cline, Roo, Aider, Gemini CLI) is covered by nevertwice watch, a small stdlib polling daemon that finds the known log folders on your machine and mines finished sessions as they land. Start it once at login and forget it. The same engine also runs as a one-shot sweep if you prefer cron over a resident process.

If you call models from Python, wrap the client in one line with auto_capture(client) or decorate a chat function with @capture_chat. Any MCP client such as Cursor, Claude Desktop, or Zed can talk to nevertwice/mcp_server.py for search, remember, and ingest. LangChain and LlamaIndex get drop-in retriever and memory adapters. The agent can even write its own lessons through remember_lessons with no separate extraction model at all. Copy-paste recipes for each live in INTEGRATIONS.md. One honest caveat: Cursor and Windsurf keep their chat in a SQLite blob rather than plain files, so they need an export step before the watcher can read them.

Benchmarks

Same-stand LongMemEval-oracle R@5 bars: Nevertwice 0.826 with the opt-in cross-encoder and 0.802 with the shipped zero-dep fusion, ahead of Mem0 0.758 and LangMem and A-MEM at 0.692. Beside them the four numbers that matter: repeat-error rate -86% with a guard on, recall 9.1x leaner than dumping the store, 0 tokens until a guard fires, 85 ms full hook cost per tool call

External and reproducible, on LongMemEval-oracle (940 sessions in one shared store, 500 human-annotated questions, local bge-m3). Nevertwice's own numbers reproduce with the zero-dep core; the head-to-head against Mem0 / LangMem / A-MEM installs those competitors' own packages to run them on the same stand (their deps, not ours), and the dataset is fetched separately (research/data/README.md):

method R@1 R@5 R@10 MRR
semantic 0.42 0.65 0.73 0.53
lexical (BM25) 0.52 0.75 0.83 0.62
calibrated fusion (shipped default, 0 deps) 0.55 0.80 0.86 0.66
+ trained cross-encoder (opt-in) 0.61 0.83 0.86 0.71

The shipped ranker fuses the semantic and lexical signals with calibrated score fusion, which lifts R@5 from 0.66 under the rank fusion most systems ship to 0.80. The optional cross-encoder (bge-reranker-v2-m3, NEVERTWICE_XRERANK=1, [reranker] extra) then takes top-1 to 0.61. Reproduce with python research/longmem_eval.py [--xrerank] (the dataset is fetched separately).

The head-to-head, run locally and reported straight. On the same stand with the same local embedder for everyone, we ran Mem0, LangMem, and A-MEM end to end on Ollama, no paid key. Nevertwice leads every metric: R@5 0.80 against Mem0's 0.758, LangMem and A-MEM at 0.692, and top-1 0.55 (0.61 with the reranker) against Mem0's 0.478. The win is the fusion, not the embedder, which is identical for all four. We are careful about what is a moat: calibrated score fusion is classic retrieval, so the durable edge is the substrate (plain files, $0, local, no server), and we publish the full table plus what we tried and cut in COMPARISON.md and research/RETRIEVAL_FUSION.md.

Compare methodology, not headlines. Vendor posts quote LongMemEval scores from other protocols: answer accuracy with an LLM judge, oracle context handed to a reader, closed embedders, different question subsets. The tables above are retrieval R@k on one open stand with every variable pinned except the memory pipeline itself, and one command reruns the whole thing on the competitors' own packages (which records the exact versions it compared against). When a bigger number appears somewhere, first ask what it measures.

After retrieval: the axis that actually separates memory

Post-retrieval correctness: contradictions resolved at write time via supersession (competitors are ADD-only or manual); poisoning attacks blocked 88 percent with prompt-injection caught 100 percent and an honest 50 percent on plausible-false facts; a submodular forgetting coreset keeps 0.14 more topic coverage per token at a 20 percent budget; and we publish negative results such as consolidation-by-replacement halving recall, so we do not ship it

Here is the uncomfortable truth about memory benchmarks in 2026: retrieval R@k has stopped discriminating. Independent analysis finds that across LongMemEval, LoCoMo and peers, retrieval-miss dominates the error budget while retrieval-hit-but-wrong-answer is rare, so the headline scores mostly measure "did the right note come back" - and every serious system now scores high there. The gap that shows up in production (Mem0's own 91.6 on LoCoMo drops to ~49% effective at 50k sessions once stale data and contradictions enter) lives after retrieval: does the memory resolve contradictions, resist poisoning, and forget the right things?

That is the axis Nevertwice is built for, and every number is measured with a harness in research/:

  • Contradictions resolve at write time. A newer fact retires the older one to Superseded/, so recall only ever returns the current truth and the conflicts ledger keeps the audit trail. Most competitors are add-only or leave deletion to you (COMPARISON.md).
  • Poisoning defence, measured. 88% of memory-poisoning acceptance attacks blocked (precision 0.91), prompt-injection caught 100%, and - stated plainly because honesty is the point - only ~50% of plausible-false facts (research/POISONING.md).
  • Forgetting is a policy, not neglect. A submodular coreset keeps +0.14 more topic coverage than recency-sorting at a tight 20% retention budget, with less redundancy (research/FORGETTING.md).
  • We publish the negative results. Consolidating episodes by replacement halved downstream recall in our own test, so it is not shipped (research/CONSOLIDATION_EVAL.md).

Retrieval is table stakes; this is the moat, and it is the part a competitor cannot copy by swapping in a better embedder.

What we measured, and what we cut

Most memory projects pile on clever ranking and assume it helps. We built the clever parts, measured them on real data, and deleted the ones that lost, because a memory you cannot trust is worse than none.

A promptable LLM reranker actually lowered top-1 precision against the plain bi-encoder, so it is gone. We A/B tested four "stronger" local embedders and none beat bge-m3 at top-1, so the default is unchanged. Abstractive consolidation, the trick of summarising many notes into one principle, dropped real recall@3 from 0.82 to 0.35, because a general principle embeds away from the specific question that needs it, so it never shipped. The recurrence prior is a sound mechanism that stays dormant on a young single-user store, so it sits off the hot path. The one idea that earned its place was the trained cross-encoder, and we only learned which was which by measuring. The write-ups live in the research directory.

What is in the box

Everything here ships today, not on a roadmap:

  • Ask "what did we believe on March 3?" and bi-temporal queries answer from that day's truth.
  • A new fact that contradicts an old one retires it at write time; recall never serves both.
  • Recall walks [[wikilinks]] for multi-hop answers, abstains instead of guessing, and carries lessons across projects.
  • Secrets are redacted before anything is written. A poisoning guard caught every injection, exfiltration, and destruction attempt in the study; across the full acceptance-attack set it blocks 88% at precision 0.91 (details in research/POISONING.md).
  • A SQLite index keeps per-query cost flat into tens of thousands of notes; a submodular forgetting cap stops unbounded growth.
  • Sync between machines is git pull. Concurrent edits to the same note auto-merge field-by-field (recurrence takes the max, a retirement wins, tags union).
  • The project card travels: it exports to and imports from AGENTS.md and the Open Knowledge Format (OKF, the draft Google/Anthropic interchange spec), so other tools can read what yours knows.

An opt-in Brain layer turns the same captured sessions into a self-wiring knowledge graph for research or personal knowledge: typed entities (paper, method, dataset, benchmark, …), per-entity cards that roll up everything known about each across projects, a timeline of how your take on it evolved, and a graph-centrality salience signal. It is pull-only, read on demand and never injected, so the lean, token-bounded hot path is byte-for-byte unchanged when it is off (the default). Turn it on with NEVERTWICE_PROFILE=research (or general); see docs/BRAIN_LAYER_DESIGN.md.

Privacy

Embeddings run locally on Ollama by default, so nothing leaves the machine. If you would rather not run a local model, point NEVERTWICE_EMBED_PROVIDER at openai, voyage, cohere, or gemini with one key and recall goes through that instead. With no embedder at all, recall falls back to lexical full-text search rather than going dark. Extraction is local-first, and an optional cloud key (Cerebras, Groq, DeepSeek, or Gemini, all zero-retention) only ever speeds it up. Secrets are redacted before anything is written or sent. The store is yours, on your disk, under your git.

And there is no telemetry: no account, no usage pings, no phone-home. The only network calls are the ones you configured yourself (your Ollama endpoint, or your own cloud key), and NEVERTWICE_LOCAL_ONLY pins named projects to local-only for good.

Install

git clone https://github.com/DonPlaton/nevertwice && cd nevertwice
python install.py            # idempotent; backs up ~/.claude/settings.json before wiring hooks
python install.py --ollama   # also pull the local models (bge-m3 embedder + an extraction model)
python install.py --profile research   # turn on the opt-in Brain layer (research/general)
python install.py --print    # dry run, shows what it would do and writes nothing

The installer ends by printing your options: which profile is active and how to switch the Brain layer on (coding is the default; research/general add the knowledge graph), so a first run is self-explanatory.

For cloud extraction, copy .env.example to .env and add one key. With no key it uses local Ollama. To skip a local model for recall too, set NEVERTWICE_EMBED_PROVIDER with the matching key and run embed_index.py --rebuild once. With no backend at all, extraction pauses loudly (sessions are kept and retried, never dropped) and recall runs on lexical full-text search until an embedder shows up.

Projects you already have. Once the hooks are wired, every new session is captured automatically, and past Claude Code sessions backfill on the catch-up sweep with no action needed. To seed a rich context card for a large existing project right away instead of waiting for sessions to accumulate, point the bootstrapper at it: python -m nevertwice.bootstrap_contexts /path/to/project.

Tests

Thirty-seven suites, standard library only, LLM and embedder fully mocked. No network, no GPU:

for t in tests/_test_*.py tests/research/_test_*.py; do python "$t" || break; done

CI runs them on Linux, Windows, and macOS across Python 3.10, 3.12, and 3.13.

Docs

Quickstart · Architecture · Brain layer (opt-in) · Integrations · Configuration · Benchmarks · Comparison vs Mem0/Zep/Letta/A-MEM · Research, the honest eval lab · Security policy

Author and citation

Built by Platon Chernov. If Nevertwice helps your work or your research, a ⭐ is genuinely appreciated, and a citation is welcome; a CITATION.cff ships with the repo.

License

MIT, see LICENSE. Use it, fork it, build on it.

  1. Cursor and Windsurf keep their chat in a local SQLite blob rather than plain log files, so they need a one-time export step before the watch daemon can read them; the MCP path works for them with no export. Details in INTEGRATIONS.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nevertwice-2.1.0.tar.gz (235.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nevertwice-2.1.0-py3-none-any.whl (244.4 kB view details)

Uploaded Python 3

File details

Details for the file nevertwice-2.1.0.tar.gz.

File metadata

  • Download URL: nevertwice-2.1.0.tar.gz
  • Upload date:
  • Size: 235.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for nevertwice-2.1.0.tar.gz
Algorithm Hash digest
SHA256 cb1eff16c6c68057949afd351f2385f49a6e10ddcc7bff51fc877ee00dea333a
MD5 7e65da0e4a14700093a1c548011a7dfc
BLAKE2b-256 4faeab4f0ada72ca6aeac64b23a1be56f6a2f9e99b2bf6842f444b15d392bafe

See more details on using hashes here.

File details

Details for the file nevertwice-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: nevertwice-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 244.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for nevertwice-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 38489c1e2ab8c75e8cd3b912fb3858494cf6ed8f4eff42941e9a120b000953ca
MD5 fa6f753a3347aad1696efefb66db8e51
BLAKE2b-256 100140e50fc118abaa8e23670e268a2244da8877ccd147ced78473ed5a009021

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page