Skip to main content

Local-first eternal memory engine for any LLM: conflict-aware claims, temporal validity, trust scoring, retrieval plasticity. Zero dependencies.

Project description

evermem

PyPI Python License: MIT GitHub

Local-first eternal memory for any LLM. Conflict-aware facts, temporal validity windows, trust scoring, and retrieval that learns from feedback. Pure Python stdlib, zero dependencies in the core, SQLite under the hood, your data never leaves your machine.

Install: pip install evermem-ai | Repo: github.com/alisa999000/evermem-ai | PyPI: pypi.org/project/evermem-ai

LLMs forget everything between sessions. Cloud memory services fix that by shipping your users' most personal data to someone else's API, and still get the hard parts wrong: they return facts that were contradicted weeks ago, add seconds of network latency to every turn, and break the moment you are offline. evermem runs entirely on your hardware and models memory as a lifecycle, not a pile of vectors:

  • Temporal validity - "lived in Minsk" isn't deleted when the user moves to Warsaw; it's superseded with a validity window. Recall returns the current fact, history is never lost.
  • Conflict awareness - contradictory facts are detected, surfaced to the LLM ("verify with the user"), and resolved by repetition and trust, not by last-write-wins.
  • Trust scoring - every claim carries trust that grows with confirmation and decays with contradiction.
  • Retrieval plasticity - recall paths that led to helpful answers are reinforced; noisy paths decay. Memory gets better the more you use it.
  • Four memory layers - working (recent turns), episodic (conversation episodes), semantic (stabilized claims), conflict (open contradictions) - modeled on how biological memory actually works.

No API keys. No Docker. No graph database to operate. One SQLite file.

Install

pip install evermem-ai            # core, zero dependencies
pip install "evermem-ai[pdf]"     # + PDF ingestion (pypdf)

The import name is evermem. Python 3.10+.

Quickstart

from evermem import EverMem

mem = EverMem("memory.db")  # rule-based extraction, no LLM needed

# Session 1
mem.observe("Меня зовут Алекс, я живу в Минске", session_id="s1")
mem.observe("I love black coffee", session_id="s1")

# Weeks later, a completely new session
pack = mem.recall("what do we know about the user?", session_id="s2")
print(pack.as_prompt())
# [MEMORY]
# Known facts (most relevant first):
# - user | name = алекс (trust 0.85, seen x1)
# - user | location = минске (trust 0.85, seen x1)
# - user | likes = black coffee (trust 0.75, seen x1)
# [/MEMORY]

mem.feedback(True, session_id="s2")  # reinforce what was useful

Inject pack.as_prompt() into any LLM's system prompt - OpenAI, Claude, or a 7B model running on your laptop. Use pack.as_prompt(budget_chars=4000) to hard-cap the pack size and keep prompts lean.

Working chat loops: examples/chat_ollama.py (fully offline) and examples/chat_openai.py (any OpenAI-compatible endpoint).

Documents: PDF, DOCX, HTML, Markdown

Feed files into the same memory; recall quotes the exact matching passages alongside conversation facts:

mem.observe_file("contract.pdf")            # needs evermem-ai[pdf]
mem.observe_file("meeting_notes.md")        # txt/md/docx/html: zero dependencies

pack = mem.recall("what is the monthly rent?")
# history now contains the matching document blocks (role "document")

Documents are split into paragraph-aligned blocks, embedded chunk by chunk and searched exactly like past conversation turns. DOCX and HTML parsing is stdlib-only.

Command line

Everything works from the terminal against the same database (~/.evermem/memory.db by default, override with --db or EVERMEM_DB):

evermem remember "we decided to ship v2 on March 3"
evermem import contract.pdf notes.md
evermem recall "when do we ship v2?"
evermem bootstrap        # session primer (call first in a new chat)
evermem profile          # everything known about the user, with trust and conflicts
evermem forget --subject user --predicate city   # invalidate a wrong fact
evermem correct user city "Warsaw"               # supersede with a correction
evermem aggregate "went to the gym"              # count matching sessions
evermem export backup.json                       # portable JSON backup
evermem stats            # database counters
evermem mcp              # run the MCP server

Add --model qwen2.5:7b to any command for LLM-powered fact extraction via Ollama, and --embed-model nomic-embed-text for better recall.

evermem Server (on-prem chat)

Web chat with streaming, memory sources, dark theme, PDF upload, and REST API. Runs fully on your hardware.

pip install "evermem-ai[server,pdf]"
ollama pull qwen2.5:7b && ollama pull nomic-embed-text
evermem-server   # http://127.0.0.1:8080

API: /api/chat, /api/chat/stream (SSE), /api/remember, /api/upload, /api/profile, /api/feedback.

Docker (server + Ollama): see server/README.md and docker/docker-compose.yml.

Rich extraction with a local LLM (Ollama)

from evermem import EverMem, OllamaLLM

