Memory System#
EurekaClaw uses a four-tier memory system managed by MemoryManager.
eurekaclaw/memory/
├── manager.py MemoryManager (main interface)
├── episodic.py EpisodicMemory (in-RAM ring buffer)
├── persistent.py PersistentMemory (cross-run JSON file)
└── knowledge_graph.py KnowledgeGraph (theorem dependency network)
eurekaclaw/learning/
└── memory_extractor.py SessionMemoryExtractor (Tier 4: domain markdown insights)
Storage layout under ~/.eurekaclaw/ (configurable via EUREKACLAW_DIR):
~/.eurekaclaw/
├── memory/
│ ├── persistent.json ← Tier 2: cross-run key-value store
│ └── knowledge_graph.json ← Tier 3: theorem dependency graph
├── memories/
│ └── <domain>/
│ ├── YYYYMMDD_<slug>.md ← Tier 4: per-domain insight files
│ └── _index.json ← Tier 4: index for semantic search
└── skills/ ← skill files updated by ContinualLearningLoop
Tier 1 — Episodic Memory (session-scoped)#
File: eurekaclaw/memory/episodic.py
In-RAM ring buffer (max 500 entries). Records agent events during the current session. Lost when the process ends — never persisted to disk.
def log_event(
agent_role: str,
content: str,
metadata: dict | None = None
) -> EpisodicEntry
Log a structured event (tool call, result, decision, error) from an agent. Called automatically by BaseAgent after each tool call.
def recent_events(
n: int = 20,
agent_role: str | None = None
) -> list[EpisodicEntry]
Return the N most recent events, optionally filtered by agent role.
Tier 2 — Persistent Memory (cross-run key-value)#
File: eurekaclaw/memory/persistent.py
Storage: ~/.eurekaclaw/memory/persistent.json
Stores arbitrary JSON-serializable key-value records that survive across sessions.
def remember(
key: str,
value: Any,
tags: list[str] | None = None,
source_session: str = ""
) -> None
Save or overwrite a cross-run record. key is typically namespaced (e.g., "theory.failed_strategies.concentration_bounds").
def recall(key: str) -> Any | None
Retrieve a value by exact key. Returns None if not found.
def recall_by_tag(tag: str) -> list[CrossRunRecord]
Return all records that include the given tag.
Tier 3 — Knowledge Graph (theorem dependency network)#
File: eurekaclaw/memory/knowledge_graph.py
Storage: ~/.eurekaclaw/memory/knowledge_graph.json
A directed graph that tracks proven theorems and their dependencies across all sessions. Exportable to networkx for analysis.
def add_theorem(
theorem_name: str,
formal_statement: str,
domain: str = "",
session_id: str = "",
tags: list[str] | None = None
) -> KnowledgeNode
Register a newly proved theorem.
def link_theorems(from_id: str, to_id: str, relation: str = "uses") -> None
Record a dependency between two theorems. Relation types: "uses", "generalizes", "specializes", "contradicts".
def find_related_theorems(node_id: str, depth: int = 2) -> list[KnowledgeNode]
BFS traversal — returns theorems within depth hops of node_id.
Tier 4 — Domain Memories (cross-session markdown insights)#
File: eurekaclaw/learning/memory_extractor.py
Storage: ~/.eurekaclaw/memories/<domain>/YYYYMMDD_<slug>.md
The primary mechanism for cross-session learning. After each session, SessionMemoryExtractor uses the fast model to analyse TheoryState and extract structured insights in four categories:
Category |
What gets saved |
|---|---|
|
New facts, lemmas, theorems discovered or confirmed |
|
Proof techniques that worked (or failed) in this domain |
|
Conjectures raised but not resolved |
|
Approaches that looked promising but failed, with root cause |
Only entries with confidence >= 0.5 are saved. A sha256 fingerprint index (_index.json) deduplicates exact matches. Near-duplicates (keyword overlap > 40%) are checked by the LLM and merged when redundant.
Injection into future sessions#
At the start of each session, BaseAgent.build_system_prompt() calls:
memory.load_for_injection(domain, k=4, query=task_description)
This selects the 4 most relevant high-confidence .md files for the domain using cosine similarity against query, strips frontmatter, and injects the content into the system prompt as <memories>...</memories>.
Semantic ranking: each memory file’s embedding is stored in _index.json at write time (via eurekaclaw/memory/embedding_utils.py). At retrieval time, candidates are scored by cosine_similarity(query_embedding, memory_embedding) and the top-k are returned. Falls back to recency ordering if embeddings are unavailable.
Lifecycle#
During session
BaseAgent.execute() → memory.log_event() → Tier 1 (RAM only)
After session (ContinualLearningLoop.post_run())
SessionMemoryExtractor.extract_and_save()
→ LLM analysis of TheoryState (proven lemmas + failed attempts)
→ write ~/.eurekaclaw/memories/<domain>/YYYYMMDD_<slug>.md [Tier 4]
ToolPatternExtractor.extract_and_save()
→ analyse tool-call patterns → generate new Skill files
SkillRegistry.update_stats()
→ EMA α=0.3 update on success_rate for all injected skills
Next session startup
MetaOrchestrator → MemoryManager.load_for_injection(domain)
→ top-4 Tier 4 files → injected into agent system prompts
Data Models#
File: eurekaclaw/types/memory.py
EpisodicEntry#
class EpisodicEntry(BaseModel):
entry_id: str
session_id: str
agent_role: str # "survey", "theory", "writer", etc.
content: str # free-text event description
metadata: dict = {} # structured data (tool name, paper_id, etc.)
timestamp: datetime
CrossRunRecord#
class CrossRunRecord(BaseModel):
record_id: str
key: str # namespaced key, e.g. "theory.failed_strategies.sample_complexity"
value: Any # arbitrary JSON-serializable value
tags: list[str] = []
source_session: str = ""
created_at: datetime
updated_at: datetime
KnowledgeNode#
class KnowledgeNode(BaseModel):
node_id: str
theorem_name: str
formal_statement: str
domain: str = ""
session_id: str = "" # session that proved this theorem
tags: list[str] = []
created_at: datetime
Storage Locations#
Tier |
Storage |
Location |
|---|---|---|
Tier 1: Episodic |
RAM (process lifetime) |
— |
Tier 2: Persistent |
JSON file |
|
Tier 3: Knowledge graph |
JSON file |
|
Tier 4: Domain insights |
Markdown files |
|
Run artifacts |
Per-session JSON |
|