Engram AI 🧠
Neuroscience-grounded memory for AI agents — ACT-R activation, Hebbian learning, cognitive consolidation
Give your AI agent a brain that actually remembers, associates, and forgets like a human.
Available in 3 runtimes:
| Runtime | Package | Use When |
|---|---|---|
| 🐍 Python | engramai on PyPI |
Python agents, MCP server, Claude Desktop |
| 🦀 Rust | engramai on crates.io — GitHub |
Performance-critical, embedded, zero-dependency |
| 📦 TypeScript | engram-ts/ |
Node.js agents, OpenClaw |
| 🔌 OpenClaw Plugin | openclaw-plugin/ |
Drop-in replacement for OpenClaw's default context engine |
What is Engram?
Most AI agents use a dumb FIFO window for context — keep the last N messages, throw away the rest. Engram replaces this with a cognitive memory system based on how human brains actually work:
- 🧠 ACT-R Activation — Memories strengthen with use, decay with time (not a fixed window)
- 🔗 Hebbian Learning — "Neurons that fire together, wire together" — related memories auto-associate
- 💤 Consolidation — Periodic forgetting + strengthening cycles (like sleep)
- 🎯 Working Memory — Miller's Law 7±2 chunks, automatic topic-change detection
- 🌍 Cross-Language Search — Recall memories across 50+ languages
- 💰 Zero Cost — Heuristic capture + prompt caching = $0 additional spend
🔌 OpenClaw Context Engine Plugin
The fastest way to use Engram — replace OpenClaw's default FIFO context with cognitive scoring in one config line:
# openclaw.yaml
plugins:
slots:
contextEngine: engram
entries:
engram:
autoCapture: true
Instead of keeping the last N messages, Engram scores every message by ACT-R activation × Hebbian association × content importance, then packs the most cognitively relevant ones into the token budget. Long-term memories persist across sessions automatically.
| Default (Legacy) | Engram | |
|---|---|---|
| Strategy | Keep last N messages (FIFO) | Score by cognitive relevance |
| Long-term memory | None | ACT-R + Hebbian |
| Cross-session | Compaction summaries (LLM cost) | Persistent recall (zero cost) |
| Topic awareness | None | Working memory + topic detection |
| Auto-capture | None | Preferences, facts, decisions, corrections |
| Cost | LLM summarization tokens | Zero (heuristic) |
🏆 Battle-Tested in Production
Real numbers from a live AI agent running 24/7:
| Metric | Value |
|---|---|
| Memories stored | 3,846 |
| Recalls served | 230,103 |
| Hebbian links formed | 12,510 (automatic) |
| Consolidation layers | 320 working → 224 core → 3,302 archive |
| Database size | 48 MB |
| Recall latency | ~90ms |
| Additional cost | $0 (prompt caching absorbs overhead) |
Quick Start
Python
pip install engramai
from engram import Memory
memory = Memory("./my-agent.db")
# Store
memory.add("User prefers detailed explanations", type="relational", importance=0.8)
memory.add("Project deadline: Feb 10", type="factual")
# Recall (ACT-R activation + Hebbian association + semantic similarity)
results = memory.recall("user preferences", limit=5)
# Consolidate (Ebbinghaus forgetting + strengthening)
memory.consolidate(days=1.0)
TypeScript
import { Memory } from 'neuromemory-ai';
const memory = new Memory('./my-agent.db');
memory.add("User prefers TypeScript over JavaScript", { type: "preference", importance: 0.8 });
const results = memory.recall("user language preferences", { limit: 5 });
Rust
use engramai::Memory;
let mut memory = Memory::new("./my-agent.db", None)?;
memory.add("User prefers Rust for systems programming", "preference", 0.8, None)?;
let results = memory.recall("user preferences", 5, None, None)?;
MCP Server (Claude Desktop, etc.)
export ENGRAM_DB_PATH=./my-agent.db
python3 -m engram.mcp_server
🆕 Engram v2: Multi-Agent Intelligence
Engram v2 adds powerful features for building multi-agent systems with shared memory, emotional feedback, and cross-agent intelligence:
🔐 Namespace Isolation & ACL
Separate memory spaces for different agents/domains with fine-grained access control:
from engram import Memory
from engram.acl import Permission
memory = Memory("./shared.db")
memory.set_agent_id("trading_agent")
# Store in namespace
memory.add_to_namespace(
"Oil prices spiked 15%",
type="factual",
importance=0.9,
namespace="trading"
)
# ACL: Grant read permission to another agent
memory.grant("ceo_agent", "trading", Permission.READ)
# Subscribe to high-importance events
memory.subscribe("ceo_agent", "*", min_importance=0.8)
# Check for notifications
notifications = memory.check_notifications("ceo_agent")
# → [{memory_id: "...", namespace: "trading", content: "Oil prices...", importance: 0.9}]
Use cases:
- CEO pattern — Supervisor agent monitors specialist agents' discoveries
- Team collaboration — Agents share knowledge in topic-specific namespaces
- Privacy isolation — Sensitive memories stay in restricted namespaces
🎭 Emotional Bus — Memory ↔ Personality Feedback Loop
The Emotional Bus connects memory to agent workspace files (SOUL.md, HEARTBEAT.md), creating a closed-loop between what the agent experiences and how it evolves:
from engram import Memory
from engram.bus import EmotionalBus
memory = Memory.with_emotional_bus(
db_path="./agent.db",
workspace_dir="./workspace"
)
# Store memory with emotional tracking
memory.add_with_emotion(
"Debugging session took 3 hours with no progress",
type="episodic",
emotion=-0.8, # Negative experience
domain="debugging"
)
# Bus accumulates emotional trends
bus = memory.emotional_bus()
trends = bus.get_trends()
# → [EmotionalTrend(domain="debugging", valence=-0.75, count=5)]
# Suggest SOUL updates based on patterns
suggestions = bus.suggest_soul_updates()
# → [SoulUpdate(domain="debugging", action="add drive",
# content="Avoid lengthy debugging sessions without breaks")]
# Drive alignment boosts importance
# Memory matching SOUL drives gets automatic importance boost
bus.drives # → [Drive(name="curiosity", description="...")]
Workspace files:
SOUL.md — Core drives/values:
# Core Drives
curiosity: Always seek to understand new things
efficiency: Prefer action over endless discussion
HEARTBEAT.md — Periodic tasks:
- [ ] Check email
- [x] Run consolidation
How it works:
- Memory → SOUL: Negative emotional patterns trigger drive suggestions
- SOUL → Memory: Memories aligned with drives get importance boost
- Behavior → HEARTBEAT: Failed actions get deprioritization suggestions
- HEARTBEAT → Behavior: Successful patterns get reinforced
Use cases:
- Self-improving agents — Personality evolves from experience
- Emotional coherence — Agent behavior aligns with "values"
- Adaptive task scheduling — HEARTBEAT learns what works
🌐 Cross-Namespace Intelligence
Hebbian links can span namespaces, enabling cross-domain insights:
# Recall with cross-namespace associations
result = memory.recall_with_associations(
"market volatility",
namespace="*", # Search all namespaces
limit=5
)
# Returns both memories + cross-links
for link in result.cross_links:
print(f"{link.source_ns}:{link.source_id} → {link.target_ns}:{link.target_id}")
# trading:abc123 → geopolitics:def456 (strength: 0.85)
Discovery pattern:
# Find connections between two domains
links = memory.discover_cross_links("trading", "geopolitics")
# → Reveals how trading events correlate with political events
🆕 v2.1.0: LLM Extraction & Hybrid Search
🤖 LLM-Powered Memory Extraction
Instead of storing raw conversation text, extract key facts automatically:
from engram import Memory, AnthropicExtractor
memory = Memory("./agent.db")
# Option 1: Auto-configure from environment
# Just set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN and it works automatically
# Option 2: Explicit setup
memory.set_extractor(AnthropicExtractor(api_key="sk-ant-..."))
# Now add() extracts facts automatically
memory.add("I had pizza yesterday and it was great, but my girlfriend didn't like it")
# Stores two separate facts:
# 1. "User likes pizza" (relational, importance 0.6)
# 2. "User's girlfriend doesn't like pizza" (relational, importance 0.6)
Why it matters:
- Better recall: Search for "user food preferences" finds "pizza" even if the word "preference" wasn't in the original text
- Cleaner memory: Facts are normalized, not duplicated across conversations
- Cost-effective: Uses Claude Haiku (~$0.0001 per memory) or local Ollama models (free)
🔧 Config Hierarchy
Engram now supports layered configuration with clear priority:
| Priority | Source | Use Case |
|---|---|---|
| 1. Code | memory.set_extractor(...) |
Agent harnesses (RustClaw, etc.) |
| 2. Env vars | ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY |
Local dev, Docker |
| 3. Config file | ~/.config/engram/config.json |
User preferences |
| 4. No extractor | Falls back to raw text storage | Backward compatible |
# Initialize config interactively
python3 -m engram init
Config file (~/.config/engram/config.json):
{
"embedding": {
"provider": "ollama",
"model": "nomic-embed-text"
},
"extractor": {
"provider": "anthropic",
"model": "claude-haiku-4-5-20251001"
}
}
⚠️ Security: Never store API keys in config files. Use environment variables.
🎯 Hybrid Search (FTS + Embedding + ACT-R)
recall() now uses triple scoring by default:
results = memory.recall("user preferences", limit=5)
# Automatically combines:
# 15% FTS (exact term matching)
# 60% Embedding (semantic similarity)
# 25% ACT-R (recency/frequency/importance)
Why three signals?
- FTS: Catches exact matches (project names, technical terms)
- Embedding: Catches semantically similar concepts ("preference" ≈ "like")
- ACT-R: Prioritizes recently/frequently accessed memories
Configurable weights (Rust crate only, Python coming soon):
let mut config = MemoryConfig::default();
config.fts_weight = 0.30; // 30% exact matching
config.embedding_weight = 0.50; // 50% semantic
config.actr_weight = 0.20; // 20% temporal
🈶 CJK Tokenization (Rust only, Python coming soon)
Chinese/Japanese/Korean text now gets intelligent word segmentation via jieba:
❌ Before:
"engram是认知记忆系统" → split into 8 characters
Search "记忆系统" matches poorly
✅ After (with jieba):
"engram是认知记忆系统" → ["engram", "是", "认知", "记忆系统"]
Search "记忆系统" matches precisely
Performance impact: Negligible (~0.02ms per memory vs ~50ms for embedding generation)
Core Concepts
🧠 ACT-R Activation
Every memory has an activation level that decays over time but strengthens with each access:
activation = base_level + spreading + importance_boost
base_level = ln(Σ tᵢ^(-d)) # frequency × recency decay
spreading = Σ wⱼ × Sⱼᵢ # context similarity
This means frequently-accessed, recent memories surface first — but old important memories can still be recalled if they're relevant to the current context.
🔗 Hebbian Learning
Memories that are recalled together form automatic associations:
ΔW = η × aᵢ × aⱼ # co-activation strengthens links
Ask about "Docker" and "deployment" in the same conversation → they become linked. Next time you ask about deployment, Docker memories get boosted automatically.
💤 Consolidation
Like human sleep, periodic consolidation:
- Decays weak memories (Ebbinghaus forgetting curve)
- Strengthens frequently-used ones (move working → core → long-term)
- Prunes noise (below-threshold memories removed)
🎯 Working Memory (TypeScript / OpenClaw Plugin)
Session-level state based on Miller's Law (7±2 chunks):
- Tracks what's "active" in the current conversation
- Detects topic changes → triggers full recall
- Continuous topic → reuses cached memories (70-80% fewer DB queries)
🧩 Memory Types
| Type | Use For | Example |
|---|---|---|
factual |
Facts and knowledge | "Project uses Python 3.12" |
episodic |
Events | "Shipped v2.0 on Jan 15" |
preference |
User preferences | "Prefers concise answers" |
procedural |
How-to knowledge | "Deploy: run tests first, then push" |
semantic |
Concepts and relationships | "Causal inference relates to Pearl" |
causal |
Cause-effect relationships | "Rate hikes → USD strengthens" |
Architecture
Query
↓
┌─────────────────────────┐
│ Vector Search (semantic)│ ← optional embedding provider
│ FTS5 Search (lexical) │ ← always available, zero-cost
│ Merge & Dedupe │
└──────────┬──────────────┘
↓
┌─────────────────────────┐
│ ACT-R Activation │ ← frequency × recency decay
│ Hebbian Spreading │ ← association boost from linked memories
│ Importance Weighting │ ← user-set priority
│ Confidence Scoring │ ← metacognition layer
└──────────┬──────────────┘
↓
Ranked Results
Configuration
Embedding Providers
Engram works without any embedding provider (FTS5 keyword search). Add one for cross-language semantic search:
| Provider | Cost | Setup | Best For |
|---|---|---|---|
| None / FTS5 | Free | Zero config | Simple agents, testing |
| Sentence Transformers | Free | pip install "engramai[sentence-transformers]" |
Privacy, offline |
| Ollama | Free | Ollama + embedding model | Already using Ollama |
| OpenAI | ~$0.0001/query | OPENAI_API_KEY |
Highest quality |
Environment Variables
| Variable | Default | Description |
|---|---|---|
ENGRAM_EMBEDDING |
auto |
Provider: auto, sentence-transformers, ollama, openai, none |
ENGRAM_DB_PATH |
./engram.db |
Database path |
ENGRAM_ST_MODEL |
paraphrase-multilingual-MiniLM-L12-v2 |
Sentence Transformers model |
OPENAI_API_KEY |
— | Required for OpenAI embeddings |
CLI
neuromem add "User prefers dark mode" --type preference --importance 0.8
neuromem recall "user preferences"
neuromem stats
neuromem consolidate
neuromem forget --threshold 0.01
neuromem hebbian "dark mode"
📚 Documentation
- OpenClaw Plugin Guide — Drop-in context engine replacement
- Integration Guide — Level 3 auto-recall/store implementation
- Performance Analysis — Production metrics and optimization
- Embedding Configuration — Provider setup and tuning
- Vision — Where Engram is heading
Development
git clone https://github.com/tonitangpotato/engram-ai.git
cd engram-ai
# Python
pip install -e ".[dev,all]"
pytest
# TypeScript
cd engram-ts && npm install && npm test
# OpenClaw Plugin
cd openclaw-plugin && npm install && npm test
Credits
Built on research from:
- ACT-R (Adaptive Control of Thought-Rational) — Anderson, Carnegie Mellon
- Hebbian Learning — Donald Hebb, 1949
- Memory Consolidation — Walker & Stickgold (sleep research)
- Forgetting Curve — Hermann Ebbinghaus, 1885
- Working Memory — Baddeley & Hitch, 1974
- Miller's Law — George Miller, 1956 ("The Magical Number Seven")
License
AGPL-3.0-or-later — see LICENSE for details. Commercial licensing available, see COMMERCIAL-LICENSE.md.
Metadata
Release files for engramai 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| engramai-2.1.0.tar.gz | 152.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| engramai-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 276.5 kB
Release files / engramai-2.1.0.tar.gz
| Download URL | engramai-2.1.0.tar.gz |
|---|---|
| Size | 152.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c14818c0912b15a802b56af48f353492f321bf3668292b3962255b1b03dbd78
|
|
BLAKE2b-256 checksum How to use checksums |
a201c09815b14b0174dd27616e5ae00d62e605f61f2cac63c56055218d1afe8b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / engramai-2.1.0-py3-none-any.whl
| Download URL | engramai-2.1.0-py3-none-any.whl |
|---|---|
| Size | 123.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
187a07fec3320d5a96f6ad8a9c089d3ca958524b4f3e5ecf54b87f7dd9308047
|
|
BLAKE2b-256 checksum How to use checksums |
c694580fa844c81194d171a01d9a6e08b5317e78a0aa2a5b244835e5f0ed012f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|