mem = EverMem("memory.db", llm=OllamaLLM("qwen2.5:7b"))
mem.observe("кстати, мы с женой завели кота, назвали Барсик")
# -> user | has_pet = кот барсик

If the LLM is down, extraction silently falls back to deterministic rules. The engine never breaks.

Better recall with local embeddings (optional)

By default evermem uses built-in hash embeddings (zero downloads, runs anywhere). For noticeably better semantic recall, plug in any local embedding model via Ollama:

from evermem import EverMem, OllamaEmbedder

mem = EverMem("memory.db", embedder=OllamaEmbedder("nomic-embed-text"))

Any callable str -> list[float] works - sentence-transformers, llama.cpp, your own model. The store handles arbitrary dimensions automatically.

Plug into Cursor / Claude Desktop (MCP)

{
  "mcpServers": {
    "evermem": {
      "command": "evermem",
      "args": ["mcp"],
      "env": { "EVERMEM_DB": "C:/Users/you/.evermem/memory.db" }
    }
  }
}

Recommended agent flow (matches what production memory MCPs like memory-mcp teach):

  1. memory_initialize - session primer at the start of every chat
  2. memory_recall - before answering questions about the past
  3. memory_remember - after the user shares durable facts
  4. memory_feedback - when recall was helpful or wrong
  5. memory_forget / memory_correct - when a stored fact is poisoned or outdated

Also available: memory_aggregate (how many times...), memory_import (PDF/MD), memory_remember_fact (structured write), MCP resources memory://profile and memory://conflicts.

Set EVERMEM_MODEL and EVERMEM_EMBED_MODEL for local Ollama extraction and recall quality.

LangChain / LlamaIndex

pip install "evermem-ai[langchain]"    # or [llamaindex]
from evermem import EverMem
from evermem.integrations.langchain import EverMemChatHistory, EverMemRetriever

mem = EverMem("memory.db")
history = EverMemChatHistory(mem, session_id="app")
history.add_user_message("We ship v2 on March 3")
print(EverMemRetriever(mem, session_id="app").invoke("when do we ship?"))

How it works

observe(text)
  └─ extractor (LLM or rules) -> claims (subject, predicate, value, exclusive)
       └─ ClaimStore (SQLite)
            ├─ same value        -> reinforce: support+1, trust ↑
            ├─ exclusive change  -> supersede: validity window closes, history kept
            └─ coexisting values -> open conflict, trust competition

recall(query)
  └─ score = 0.55·semantic + 0.15·recency + 0.20·trust + 0.10·learned_paths
       └─ MemoryPack: facts + contradictions + history timeline + episodes + recent turns

feedback(helpful)
  └─ plasticity: reward/decay retrieval paths; adjust claim trust

Embeddings are deterministic hash vectors (token stems + char trigrams) - robust to Russian/English morphology and typos, no model download required. The embeddings module is swappable for real embedding models.

Why not just RAG?

RAG retrieves documents. Memory needs lifecycle: facts change, contradict each other, gain and lose credibility, and must be forgotten or superseded - not appended forever. A pure vector store will happily return "works at Acme" months after the user said they quit, because semantic similarity knows nothing about time. evermem models that lifecycle explicitly.

Comparison

evermem Mem0 Zep / Graphiti plain RAG
Runs fully offline yes no (LLM API for extraction) no depends
Setup pip install, one file SDK + LLM key Docker + graph DB DIY
Supersede / validity windows yes partial yes (temporal graph) no
Conflict surfacing to the LLM yes no no no
Learns from feedback yes no no no
Recall latency ~0.1 s local seconds (cloud) seconds (cloud) varies
Hardware floor any CPU, even no ML model cloud or GPU server GPU for embeddings
License MIT Apache 2.0 (cloud paid) cloud / enterprise -

Honest scope: Mem0 and Zep are managed platforms with SDK ecosystems and dashboards; evermem is an engine you embed. If you want zero cloud, zero dependencies and memory lifecycle done right, that trade is the point.

Performance

Latency on a plain CPU, zero-dependency mode (python bench/latency.py):

store size observe (p50) recall (p50) recall (p95)
2,000 turns 1.3 ms 103 ms 235 ms
10,000 turns 5.1 ms 346 ms 536 ms

Writes never block on a network call. For comparison, independent 2026 reviews measure cloud memory services at roughly 4 s (Zep) and 7 s (Mem0) per recall round-trip.

Benchmarks (LongMemEval)

Measured on longmemeval-cleaned with a fully local stack: nomic-embed-text embeddings + qwen2.5:7b reader/judge via Ollama. No cloud, no API keys.

Metric oracle (evidence only, n=500) _s (~40 distractor sessions, n=100)
Evidence session recall 99.8% 96.3%
QA accuracy (local 7B reader) 58.7% 51.1%
Answer presence in pack 44.7% 51.1%

