Engram:本地优先的开源 AI 记忆层
TushaeBXN/engram
Engram 是一个本地优先、开源(MIT)的 AI 记忆系统,把每次 AI 会话中的决策、调试和架构选择永久保存并可检索,冷启动上下文约 170 tokens。
The AI memory layer that never forgets.
Engram is a local-first, open-source AI memory system. It solves one problem: AI sessions end, but your work doesn't. Every decision, debug session, and architecture choice you've had with an AI disappears the moment the conversation closes. Engram makes it permanent, searchable, and retrievable in ~170 tokens.
Everything lives on your machine. No cloud. No API key required to run.
Web UI
pip install git+https://github.com/TushaeBXN/engram
engram ui # opens http://127.0.0.1:7741 in your browserA force-directed knowledge graph that maps every note and the connections between them — built into the package, no configuration needed.
[Engram Web UI]
- Knowledge graph — live force-directed view; hover any node for a preview card
[[Wikilinks]]— type[[to autocomplete note titles; links become graph edges instantly- Wing tabs — work / personal / ideas / journal, each with its own color and note count
- Tag filtering — click any
#tagchip to filter the notes list - Pin notes — float important notes to the top with a purple accent bar
- Daily journal — one click opens or creates today's dated entry
- Markdown editor — live preview, word count, ⌘S to save, ⌘N for a new note
- Export / Import — full JSON round-trip; nothing ever leaves your machine
Why Engram?
| Engram | Cloud memory tools | |
|---|---|---|
| Cold-start context | ~170 tokens | 500+ tokens |
| Install | One pip install (from GitHub) |
Docker + cloud signup |
| API key required | No | Yes |
| Data leaves your machine | Never | Always |
| Compression | ES shorthand for context (~1.6× on prose) | None |
| Open source | MIT | Proprietary |
Benchmark Targets
These are goals, not results. Only ES compression is measured today (python benchmarks/longmemeval_bench.py --compression-only); the LongMemEval and LoCoMo runners are still stubs.
| Benchmark | Metric | Target | Status |
|---|---|---|---|
| LongMemEval | Single-session QA | ≥ 0.68 F1 | Not yet implemented |
| LongMemEval | Multi-session QA | ≥ 0.61 F1 | Not yet implemented |
| LoCoMo | Entity recall | ≥ 0.72 | Not yet implemented |
| LoCoMo | Event recall | ≥ 0.69 | Not yet implemented |
| ES compression | Factual paragraphs | ≥ 1.5× | 1.6× measured |
| ES compression | Code-heavy content | ≥ 1.1× | 1.1× measured |
| ES compression | Mixed | ≥ 1.4× | 1.5× measured |
| Cold-start context | L0 + L1 tokens | ≤ 170 | Not yet measured |
| Search latency p99 | ChromaDB 100k | < 200ms | Not yet measured |
| Search latency p99 | FAISS 100k | < 50ms | Not yet measured |
Quick Start
Note: the
engrampackage on PyPI is an unrelated project. Install Engram from GitHub as shown below, not withpip install engram.
# Install (from GitHub; Engram is not on PyPI yet) pip install git+https://github.com/TushaeBXN/engram # Or with optional backends pip install "engram[faiss] @ git+https://github.com/TushaeBXN/engram" # FAISS speed backend pip install "engram[sqlitevec] @ git+https://github.com/TushaeBXN/engram" # zero-dependency fallback pip install "engram[viz] @ git+https://github.com/TushaeBXN/engram" # graph visualisation (matplotlib + networkx) pip install "engram[all] @ git+https://github.com/TushaeBXN/engram" # everything # Initialise your memory château engram init ~/myproject # Mine a project directory engram mine ~/myproject --wing myapp # Mine a conversation export engram mine ~/Downloads/claude-export --mode convos --wing myapp # Search engram search "auth migration decisions" --wing myapp # Answer a question grounded in memory (uses Ollama if available) engram answer "What did we decide about the auth strategy?" --wing myapp # Store a typed, validated memory engram remember-type "Always prefer float32 on CPU because bfloat16 is unsupported" \ instruction --wing myapp --confidence 0.95 # Load cold-start context (~170 tokens) engram wake-up
Memory Château Architecture
Wing (person or project)
└── Room (named topic: "auth-migration", "ci-pipeline")
├── Hall (memory type: facts | events | discoveries | preferences | advice)
│ ├── Closet (ES-compressed summary — fast AI read)
│ └── Drawer (verbatim original — never summarised)
└── Tunnel (cross-wing link when same room spans multiple wings)
Mined notes and conversation messages are sorted into halls by their content (e.g. "I prefer…" → preferences, "turns out the root cause…" → discoveries) using a local, rule-based classifier (engram/classifier.py). Code and config files keep their extension-based hall; when nothing matches clearly, the old extension/role default is used.
Memory Layers
| Layer | Content | Size | When Loaded |
|---|---|---|---|
| L0 | Identity — who is this AI? | ~50 tokens | Always |
| L1 | Critical facts in ES | ~120 tokens | Always |
| L2 | Room recall — current project | On demand | When topic arises |
| L3 | Deep semantic search | On demand | When explicitly queried |
Total cold-start context: ~170 tokens (L0 + L1 only).
Using with Claude via MCP
Start the MCP server:
python -m engram.mcp_server
Add to ~/.config/claude/claude_desktop_config.json:
{
"mcpServers": {
"engram": {
"command": "python",
"args": ["-m", "engram.mcp_server"]
}
}
}Claude will then have access to all 22 engram_* tools including engram_wake_up,
engram_search, engram_add_memory, engram_kg_add, engram_replay, and more.
See examples/mcp_setup.md for the full tool list.
Using with Local Models
Engram works entirely offline. The vector backends use local embeddings:
from engram.backends import get_backend from engram.palace import Palace from engram.searcher import Searcher palace = Palace() backend = get_backend("chromadb") # or "faiss" / "sqlitevec" searcher = Searcher(backend, palace) results = searcher.search("auth migration") for r in results: print(r["text"], r["final_score"])
No model API required. ChromaDB embeds locally using its bundled models.
Full CLI Reference
Setup
engram init <dir> # guided onboarding + ES bootstrap
Mining
engram mine <dir> # mine project files engram mine <dir> --mode convos # mine conversation exports engram mine <dir> --mode convos --wing myapp # tag with a wing engram mine <dir> --since 2026-01-01 # skip files older than date engram mine <dir> --plugin obsidian # use Obsidian vault plugin engram mine <dir> --plugin notion # Notion export engram mine <dir> --plugin linear # Linear issues export
Watch Mode
engram watch <dir> # auto-mine on file changes engram watch <dir> --wing myapp --mode convos # tag + conversation mode
Search
engram search "query" engram search "query" --wing myapp engram search "query" --room auth-migration engram search "query" --no-decay # disable recency weighting engram search "query" --results 20 # max results
Memory Stack
engram wake-up # L0 + L1 context dump (~170 tokens) engram wake-up --wing myapp # wing-scoped L1 engram wake-up --rebuild # rebuild L1 from drawers
Compression
engram compress # ES compress all closets engram compress --wing myapp # wing-scoped engram compress --wing myapp --room auth # room-scoped
Knowledge Graph
engram kg query "Kai" engram kg query "Kai" --all # include expired triples engram kg add "Kai" works_on "Orion" --from 2025-06-01 engram kg invalidate "Kai" works_on "Orion" --ended 2026-03-01 engram kg timeline "auth-migration"
Answer (LLM-grounded QA)
engram answer "What auth approach did we choose?" engram answer "What did we decide about the DB?" --wing myapp engram answer "Why did we drop Redis?" --model llama3.2 --chunks 8
Typed Memory
# Store a categorised, validated memory engram remember-type "Prefer SQLite for local dev" preference --wing myapp engram remember-type "Use float32 on CPU because bfloat16 unsupported" \ instruction --wing anthos --confidence 0.95 # List all 13 valid types engram remember-type --list
Provenance
engram provenance <drawer-id> # provenance record for one memory engram provenance <drawer-id> --history # full version chain engram provenance --summary # source counts across château
Graph Visualisation
pip install "engram[viz] @ git+https://github.com/TushaeBXN/engram" engram graph # all wings → memory_graph.png engram graph --wing myapp --output myapp.png # scoped to one wing
Maintenance
engram conflicts # interactive TUI conflict resolver engram audit # health check engram audit --fix # auto-resolve safe issues engram replay --room auth-migration # chronological room story engram replay --room auth-migration --wing myapp engram replay --room auth-migration --type decision # filter by type engram replay --room auth-migration --since 2026-06-01 # filter by date engram replay --room auth-migration --min-confidence 0.8 # filter by confidence engram status # château overview engram split <dir> # split concatenated transcripts engram split <dir> --dry-run
Configuration
~/.engram/config.json
{
"palace_path": "~/.engram/palace",
"vector_backend": "chromadb",
"decay_factor": 0.005,
"decay_max_days": 90,
"collection_name": "engram_drawers",
"people_map": {}
}| Key | Default | Description |
|---|---|---|
palace_path |
~/.engram/palace |
Root of the château filesystem |
vector_backend |
chromadb |
chromadb | faiss | sqlitevec |
decay_factor |
0.005 |
Recency boost per day: score * (1 + factor * days) |
decay_max_days |
90 |
Days after which decay levels off |
collection_name |
engram_drawers |
ChromaDB collection name |
ENGRAM_VECTOR_BACKEND overrides vector_backend for a single run without editing the file, e.g. ENGRAM_VECTOR_BACKEND=sqlitevec engram search "auth".
Troubleshooting: ChromaDB fails to load
ChromaDB 1.x ships compiled Rust bindings (chromadb_rust_bindings). If they don't match your Python or platform, Engram prints a ChromaDB failed to load message instead of starting. Fix it by reinstalling (pip install --force-reinstall --no-cache-dir chromadb) or by switching to the sqlitevec backend, which needs no compiled dependencies. Each backend keeps its own index, so re-run engram mine after switching.
~/.engram/identity.txt — plain text, becomes your L0 context.
~/.engram/wing_config.json — generated by engram init.
Module Reference
| File | Description |
|---|---|
engram/chateau.py |
Wing/Room/Hall/Closet/Drawer data model |
engram/config.py |
Config loading, ~/.engram/ management |
engram/shorthand.py |
Engram Shorthand (ES) compression dialect |
engram/knowledge_graph.py |
Temporal KG, SQLite backend |
engram/miner.py |
Project file ingest pipeline |
engram/convo_miner.py |
Conversation export ingest (Claude, ChatGPT, Slack) |
engram/searcher.py |
Semantic search + recency weighting |
engram/layers.py |
L0–L3 memory stack |
engram/watcher.py |
FSEvents/inotify watch mode |
engram/conflict.py |
Contradiction detection + TUI resolver |
engram/audit.py |
Memory health audit |
engram/replay.py |
Session/room replay |
engram/qa.py |
LLM-grounded QA over memory (Ollama + fallback) |
engram/typed_memory.py |
13-type typed memory with validation + ES storage |
engram/provenance.py |
Memory provenance and version-chain tracking |
engram/agents.py |
Specialist agent diary system |
engram/chateau_graph.py |
Room navigation graph |
engram/onboarding.py |
Guided init + ES bootstrap |
engram/cli.py |
Typer CLI entry point |
engram/mcp_server.py |
MCP server — 22 tools |
engram/backends/base.py |
Abstract VectorBackend interface |
engram/backends/chromadb_backend.py |
ChromaDB backend (default) |
engram/backends/faiss_backend.py |
FAISS backend (speed-optimised) |
engram/backends/sqlitevec_backend.py |
sqlite-vec backend (zero-dependency) |
engram/plugins/obsidian.py |
Obsidian vault plugin miner |
engram/plugins/notion.py |
Notion export plugin miner |
engram/plugins/linear.py |
Linear issues plugin miner |
engram/hooks/engram_save_hook.sh |
Claude Code auto-save hook |
engram/hooks/engram_precompact_hook.sh |
Claude Code pre-compact hook |
Engram Shorthand (ES)
ES is a compact shorthand that any LLM can read without a decoder. It is used for the context Engram loads into a model (L1 facts, closets); drawers always keep your original text. ES is lossy: filler words such as "the" and "that" are dropped, and decompress() only expands unambiguous symbols such as ∴ and →. Expect about 1.6× on prose and 1.1× on code.
from engram.shorthand import compress, decompress text = ( "The authentication module is a critical component that has a dependency " "on the database and is responsible for verifying user credentials." ) es = compress(text, confidence=4) # → "auth module=★★ component +dep on db&owns: verifying user credentials. [★★★★]" decompress(es) # → expands unambiguous symbols (∴, →, ¬ …) back to words # Code-aware compression code = "def authenticate(user: str, token: str) -> bool:" compress(code, is_code=True) # → "fn:authenticate(user: str,token: str)->bool" # Diff notation compress("+add_middleware()\n-manual_verify()", is_diff=True, diff_filename="auth.py") # → "CHANGE:auth.py add:add_middleware() rm:manual_verify()"
Recency Weighting
final_score = semantic_score × (1 + recency_boost)
recency_boost = decay_factor × max(0, decay_max_days − age_days)
Pinned drawers (engram_pin) bypass decay entirely.
Claude Code Hooks
Copy hooks to ~/.engram/hooks/ then add to ~/.claude/settings.json:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{"type": "command", "command": "~/.engram/hooks/engram_save_hook.sh"}]
}],
"PreCompact": [{
"hooks": [{"type": "command", "command": "~/.engram/hooks/engram_precompact_hook.sh"}]
}]
}
}Set ENGRAM_WING=myapp and ENGRAM_ROOM=current-task in your environment.
Requirements
- Python 3.9+
- chromadb ≥ 0.4.0
- typer ≥ 0.9.0
- rich ≥ 13.0.0
- watchdog ≥ 3.0.0
- questionary ≥ 2.0.0
- pyyaml ≥ 6.0
Optional:
faiss-cpu— FAISS backendsqlite-vec— sqlite-vec backendmatplotlib+networkx— graph visualisation (pip install "engram[viz] @ git+https://github.com/TushaeBXN/engram")requests— Ollama API calls forengram answer
No API key. No internet after install.
Contributing
- Fork the repo
pip install -e ".[dev]"pre-commit install- Run tests:
pytest tests/ -v - Submit a PR
License
MIT © 2026 Tushae Thomas
来源:GitHub · github.com

