Skip to main content
Glama

engram

The memory engine that forgets.

Every agent memory system ever shipped has the same bug: it never forgets. They hoard every trace forever, then wonder why context rots, tokens bleed, stale facts override fresh ones, and the "memory" of a 3-month-old agent is a landfill.

The only general intelligence we know of — the human brain — runs on forgetting. You remember the gist of ten thousand breakfasts, not the pixels. Forgetting isn't a failure of memory. It's the compression strategy that makes memory work.

engram is a long-term memory layer for AI agents built on that principle:

Mechanism

Borrowed from

What it does

Ebbinghaus decay

Forgetting curve (1885)

Every trace fades unless used: R(t) = exp(-t / S)

Spaced reinforcement

Spacing effect, reconsolidation

Every successful recall() strengthens the trace — use it or lose it

Sleep-time consolidation

Hippocampal replay

dream() merges duplicates, distills repeated episodes into semantic gists, rewires associations, dissolves the dead

Local-first SQLite. Zero required dependencies. MCP-native. One file you own.

from engram import Memory

mem = Memory("./brain.db")

mem.remember("user is allergic to peanuts", salience=0.8)
mem.remember("had pho for breakfast", salience=0.3)

mem.recall("what should I cook?")   # retrieval also REINFORCES the winners
mem.dream()                          # sleep: compress the day, drop the noise
mem.forget(query="breakfast")        # deliberate, immediate erasure

Six months later: the allergy is one tool-call away (the agent kept touching it). The breakfasts are gone. Your prompt stays 70 tokens, not 3,000.


Why forgetting is the feature

The agent tax. Memory engines that keep everything pay for everything, every turn. A transcript-dumping agent carries months of stale context into every single call. In our 120-day synthetic benchmark, engram's per-query context cost is 2.3% of the full transcript — with 8–10/10 exam hit-rate on facts the agent actually used.

Context rot. A memory store that never forgets degrades: duplicates accumulate, old states shadow new ones ("user lives in Hanoi" and "user lives in Saigon"), and retrieval quality decays as the index fills with dead weight. Forgetting is garbage collection for cognition.

Use it or lose it. Memories an agent keeps retrieving get exponentially more durable (stability compounds per recall — from ~4 days at birth to years after a handful of spaced uses). Memories nobody touches fade on an Ebbinghaus curve and are swept out of the file at the next dream. The memory becomes what the agent's life actually is — no manual curation, no TTL configs, no cron jobs to prune the past.

Privacy that compounds. Data you stop using doesn't linger: it decays and dissolves. The retention surface of a running agent shrinks by itself. And when the user says forget it — forget() is immediate, total, row-level deletion. Not "archived." Gone.

Related MCP server: mnemosyne

Install

pip install engram-ai            # core: pure stdlib, no dependencies
pip install "engram-ai[mcp]"     # + the MCP server for Claude/OpenClaw/Cursor/…

Python ≥ 3.10. The brain is one SQLite file — back it up, copy it, inspect it with the sqlite3 CLI, rm it.

The 60-second tour

from engram import Clock, Memory

# a virtual clock lets you time-travel a brain (great for tests & demos)
clock = Clock(virtual=True)
mem = Memory.in_memory(clock=clock)

used   = mem.remember("user is allergic to peanuts", salience=0.8)
unused = mem.remember("printer on floor 3 jams on wednesdays", salience=0.4)

# use the allergy on a spaced schedule; ignore the printer
for gap in (2, 5, 10, 20):
    clock.jump(days=gap)
    mem.recall("peanut allergy", k=1)

clock.jump(days=60)   # two quiet months
print(used.retention(clock.now()))    # 0.97 — solid
print(unused.retention(clock.now()))  # 0.00 — gone

Run the full visual version: python examples/forgetting.py

day   used-memory R        unused-memory R
  0   ############################ 100%    ############################ 100%
 10   #######################       82%    #                              2%
 35   ###########################   95%                                   0%
 60   ###########################   97%                                   0%

dream(): sleep-time consolidation

>>> mem.dream()
dream complete: scanned 10 traces
  merged 2 duplicates
  distilled 1 gists from 3 episodes
  formed 1 new associations
  dissolved 0 traces past the forgetting floor
  new knowledge: had pho for breakfast again
net trace change overnight: -4

Ten messy notes from one day become six clean traces: duplicates fused, four breakfast episodes distilled into one semantic gist carrying their combined stability, related facts linked for future spreading activation. No LLM involved — the default dream is deterministic, offline, auditable. (Bring your own model to write prettier gists; the bookkeeping is identical.)

context(): memory as a prompt block

>>> print(mem.context("what should I know about the user?", k=3))
<memory>
- (2026-10-02) [core] user's name is Hieu
- (2026-10-02) user is allergic to peanuts
- (2026-10-02) user prefers concise bullet-point answers
</memory>

Drop it in the system prompt. Fading traces rank lower automatically — a memory's accessibility is part of its retrieval score, just like a tip-of-the-tongue fact that takes a specific cue to surface.

MCP: memory for any agent

engram ships as a first-class MCP server. One command, any client:

// Claude Code / OpenClaw / Cursor / any MCP client
{
  "mcpServers": {
    "memory": {
      "command": "engram",
      "args": ["serve"]
    }
  }
}

The agent gets six tools — remember, recall, context, forget, dream, stats — with docstrings that teach it when to use each one (store durable facts, recall at task start, dream when idle, forget on request). Because retrieval reconsolidates, an agent that uses its memory automatically maintains it. That's the whole trick.

CLI

$ engram remember "user's name is Hieu" --kind core --salience 0.9
$ engram recall "who is allergic to peanuts?"
$ engram context "plan a dinner"          # prompt-ready block
$ engram dream
$ engram stats                            # counts, decay state, token story
$ engram forget --query "flight numbers"  # GDPR-grade erasure
$ engram export brain.json                # your memory, your file

