Episodic Memory
Long-term storage for experiences, conversations, and events. Organized chronologically with rich metadata and hybrid retrieval. Entries are promoted from Working Memory during sleep consolidation.
Schema
Episodic Memory uses an auto-incrementing rowid with a unique text id:
| Column | Type | Description |
|---|---|---|
rowid | INTEGER | Auto-increment primary key |
id | TEXT | UUIDv4 unique identifier |
content | TEXT | Full experience record |
source | TEXT | Origin (user, tool, observation) |
timestamp | TEXT | Application-level timestamp |
session_id | TEXT | Session grouping key (default: 'default') |
importance | REAL | 0.0–1.0 importance score (default: 0.5) |
metadata_json | TEXT | Arbitrary JSON metadata blob |
summary_of | TEXT | IDs of original Working Memory entries this summarizes |
created_at | TIMESTAMP | Row creation time |
recall_count | INTEGER | Number of times recalled (default: 0) |
last_recalled | TIMESTAMP | Last recall time (default: NULL) |
valid_until | TIMESTAMP | TTL expiry time |
superseded_by | TEXT | ID of newer version |
scope | TEXT | Visibility scope (default: 'global') |
Indexes
idx_episodic_sessiononsession_ididx_episodic_timestampontimestampidx_episodic_sourceonsource
FTS5
Full-text search via fts_episodes (content synced from episodic_memory), maintained by INSERT/UPDATE/DELETE triggers.
Vector Search
Embeddings stored in vec_episodes (sqlite-vec, int8[384]), generated at recall time.
Hybrid Scoring
Retrieval combines text and vector signals:
score = (vector_similarity * 0.5) +
(fts_rank * 0.3) +
(temporal_proximity * 0.2)
| Signal | Weight | Description |
|---|---|---|
| Vector similarity | 0.5 | Semantic closeness to query embedding |
| FTS5 rank | 0.3 | Full-text match quality via BM25 |
| Temporal proximity | 0.2 | Recency of the memory |
Consolidation Pipeline
Episodic entries are created during sleep consolidation, not directly by the agent:
flowchart TD
WM[Working Memory] -->|age > TTL/2| C{Consolidation}
C -->|group by source| G[Group entries]
G -->|summarize| S[LLM or AAAK summary]
S -->|promote| EM[Episodic Memory]
C -->|evict originals| DEL[Evict from Working]
The summary_of column in the episodic record tracks which Working Memory entries were consolidated to produce it.
Session Grouping
Episodic entries are grouped by session_id for chronological recall:
# Store with session (goes to Working Memory first)
mem.remember(
content="User approved the design mockup.",
session_id="design-review-2026-04-25",
)
# Recall with session filter
results = mem.recall("design mockup", session_id="design-review-2026-04-25")
Performance
| Metric | Value |
|---|---|
| Median retrieval | 85ms |
| Storage per entry | ~2KB (compressed) |
| Queryable fields | content, source, session_id, timestamp, date range |
Use descriptive source values and meaningful metadata_json fields for episodic memories. These are indexed and used in retrieval scoring. Good sources: "user-feedback", "tool-result", "agent-decision".
Mnemosyne