Retrieval is essentially solved by the memory layer (96-100% evidence recall); the reader model sets the ceiling. Best types on the haystack: knowledge-update 85.7% (temporal validity windows at work), single-session-preference 66.7%, single-session-user 61.5%.

For reference: Zep reports 63.8% on LongMemEval with a GPT-4o reader in the cloud. evermem reaches 51.1% with a 7B model that runs on a $300 GPU - a different point on the cost/privacy curve, fully offline. The pack hands the reader a dated timeline with pre-computed day gaps, which alone lifted temporal-reasoning QA from 4% to 40-52%.

Zero-dependency mode (hash embeddings, no Ollama at all) still achieves 71% evidence recall on the haystack - enough for edge devices where no embedding model fits.

python bench/run_longmemeval.py --data bench/data/longmemeval_s.json \
  --embed-model nomic-embed-text --qa-model qwen2.5:7b --every 5 --report bench/report_s_v3.json
python bench/analyze_errors.py --report bench/report_s_v3.json --data bench/data/longmemeval_s.json

Full runbook: bench/README.md.

FAQ

Does it need an internet connection or API key? No. The core runs on the Python standard library alone. Ollama integration is optional and also local.

Multiple users on one database? Yes: every API call takes user_id, memories are strictly isolated per user.

How do I delete a user's data (GDPR)? Keep one database file per user and delete the file: erasure is then physical and provable, which is exactly what regulators want from on-device storage.

What about non-English text? The hash embedder handles Russian and English morphology out of the box; rule extraction covers both languages. Any other language works through an Ollama embedder and LLM extractor.

Can I use my own vector model / store? Embeddings are any str -> list[float] callable. The storage layer is a single SQLite file you can inspect with any SQLite client.

Will it slow my agent down? Recall is a local SQLite query plus vector scan: ~0.1 s at 2k turns on CPU, no network round-trip. observe is a few milliseconds and can run after the response is sent.

Status & roadmap

  • Claim store with validity windows, conflicts, trust
  • Retrieval plasticity (learning from feedback)
  • LLM extraction (Ollama / OpenAI-compatible) with rule fallback
  • Pluggable embeddings (hash zero-dep default, Ollama backend, any callable)
  • Chunk-level turn search + dated timeline with pre-computed day gaps
  • Document ingestion: PDF, DOCX, HTML, Markdown, plain text
  • Memory lifecycle: forget, correct, purge (GDPR), provenance (source session/turn)
  • Session primer (bootstrap / memory_initialize) with stale-fact warnings
  • Multi-session aggregation (aggregate / memory_aggregate)
  • MCP: 10 tools + 2 resources, embed model, budget_chars, feedback loop
  • CLI: remember / recall / import / bootstrap / forget / correct / export / mcp
  • MCP server (memory for Cursor / Claude Desktop in one config line)
  • LongMemEval harness: retrieval metrics + QA stage (local reader + judge) + error analyzer
  • Multi-session: entity counters at ingest + distinct-item counts in recall
  • Temporal: chronological order block for which-first questions
  • Preferences: boosted in recall for recommend/suggest questions
  • Episode summarization (rule fallback; LLM when Ollama configured)
  • LangChain / LlamaIndex adapters (pip install "evermem-ai[langchain]")
  • Memory events, assistant-turn extraction, query router (0.3.0)
  • evermem Server: FastAPI + web UI + upload + Docker (0.4.0)
  • Context compression benchmark: raw history vs MemoryPack
  • Encrypted sync between devices (planned)

Development

pip install -e ".[dev]"
pytest -q          # 80 tests, no network needed
python demo.py     # offline end-to-end scenario

MIT License.

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

evermem_ai-0.4.1.tar.gz (172.9 kB view details)

Uploaded Source

Built Distribution

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

evermem_ai-0.4.1-py3-none-any.whl (162.5 kB view details)

Uploaded Python 3

File details

Details for the file evermem_ai-0.4.1.tar.gz.

File metadata

  • Download URL: evermem_ai-0.4.1.tar.gz
  • Upload date:
  • Size: 172.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for evermem_ai-0.4.1.tar.gz
Algorithm Hash digest
SHA256 2cdd59511d1c2ccf1c57a6ef41994cb8602f459c9a741c249e2d0c68ad21c75f
MD5 9d8b732aa08ebd06b79fdbcc63542184
BLAKE2b-256 9fa19c76bcd7c95280f1c015b1970937d595de0fddb3d035ab6f2e7c58ff603d

See more details on using hashes here.

File details

Details for the file evermem_ai-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: evermem_ai-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 162.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for evermem_ai-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4e04407b9f9c909469c695028f258edd39a5a749f251ba5dae1408682eb5dadd
MD5 d7ffa39914c97a94f08365195d739234
BLAKE2b-256 8d5a56725dab1fbc7f4c8c3cf99051d81108b14ada7d09bcffc47b065d1d9975

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