Benchmark

Synthetic but honest: an agent lives 120 days, writes 370 memories (10 durable profile facts + daily noise), uses its memory organically ~360 times, sleeps on it, then takes an exam. Deterministic — same seed, same numbers. benchmark/run.py

memories written            370
organic recall calls        358
night: merged 20  gisted 60  dissolved 106
traces in the brain         24 (from 370 written)
profile knowledge alive     8/10 (trace or gist)
most-used fact stability    1826 days (born at ~4)
exam hit-rate@5             8/10
avg context per query       70 tokens
full transcript dump        3078 tokens/query
prompt cost vs transcript   2.3%

94% of the noise is compressed away; the used knowledge is all there — as raw traces or distilled gists — for 2.3% of the token cost. Try --seed 42 for a 10/10 run.

How it works

remember() ──► engram trace ──► SQLite (single file you own)
                 │  content, kind, salience
                 │  stability S          ◄── ratchet: grows on every recall
                 │  retention = e^(−t/S) ◄── Ebbinghaus, computed live
                 ▼
recall() ──►  score = √BM25 · + vec · + Hebbian spread ) × retention^0.35
                 │                     lexical   optional  association
                 └──► winners reconsolidated (S ↑) + co-fired pairs wired (Hebb)

dream() ──►  1. dissolve  (R < 0.02: delete, rewire surviving links)
             2. merge     (near-duplicates fuse, stability fuse)
             3. gist      (3+ similar episodes → one semantic trace)
             4. associate (related traces get weak links)
  • Retrieval is hybrid: BM25 over lightly-stemmed tokens + character trigrams (typo/morphology tolerant, any language incl. CJK), optional vector axis (plug any embedding function; the default is a zero-dependency hashing embedder), and spreading activation through Hebbian links — memories recalled together become associated, so the graph self-organizes into a semantic network with use.

  • No cliff, only a slope: faded memories are demoted in ranking but never hidden — a specific cue can still rescue a fading trace (that's the reconsolidation rescue), preventing the rich-get-richer death spiral of naive decay systems.

  • Anti-cramming: recalls spaced a sliver apart barely count; a near-dead trace cannot bank time it wasn't intact. The stability ratchet is honest.

  • Kinds: episodic (events, the default), semantic (facts), core (identity — near-permanent, exempt from dissolution).

  • Time is injectable: Clock(virtual=True) makes every decay decision deterministic and testable. This is why the whole system is testable — the test suite time-travels a decade in milliseconds.

Design principles

  1. Local-first, forever. One SQLite file. No server required, no cloud, no telemetry. Your agent's memory is yours — exportable, inspectable, deletable.

  2. Zero required dependencies. The core is pure stdlib. The default embedder is deterministic feature hashing — no model downloads, works offline, any language. Want real embeddings? Memory(embedder=my_fn). Want a server? Memory behind FastAPI is 20 lines (see roadmap).

  3. Honest no-LLM defaults. dream() distills gists with deterministic clustering, not a hidden API call. Everything is auditable. Swap in an LLM for prettier gists when you want — it's a hook, not a dependency.

  4. Forgetting is policy, not loss. Decay, dissolution and erasure are explicit, inspectable mechanisms — with stats() reporting exactly what the mind holds, what faded, and what the night swept away.

Compared to other agent memory engines

keeps everything

forgetting model

sleep consolidation

deps

storage

engram

no — use it or lose it

Ebbinghaus + spaced reinforcement

dream() built-in

0

SQLite file

vector-dump engines

yes

none

—

heavy

server + vector DB

extractive memory (Mem0-style)

mostly

manual TTL/pruning

background extraction (LLM)

LLM required

service

graph memory (Zep/Letta-style)

yes

none

incremental graph updates

heavy

graph DB/service

Those projects solve retrieval at scale; engram solves the lifecycle of memory. They compose well — plug a real embedder into engram, or run engram beside a big store as the decay-and-consolidation layer. We think forgetting is the missing half of every one of them.

Roadmap

  • pip install engram-ai[server] — FastAPI/REST wrapper with multi-agent brains

  • LLM-backed gists as an optional DreamConfig(summarizer=...) hook

  • review() — retrieval-practice scheduler ("what's about to fade?") for agents that want to actively study their own memory

  • sqlite-vec / FTS5 accelerators for very large brains

  • WASM build for in-browser agents

Development

pip install -e .[dev]
pytest -q                  # 80+ tests, all time-travelling
ruff check .
python benchmark/run.py    # deterministic benchmark

License

MIT — © HalisAI. Toward AGI, one forgetting curve at a time.

engram (n.) — the physical trace a memory leaves in a brain. Coined by Richard Semon, 1904.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables agents to persist, search, and manage short- and long-term memories using local SQLite storage and offline embeddings, with tools for recall, update, confirmation, and consolidation without external services.
    10 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to manage a local-first, zero-cloud lifelong memory with 33 tools for adding, recalling, searching, consolidating, forgetting memories, traversing knowledge graphs, and checking sync/health status.
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Provides AI agents with a persistent long-term memory over a single SQLite file, letting them write, screen, consolidate, and recall notes across sessions without any generative LLM in the loop. Recall judges relevance, follows links between notes, and signals when memory is insufficient, so agents get one to three useful facts per question instead of a generic top-k list.
    11
    43 PyPI
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Gives AI agents a local-first, persistent memory backed by a single SQLite file, letting them save decisions, preferences, and facts, then recall them by meaning or keyword across sessions and projects. Exposes tools for loading pinned context, searching, adding, updating, listing, and deleting memories, so agents stop forgetting between sessions.
    15 npm
    1
    Apache 2.0