"Memory is the treasury and guardian of all things." — Cicero
GraphMem is the first memory system that thinks like a human brain. It doesn't just store data—it forgets, consolidates, prioritizes, and evolves exactly like biological memory does.
This is the future of enterprise AI agents.
Every production AI agent faces the same crisis:
Day 1: "Who is the CEO?" → "Elon Musk" ✅
Day 100: Context window: OVERFLOW 💥
Day 365: "Who is the CEO?" → "John... or was it Jane... maybe Elon?" 🤯
Vector databases don't forget. They accumulate garbage until your agent drowns in irrelevant, conflicting, outdated information.
GraphMem implements the four pillars of human memory:
| Human Brain | GraphMem | Why It Matters |
|---|---|---|
| 🧠 Forgetting Curve | Memory Decay | Irrelevant memories fade naturally |
| 🔗 Neural Networks | Knowledge Graph | Relationships between concepts |
| ⭐ Importance Weighting | PageRank Centrality | Hub concepts (Elon Musk) > peripheral ones |
| ⏰ Episodic Memory | Temporal Validity | "CEO in 2015" vs "CEO now" |
"Who was CEO in 2015?" — No other memory system can answer this.
from datetime import datetime
from graphmem import GraphMem, MemoryConfig
memory = GraphMem(config)
# GraphMem tracks WHEN facts are true
memory.ingest("John Smith was CEO of ACME from 2010 to 2018")
memory.ingest("Jane Doe became CEO of ACME in July 2018")
# Point-in-time queries - like human episodic memory!
memory.query("Who was CEO in 2015?") # → "John Smith" ✅
memory.query("Who is CEO now?") # → "Jane Doe" ✅
memory.query("Who was CEO in 2019?") # → "Jane Doe" ✅Use Cases:
- 📋 "What contracts were active last quarter?"
- 👔 "Who was our legal counsel before 2020?"
- 📈 "What was our strategy during COVID?"
GraphMem uses Google's PageRank algorithm to identify important entities:
Importance Formula: ρ(e) = w1·f1 + w2·f2 + w3·f3 + w4·f4
where:
f1 = Temporal recency (recent = important)
f2 = Access frequency (used often = important)
f3 = PageRank centrality (well-connected = important) ← NEW!
f4 = User feedback (explicit signals)
Result: "Elon Musk" (connected to Tesla, SpaceX, Neuralink) scores 3x higher than "Austin, Texas" (connected only to Tesla HQ).
# PageRank automatically identifies hub entities
Elon Musk: PR = 1.000 ████████████████████ # Hub - many connections
Tesla: PR = 0.774 ███████████████ # Important company
Austin: PR = 0.520 ██████████ # Just a locationmemory.evolve() # This single line triggers:| Mechanism | What Happens | Human Equivalent |
|---|---|---|
| Decay | Old unused memories fade (importance → 0) | Forgetting curve |
| Consolidation | 5 mentions of "user likes Python" → 1 strong memory | Sleep consolidation |
| Rehydration | Contradictions resolved ("CEO is John" → "CEO is Jane") | Memory updating |
| Importance Scoring | PageRank recalculated | Synaptic strengthening |
Result: 80% memory reduction while keeping what matters.
Each user gets their own brain. Complete data separation.
# Alice's memory
alice = GraphMem(config, user_id="alice", memory_id="chat")
alice.ingest("I work at Google as a senior engineer")
# Bob's memory (COMPLETELY ISOLATED)
bob = GraphMem(config, user_id="bob", memory_id="chat")
bob.ingest("I'm a doctor at Mayo Clinic")
# Alice can NEVER see Bob's data
alice.query("What does Bob do?") # → "No information found" ✅
# Bob can NEVER see Alice's data
bob.query("Where does Alice work?") # → "No information found" ✅Architecture:
┌──────────────────────────────────────────────────────────────────────────┐
│ Neo4j Global Instance │
├────────────────────────────────────┬─────────────────────────────────────┤
│ USER: alice │ USER: bob │
│ ┌─────────────────────────────┐ │ ┌─────────────────────────────┐ │
│ │ 🏢 Google → 👤 Alice │ │ │ 🏥 Mayo Clinic → 👤 Bob │ │
│ │ ↓ │ │ │ ↓ │ │
│ │ 💼 Senior Engineer │ │ │ 🩺 Doctor │ │
│ └─────────────────────────────┘ │ └─────────────────────────────┘ │
├────────────────────────────────────┴─────────────────────────────────────┤
│ Redis Cache (Also Isolated by user_id) │
│ alice:query:* alice:search:* │ bob:query:* bob:search:* │
└──────────────────────────────────────────────────────────────────────────┘
from graphmem import GraphMem, MemoryConfig
# Initialize (works with ANY OpenAI-compatible API)
config = MemoryConfig(
llm_provider="openai_compatible",
llm_api_key="your-key",
llm_api_base="https://openrouter.ai/api/v1",
llm_model="google/gemini-2.0-flash-001",
embedding_provider="openai_compatible",
embedding_api_key="your-key",
embedding_api_base="https://openrouter.ai/api/v1",
embedding_model="openai/text-embedding-3-small",
)
memory = GraphMem(config)
# That's it. 3 methods:
memory.ingest("Tesla is led by CEO Elon Musk...") # ← Extract knowledge
memory.query("Who is the CEO?") # ← Ask questions
memory.evolve() # ← Let memory mature┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🧠 GraphMem │
│ The Human Brain for AI Agents │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ingest() │ │ query() │ │ evolve() │ │
│ │ Learn new │ │ Recall + │ │ Mature │ │
│ │ knowledge │ │ Reasoning │ │ memories │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
└──────────┼──────────────────────┼──────────────────────┼────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🔐 MULTI-TENANT LAYER │
│ │
│ Every operation is scoped by: user_id + memory_id │
│ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ USER: alice │ │ USER: bob │ │
│ │ memory_id: chat_1 │ │ memory_id: chat_1 │ │
│ │ memory_id: notes │ │ memory_id: work │ │
│ │ ════════════════════ │ │ ════════════════════ │ │
│ │ Complete isolation ✅ │ │ Complete isolation ✅ │ │
│ └─────────────────────────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🕸️ KNOWLEDGE GRAPH ENGINE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ │
│ │ ENTITY EXTRACTION │ │ RELATIONSHIP │ │ COMMUNITY │ │
│ │ │ │ DETECTION │ │ DETECTION │ │
│ │ • LLM-powered │ │ │ │ │ │
│ │ • Named entities │ │ • Semantic links │ │ • Louvain algo │ │
│ │ • Type inference │ │ • Temporal bounds │ │ • Auto-clustering │ │
│ │ • Descriptions │ │ • [t_s, t_e] │ │ • LLM summaries │ │
│ └───────────────────┘ └───────────────────┘ └───────────────────┘ │
│ │
│ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ │
│ │ ENTITY RESOLUTION │ │ SEMANTIC │ │ QUERY ENGINE │ │
│ │ │ │ SEARCH │ │ │ │
│ │ • Alias merging │ │ │ │ • Multi-hop │ │
│ │ • Canonicalization│ │ • Vector index │ │ • Cross-cluster │ │
│ │ • 95% accuracy │ │ • Cosine sim │ │ • Context assembly│ │
│ │ • user_id aware │ │ • user_id filter │ │ • LLM synthesis │ │
│ └───────────────────┘ └───────────────────┘ └───────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🔄 EVOLUTION ENGINE │
│ (Human Memory Simulation) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ ⭐ PAGERANK CENTRALITY │ │
│ │ │ │
│ │ PR(A) = (1-d) + d × Σ(PR(Ti)/C(Ti)) where d = 0.85 │ │
│ │ │ │
│ │ Hub Detection: │ │
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
│ │ │ Elon Musk ─────┬───→ Tesla ───→ Austin │ │ │
│ │ │ (HUB) ├───→ SpaceX ───→ Hawthorne │ │ │
│ │ │ PR=1.00 └───→ Neuralink │ │ │
│ │ │ │ │ │
│ │ │ PageRank: Elon(1.00) > Tesla(0.77) > SpaceX(0.77) > Austin(0.52)│ │ │
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌────────────────────┐ │
│ │ MEMORY DECAY │ │ CONSOLIDATION │ │ TEMPORAL VALIDITY │ │
│ │ │ │ │ │ │ │
│ │ Ebbinghaus Curve: │ │ LLM-based merging: │ │ Time bounds: │ │
│ │ │ │ │ │ │ │
│ │ I(t) = I₀·e^(-λt) │ │ 5 mentions → │ │ valid_from: t_s │ │
│ │ │ │ 1 strong memory │ │ valid_until: t_e │ │
│ │ λ = decay rate │ │ │ │ │ │
│ │ │ │ 80% reduction │ │ is_valid_at(t) │ │
│ │ Unused → archived │ │ while keeping value │ │ supersede(end) │ │
│ └──────────────────────┘ └──────────────────────┘ └────────────────────┘ │
│ │
│ Importance Formula: ρ(e) = w1·f1 + w2·f2 + w3·f3 + w4·f4 │
│ ├── f1: Recency (0.3) - Recent access = important │
│ ├── f2: Frequency (0.3) - Used often = important │
│ ├── f3: PageRank (0.2) - Well-connected = important (HUB) │
│ └── f4: User signal (0.2) - Explicit importance │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 💾 STORAGE LAYER │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐│
│ │ CHOOSE YOUR STORAGE BACKEND ││
│ │ ││
│ │ ┌─────────────┐ ┌─────────────────┐ ┌─────────────────────┐ ││
│ │ │ InMemory │ │ 🔥 TURSO 🔥 │ │ NEO4J │ ││
│ │ │ (Default) │ │ (Embedded) │ │ (Enterprise) │ ││
│ │ ├─────────────┤ ├─────────────────┤ ├─────────────────────┤ ││
│ │ │ No persist │ │ SQLite file │ │ Full graph DB │ ││
│ │ │ Zero config │ │ Works offline │ │ ACID + clustering │ ││
│ │ │ Dev/testing │ │ Cloud sync opt │ │ Native Cypher │ ││
│ │ │ Python vec │ │ Native vec 🚀 │ │ HNSW vec 🚀 │ ││
│ │ │ │ │ ~10ms search │ │ ~5ms search │ ││
│ │ └─────────────┘ └─────────────────┘ └─────────────────────┘ ││
│ │ │ │ │ ││
│ │ │ ALL BACKENDS GET THE SAME FEATURES: │ ││
│ │ │ ✅ Multi-tenant ✅ Temporal validity │ ││
│ │ │ ✅ PageRank ✅ Memory evolution │ ││
│ │ │ ✅ Communities ✅ Entity resolution │ ││
│ │ └─────────────────────┬─────────────────────────┘ ││
│ │ │ ││
│ └───────────────────────────────┴─────────────────────────────────────────────┘│
│ │
│ ┌───────────────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ 🗃️ NEO4J GRAPH │ │ ⚡ REDIS CACHE │ │
│ │ (Enterprise Option) │ │ (Optional Layer) │ │
│ │ │ │ │ │
│ │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────┐ │ │
│ │ │ ENTITY NODES │ │ │ │ EMBEDDING CACHE │ │ │
│ │ │ • id, name, type │ │ │ │ │ │ │
│ │ │ • embedding[1536] │ │ │ │ Key: emb:{text_hash} │ │ │
│ │ │ • user_id ← ISOLATION │ │ │ │ TTL: 24 hours │ │ │
│ │ │ • memory_id │ │ │ │ 3x faster embeddings │ │ │
│ │ │ • importance, access_count │ │ │ └────────────────────────┘ │ │
│ │ └─────────────────────────────────┘ │ │ │ │
│ │ │ │ ┌────────────────────────┐ │ │
│ │ ┌─────────────────────────────────┐ │ │ │ QUERY CACHE │ │ │
│ │ │ RELATIONSHIP EDGES │ │ │ │ (Multi-Tenant!) │ │ │
│ │ │ • valid_from ← TEMPORAL │ │ │ │ │ │ │
│ │ │ • valid_until ← VALIDITY │ │ │ │ Key: query:{user}:* │ │ │
│ │ │ • user_id ← ISOLATION │ │ │ │ TTL: 5 minutes │ │ │
│ │ └─────────────────────────────────┘ │ │ │ Instant repeat: 0ms │ │ │
│ │ │ │ └────────────────────────┘ │ │
│ │ ┌─────────────────────────────────┐ │ │ │ │
│ │ │ VECTOR INDEX (HNSW) │ │ │ Auto-Invalidation: │ │
│ │ │ Dimension: 1536, cosine │ │ │ • ingest() → clear cache │ │
│ │ │ ~5ms similarity search │ │ │ • evolve() → clear cache │ │
│ │ └─────────────────────────────────┘ │ │ • clear() → clear cache │ │
│ └───────────────────────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ 🔥 TURSO (SQLite) - RECOMMENDED! │ │ 🔥 TURSO CACHE │ │
│ │ (Edge/Offline Option) │ │ (Built-in to TursoStore) │ │
│ │ │ │ │ │
│ │ pip install "agentic-graph-mem[libsql]" │ ┌────────────────────────┐ │ │
│ │ │ │ │ No Redis needed! │ │ │
│ │ ✅ Persists to local .db file │ │ │ SQLite-based cache │ │ │
│ │ ✅ Works completely offline │ │ │ TTL support │ │ │
│ │ ✅ Optional Turso Cloud sync │ │ │ Multi-tenant keys │ │ │
│ │ ✅ Native F32_BLOB vector search │ │ │ Survives restarts │ │ │
│ │ ✅ ~10ms vector similarity │ │ └────────────────────────┘ │ │
│ │ │ │ │ │
│ │ SAME FEATURES AS NEO4J: │ │ Great for: │ │
│ │ • Temporal validity ✅ │ │ • Edge AI devices │ │
│ │ • PageRank centrality ✅ │ │ • Offline agents │ │
│ │ • Multi-tenant isolation ✅ │ │ • Mobile apps │ │
│ │ • Point-in-time queries ✅ │ │ • Cost-sensitive deploys │ │
│ └───────────────────────────────────────┘ └───────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🤖 LLM PROVIDERS │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ OpenAI │ │ Azure │ │Anthropic │ │ Groq │ │ Together │ │ Ollama │ │
│ │ GPT-4o │ │ OpenAI │ │ Claude │ │ Llama │ │ AI │ │ Local │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ OpenRouter (100+ Models) │ │
│ │ google/gemini-2.0-flash │ anthropic/claude-3.5 │ meta-llama/llama-3 │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ INGEST FLOW │
└─────────────────────────────────────────────────────────────────────────────────┘
Input Document Knowledge Extraction Storage
┌──────────────┐ ┌──────────────────┐ ┌───────────┐
│ "Tesla is │ ──────────▶ │ LLM extracts: │ ──────────▶ │ Neo4j OR │
│ led by CEO │ │ │ │ 🔥Turso │
│ Elon Musk" │ │ Entities: │ │ │
└──────────────┘ │ • Tesla [Org] │ │ (Tesla)───│
│ │ • Elon Musk [Per]│ │ │ │
│ │ │ │ ▼ │
│ │ Relations: │ │ CEO_OF │
│ │ • (Elon)─CEO─▶ │ │ │ │
│ │ (Tesla) │ │ ▼ │
│ │ │ │ (Elon) │
│ │ Temporal: │ └───────────┘
│ │ • valid_from=now │ │
│ │ • valid_until=∞ │ ▼
│ └──────────────────┘ ┌───────────┐
│ │ │ Redis OR │
│ │ │ TursoCache│
│ ▼ └───────────┘
│ ┌──────────────────┐
│ │ Entity Resolution│
│ │ │
│ │ "Elon" = "Musk" │
│ │ = "Elon Musk" │
│ │ → Canonical: "Elon Musk"
│ └──────────────────┘
│
└─── user_id + memory_id tagged on ALL nodes/edges
┌─────────────────────────────────────────────────────────────────────────────────┐
│ QUERY FLOW │
└─────────────────────────────────────────────────────────────────────────────────┘
User Question Cache Check Retrieval Answer
┌──────────────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐
│ "Who is the │ ───▶ │ Redis │ HIT │ │ ───▶ │ "Elon │
│ CEO?" │ │ Cache │ ───▶ │ SKIP! │ │ Musk" │
│ │ │ │ │ │ │ │
│ user: alice │ │ Key: │ └───────────┘ └──────────┘
│ mem: chat_1 │ │ query: │
└──────────────┘ │ alice: │ MISS
│ │ chat_1: │ ───▶ ┌───────────────────────────────┐
│ │ {hash} │ │ RETRIEVAL │
│ └───────────┘ │ │
│ │ 1. Embed query │
│ │ 2. Vector search (Neo4j/Turso)│
│ │ WHERE user_id = 'alice' │
│ │ AND memory_id = 'chat_1' │
│ │ 3. Get related edges │
│ │ 4. Filter by temporal │
│ │ is_valid_at(now) ✅ │
│ │ 5. Rank by importance │
│ │ (PageRank score) │
│ │ 6. Build context │
│ │ 7. LLM generates answer │
│ │ 8. Cache result in Redis │
│ └───────────────────────────────┘
│
└─── user_id ensures Alice NEVER sees Bob's data
┌─────────────────────────────────────────────────────────────────────────────────┐
│ EVOLVE FLOW │
└─────────────────────────────────────────────────────────────────────────────────┘
Trigger Evolution Cycle Result
┌──────────────┐ ┌────────────────────────────────┐ ┌────────────┐
│ memory │ ───▶ │ │ │ │
│ .evolve() │ │ 1. PAGERANK RECALCULATION │ │ • Hubs │
│ │ │ Build graph from edges │ │ identified│
│ user: alice │ │ Compute PR scores │ │ │
│ │ │ Update importance │ │ • 80% │
└──────────────┘ │ │ │ memory │
│ │ 2. MEMORY DECAY │ │ reduced │
│ │ I(t) = I₀ × e^(-λt) │ │ │
│ │ Archive if I < 0.1 │ │ • Conflicts│
│ │ │ │ resolved │
│ │ 3. CONSOLIDATION │ │ │
│ │ Find similar memories │ │ • Cache │
│ │ LLM merges duplicates │ │ cleared │
│ │ │ │ │
│ │ 4. REHYDRATION │ └────────────┘
│ │ Update contradictions │
│ │ "CEO=John" → "CEO=Jane" │
│ │ │
│ │ 5. CACHE INVALIDATION │
│ │ Clear Redis for user │
│ └────────────────────────────────┘
│
└─── Only evolves Alice's data (user_id scoped)
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 🔐 MULTI-TENANT ARCHITECTURE │
│ (Works identically with Neo4j, Turso, or InMemory) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ STORAGE BACKEND (Neo4j / Turso / InMemory) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ GLOBAL VECTOR INDEX │ │
│ │ (Entity.embedding, HNSW) │ │
│ │ │ │
│ │ Query: db.index.vector.queryNodes( │ │
│ │ 'entity_embedding_index', │ │
│ │ $top_k * 10, ← Fetch extra for filtering │ │
│ │ $query_embedding │ │
│ │ ) │ │
│ │ WHERE node.user_id = $user_id ← ISOLATION │ │
│ │ AND node.memory_id = $memory_id │ │
│ │ RETURN node LIMIT $top_k │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────────┐ │
│ │ USER: alice │ │ USER: bob │ │
│ │ │ │ │ │
│ │ ┌─────────────────────────┐ │ │ ┌─────────────────────────────┐ │ │
│ │ │ memory: chat_1 │ │ │ │ memory: chat_1 │ │ │
│ │ │ ┌─────┐ ┌─────┐ │ │ │ │ ┌─────┐ ┌─────┐ │ │ │
│ │ │ │Alice│───▶│Google│ │ │ │ │ │ Bob │───▶│Mayo │ │ │ │
│ │ │ └─────┘ └─────┘ │ │ │ │ └─────┘ │Clinic│ │ │ │
│ │ │ │ │ │ │ │ │ └─────┘ │ │ │
│ │ │ ▼ │ │ │ │ ▼ │ │ │
│ │ │ ┌────────┐ │ │ │ │ ┌──────┐ │ │ │
│ │ │ │Engineer│ │ │ │ │ │Doctor│ │ │ │
│ │ │ └────────┘ │ │ │ │ └──────┘ │ │ │
│ │ └─────────────────────────┘ │ │ └─────────────────────────────┘ │ │
│ │ │ │ │ │
│ │ ┌─────────────────────────┐ │ │ ┌─────────────────────────────┐ │ │
│ │ │ memory: notes │ │ │ │ memory: work │ │ │
│ │ │ ┌──────┐ ┌─────┐ │ │ │ │ ┌───────┐ ┌──────┐ │ │ │
│ │ │ │Python│──▶│ ML │ │ │ │ │ │Patient│──▶│Record│ │ │ │
│ │ │ └──────┘ └─────┘ │ │ │ │ └───────┘ └──────┘ │ │ │
│ │ └─────────────────────────┘ │ │ └─────────────────────────────┘ │ │
│ │ │ │ │ │
│ └───────────────────────────────┘ └───────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────────┤
│ REDIS CACHE (ISOLATED) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Alice's Keys: Bob's Keys: │ │
│ │ ───────────── ────────── │ │
│ │ query:alice:chat_1:abc123 query:bob:chat_1:xyz789 │ │
│ │ search:alice:chat_1:def456 search:bob:chat_1:uvw321 │ │
│ │ search:alice:notes:ghi789 search:bob:work:rst654 │ │
│ │ │ │
│ │ Shared (same text = same embedding): │ │
│ │ ───────────────────────────────────── │ │
│ │ emb:sha256_of_text → [0.1, 0.2, ...] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ✅ Alice can NEVER access Bob's cached queries │
│ ✅ Bob can NEVER access Alice's cached queries │
│ ✅ Embeddings shared (efficiency) - no sensitive data in embeddings │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ ⏰ TEMPORAL VALIDITY │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Every RELATIONSHIP has a time interval: [valid_from, valid_until] │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ CEO TRANSITIONS │ │
│ │ │ │
│ │ Timeline: 2010 2015 2018 2020 2025 │ │
│ │ │ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ ▼ │ │
│ │ │ │
│ │ John ──CEO_OF──▶ ACME ════════════════╗ │ │
│ │ valid: [2010-01-01, 2018-06-30] ║ │ │
│ │ ║ │ │
│ │ Jane ──CEO_OF──▶ ACME ╚════════════════════════ │ │
│ │ valid: [2018-07-01, NULL] ← NULL = still current │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ Point-in-Time Queries: │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Q: "Who was CEO in 2015?" │ │
│ │ │ │
│ │ 1. Find edges WHERE relation_type = 'CEO_OF' │ │
│ │ 2. Filter: is_valid_at(datetime(2015, 6, 1)) │ │
│ │ ├── John: valid_from=2010 ≤ 2015 ≤ valid_until=2018 ✅ │ │
│ │ └── Jane: valid_from=2018 > 2015 ❌ │ │
│ │ 3. Return: "John Smith" │ │
│ │ │ │
│ │ Q: "Who is CEO now?" │ │
│ │ │ │
│ │ 1. Filter: is_valid_at(datetime.utcnow()) │ │
│ │ ├── John: valid_until=2018 < now ❌ │ │
│ │ └── Jane: valid_from=2018 ≤ now, valid_until=NULL ✅ │ │
│ │ 2. Return: "Jane Doe" │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ API: │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ # Check validity at any point in time │ │
│ │ edge.is_valid_at(datetime(2015, 6, 1)) # True/False │ │
│ │ │ │
│ │ # Mark relationship as ended │ │
│ │ edge.supersede(end_time=datetime(2018, 6, 30)) │ │
│ │ │ │
│ │ # Query edges at specific time │ │
│ │ store.query_edges_at_time( │ │
│ │ memory_id="company_kb", │ │
│ │ query_time=datetime(2015, 6, 1), │ │
│ │ relation_type="CEO_OF" │ │
│ │ ) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
graphmem/
├── core/
│ ├── memory.py # GraphMem main class
│ ├── memory_types.py # MemoryNode, MemoryEdge (+ temporal validity)
│ └── exceptions.py # Custom exceptions
│
├── graph/
│ ├── knowledge_graph.py # LLM-based extraction
│ ├── entity_resolver.py # Deduplication (user_id aware)
│ └── community_detector.py # Topic clustering
│
├── evolution/
│ ├── memory_evolution.py # Evolution orchestrator
│ ├── importance_scorer.py # PageRank + multi-factor scoring
│ ├── decay.py # Ebbinghaus forgetting curve
│ ├── consolidation.py # LLM-based merging (user_id aware)
│ └── rehydration.py # Contradiction resolution
│
├── retrieval/
│ ├── query_engine.py # Multi-hop + cross-cluster
│ ├── retriever.py # Context retrieval
│ └── semantic_search.py # Vector search (user_id filtered)
│
├── stores/
│ ├── neo4j_store.py # Graph + temporal + HNSW vector index
│ ├── turso_store.py # SQLite + temporal + native vector (NEW!)
│ ├── memory_store.py # In-memory (default)
│ └── redis_cache.py # Multi-tenant cache
│
├── llm/
│ ├── providers.py # 10+ LLM providers
│ └── embeddings.py # Embedding + cache
│
└── context/
├── context_engine.py # Context assembly
├── chunker.py # Semantic chunking
└── multimodal.py # JSON, CSV, Markdown, Code, Web
| Metric | Naive RAG | GraphMem | Advantage |
|---|---|---|---|
| 1K conversations | 💥 Context overflow | ✅ Bounded | Handles growth |
| 10K entities | O(n) = 2.3s | O(1) = 50ms | 46x faster |
| 1 year history | 3,650 entries | ~100 consolidated | 97% reduction |
| Entity conflicts | Duplicates | Auto-resolved | Clean data |
| Temporal queries | ❌ Impossible | ✅ Native | Unique capability |
Naive RAG: Send entire history every query = $$$$$
GraphMem: Retrieve only relevant subgraph = $
─────
99% savings
| Requirement | GraphMem |
|---|---|
| Multi-tenant isolation | ✅ user_id on every node |
| ACID transactions | ✅ Neo4j backend |
| Horizontal scaling | ✅ Neo4j cluster + Redis |
| Audit trail | ✅ Temporal validity history |
| Data sovereignty | ✅ Self-hosted option |
# Core only (in-memory, for development)
pip install agentic-graph-mem
# 🔥 RECOMMENDED: Turso (SQLite persistence + offline)
pip install "agentic-graph-mem[libsql]"
# Enterprise: Neo4j + Redis (full graph power)
pip install "agentic-graph-mem[all]"┌─────────────────────────────────────────────────────────────────────────────────┐
│ STORAGE BACKEND DECISION TREE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ "Do you need data to persist between restarts?" │
│ │ │
│ ┌────────────┴────────────┐ │
│ │ │ │
│ NO YES │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ "Do you need complex graph queries │
│ │ InMemory │ (multi-hop traversals, GDS algorithms)?" │
│ │ │ │ │
│ │ • Development │ ┌────────────┴────────────┐ │
│ │ • Testing │ │ │ │
│ │ • Quick POCs │ NO YES │
│ │ • Zero config │ │ │ │
│ └─────────────────┘ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 🔥 TURSO │ │ NEO4J │ │
│ │ │ │ │ │
│ │ • Edge/offline │ │ • Enterprise │ │
│ │ • Mobile apps │ │ • Complex graphs│ │
│ │ • Single-user │ │ • Multi-tenant │ │
│ │ • No server │ │ • Horizontal │ │
│ │ • Simple setup │ │ scaling │ │
│ │ • SQLite-based │ │ • ACID + cluster│ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │
│ "Add high-performance caching?" │
│ │ │
│ ┌───────┴───────┐ │
│ YES NO │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ │
│ │ + REDIS │ │ Neo4j only│ │
│ │ Cache │ │ (still │ │
│ │ │ │ great!) │ │
│ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
| Feature | InMemory | Turso 🔥 | Neo4j |
|---|---|---|---|
| Persistence | ❌ | ✅ SQLite file | ✅ Server |
| Works Offline | ✅ | ✅ | ❌ |
| Vector Search | Python | Native F32_BLOB |
Native HNSW |
| Cloud Sync | ❌ | ✅ Optional | ✅ |
| Setup Complexity | None | One file path | Server required |
| Multi-hop Queries | ✅ NetworkX | ✅ NetworkX | ✅ Native Cypher |
| PageRank | ✅ | ✅ | ✅ |
| Temporal Validity | ✅ | ✅ | ✅ |
| Multi-tenant | ✅ | ✅ | ✅ |
| Best For | Dev/Test | Edge/Offline | Enterprise |
from graphmem import GraphMem, MemoryConfig
config = MemoryConfig(
llm_provider="openai_compatible",
llm_api_key="sk-or-v1-your-key",
llm_api_base="https://openrouter.ai/api/v1",
llm_model="google/gemini-2.0-flash-001",
embedding_provider="openai_compatible",
embedding_api_key="sk-or-v1-your-key",
embedding_api_base="https://openrouter.ai/api/v1",
embedding_model="openai/text-embedding-3-small",
)
memory = GraphMem(config)
# Learn
memory.ingest("Tesla is led by CEO Elon Musk. Founded in 2003.")
memory.ingest("SpaceX, founded by Elon Musk in 2002, builds rockets.")
memory.ingest("Neuralink develops brain-computer interfaces.")
# Recall
response = memory.query("What companies does Elon Musk lead?")
print(response.answer) # "Elon Musk leads Tesla, SpaceX, and Neuralink."
# Mature
memory.evolve() # Consolidates, decays, re-ranks importancefrom graphmem import GraphMem, MemoryConfig
# Turso gives you persistence without running Neo4j!
# Data survives restarts, works offline, can sync to cloud
config = MemoryConfig(
llm_provider="openai_compatible",
llm_api_key="sk-or-v1-your-key",
llm_api_base="https://openrouter.ai/api/v1",
llm_model="google/gemini-2.0-flash-001",
embedding_provider="openai_compatible",
embedding_api_key="sk-or-v1-your-key",
embedding_api_base="https://openrouter.ai/api/v1",
embedding_model="openai/text-embedding-3-small",
# 🔥 Just add a file path - that's it!
turso_db_path="my_agent_memory.db",
# Optional: Sync to Turso Cloud for backups/multi-device
# turso_url="https://your-db.turso.io",
# turso_auth_token="your-token",
)
memory = GraphMem(config, user_id="alice")
# All data persists in my_agent_memory.db
memory.ingest("Alice is a software engineer at Google.")
memory.save() # Data survives restart!
# Later, in a new session:
memory2 = GraphMem(config, user_id="alice")
response = memory2.query("Where does Alice work?") # Still knows! ✅Why Turso over InMemory?
- ✅ Data survives restarts (SQLite file)
- ✅ Works offline (no network needed)
- ✅ Optional cloud sync (Turso Cloud)
- ✅ No server to manage (unlike Neo4j)
- ✅ Per-user database files (true isolation)
from graphmem import GraphMem, MemoryConfig
# Base config (shared across all users)
base_config = MemoryConfig(
llm_provider="openai_compatible",
llm_api_key="sk-or-v1-your-key",
llm_api_base="https://openrouter.ai/api/v1",
llm_model="google/gemini-2.0-flash-001",
embedding_provider="openai_compatible",
embedding_api_key="sk-or-v1-your-key",
embedding_api_base="https://openrouter.ai/api/v1",
embedding_model="openai/text-embedding-3-small",
# Production storage
neo4j_uri="neo4j+ssc://xxx.databases.neo4j.io",
neo4j_username="neo4j",
neo4j_password="your-password",
redis_url="redis://default:password@your-redis.cloud.redislabs.com:17983",
)
class ChatService:
def get_memory(self, user_id: str, session_id: str) -> GraphMem:
"""Each user gets isolated memory."""
return GraphMem(
base_config,
user_id=user_id, # ← Complete isolation
memory_id=session_id, # ← Per-session memory
)
def chat(self, user_id: str, session_id: str, message: str) -> str:
memory = self.get_memory(user_id, session_id)
# Store user message as memory
memory.ingest(message)
# Generate response using memory
response = memory.query(message)
return response.answer
# Usage
service = ChatService()
# Alice's session (isolated)
alice_response = service.chat("alice", "session_1", "I'm a software engineer at Google")
alice_response = service.chat("alice", "session_1", "What do I do?") # → "Software engineer at Google"
# Bob's session (completely separate)
bob_response = service.chat("bob", "session_1", "I'm a doctor")
bob_response = service.chat("bob", "session_1", "What does Alice do?") # → "No information found"from datetime import datetime
from graphmem.core.memory_types import MemoryEdge
from graphmem.stores.neo4j_store import Neo4jStore
store = Neo4jStore(uri, user, password)
# Track CEO transitions
john_ceo = MemoryEdge(
id="john_ceo",
source_id="john_smith",
target_id="acme_corp",
relation_type="CEO_OF",
valid_from=datetime(2010, 1, 1),
valid_until=datetime(2018, 6, 30), # John left
)
jane_ceo = MemoryEdge(
id="jane_ceo",
source_id="jane_doe",
target_id="acme_corp",
relation_type="CEO_OF",
valid_from=datetime(2018, 7, 1),
valid_until=None, # Current CEO
)
# Query by time period
ceo_2015 = store.query_edges_at_time(
memory_id="company_kb",
query_time=datetime(2015, 6, 1),
relation_type="CEO_OF"
)
# → Returns John Smith's edge
ceo_now = store.query_edges_at_time(
memory_id="company_kb",
query_time=datetime.utcnow(),
relation_type="CEO_OF"
)
# → Returns Jane Doe's edge
# Mark relationship as ended
store.supersede_relationship(
memory_id="company_kb",
edge_id="jane_ceo",
end_time=datetime(2025, 12, 31) # Jane leaves
)cd graphmem/evaluation
python run_eval.pyUses MultiHopRAG dataset (2,556 QA samples, 609 documents).
importance(t) = importance_0 × e^(-λ × (t - last_access))
Just like human memory, unused information fades exponentially.
PR(A) = (1-d) + d × Σ(PR(Ti)/C(Ti))
Hub entities (connected to many concepts) are more important—exactly like neural hubs in the brain.
valid(r, t) = 1[t_s(r) ≤ t ≤ t_e(r)]
Every relationship has a time interval, enabling episodic memory recall.
| Scale | Users | Strategy | Infrastructure |
|---|---|---|---|
| Development | 1 | InMemory (no persistence) | Nothing required |
| Personal/Edge | 1-10 | 🔥 Turso (local SQLite) | Single .db file per user |
| Startup | 1-100 | Turso + Cloud sync | Turso Cloud (free tier) |
| Growth | 100-10K | Neo4j + Redis | Neo4j Aura Pro + Redis Cloud |
| Enterprise | 10K-100K | Sharded by region | Neo4j Enterprise Cluster |
| Global | 100K+ | Database per tenant | Multi-region Neo4j Fabric |
┌─────────────────────────────────────────────────────────────────────────────────┐
│ STORAGE SELECTION GUIDE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 🧪 DEVELOPMENT / TESTING │
│ └─▶ InMemory (default) │
│ • pip install agentic-graph-mem │
│ • config = MemoryConfig(...) # No storage params needed │
│ │
│ 📱 EDGE / OFFLINE / SIMPLE APPS │
│ └─▶ 🔥 Turso (RECOMMENDED) │
│ • pip install "agentic-graph-mem[libsql]" │
│ • config = MemoryConfig(..., turso_db_path="agent.db") │
│ • Works offline, data persists, no server! │
│ │
│ 🏢 ENTERPRISE / HIGH-SCALE │
│ └─▶ Neo4j + Redis │
│ • pip install "agentic-graph-mem[all]" │
│ • config = MemoryConfig(..., neo4j_uri=..., redis_url=...) │
│ • Complex graph queries, horizontal scaling, ACID │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
# Core (no external services, in-memory only)
pip install agentic-graph-mem
# With Turso (SQLite persistence, offline-first) - SIMPLEST OPTION!
pip install agentic-graph-mem libsql
# With Neo4j persistence (full graph database)
pip install "agentic-graph-mem[neo4j]"
# With Redis caching (high-performance cache)
pip install "agentic-graph-mem[redis]"
# Full production stack (Neo4j + Redis)
pip install "agentic-graph-mem[all]"| Backend | Persistence | Vector Search | Graph Algorithms | Offline | Use Case |
|---|---|---|---|---|---|
| InMemory | ❌ | ✅ (in Python) | ✅ (NetworkX) | ✅ | Development, testing |
| Turso | ✅ | ✅ (native) | ✅ (NetworkX) | ✅ | Edge/offline AI, simple deploys |
| Neo4j | ✅ | ✅ (HNSW) | ✅ (GDS, native) | ❌ | Enterprise, complex graphs |
| Redis | ❌ | ❌ | ❌ | Caching layer only |
GraphMem isn't just another vector database wrapper. It's a paradigm shift:
| Old Way | GraphMem Way |
|---|---|
| Store everything | Remember what matters |
| Static forever | Evolves over time |
| No relationships | Rich knowledge graph |
| "Who is CEO?" | "Who was CEO in 2015?" |
| One user fits all | Enterprise multi-tenant |
| Hope for the best | PageRank prioritization |
The agents of tomorrow will have memories that think.
We're building the future of AI memory. Join us!
MIT License - see LICENSE.
- Inspired by cognitive neuroscience research on human memory
- Built on Neo4j, Redis, Turso (libSQL), and OpenAI
- PageRank algorithm by Larry Page and Sergey Brin
- Turso team for the amazing embedded SQLite with vector search