Use this file to discover all available pages before exploring further.
Spacebot’s memory system is not markdown files. Not unstructured blocks in a vector database. It’s a typed, graph-connected knowledge system — and this opinionated structure is why agents are productive out of the box.Every memory has a type, an importance score, and graph edges connecting it to related memories. The agent doesn’t just “remember things” — it knows the difference between a fact it learned, a decision that was made, a goal it’s working toward, and a preference the user expressed.
// From src/memory/types.rspub enum MemoryType { Fact, // Something that is true Preference, // Something the user likes or dislikes Decision, // A choice that was made Identity, // Core information about who the user is or who the agent is Event, // Something that happened Observation, // Something the system noticed Goal, // Something the user or agent wants to achieve Todo, // An actionable task or reminder}
Memories connect to each other via typed relationships:
// From src/memory/types.rspub enum RelationType { RelatedTo, // General semantic connection Updates, // Newer version of the same information Contradicts, // Conflicting information CausedBy, // Causal relationship ResultOf, // Result relationship PartOf, // Hierarchical relationship}
When a memory is created, it’s automatically associated with similar memories:
// From src/memory/store.rs// After saving to SQLite, search for similar memorieslet similar = embedding_table.vector_search(&embedding, 5).await?;for (existing_id, distance) in similar { let similarity = 1.0 - distance; if similarity > 0.9 { // Very similar — likely an update create_association(memory_id, existing_id, RelationType::Updates); } else if similarity > 0.7 { // Semantically related create_association(memory_id, existing_id, RelationType::RelatedTo); }}
// From src/memory/search.rspub enum SearchMode { Hybrid, // Vector + FTS + graph + RRF (default) Recent, // Most recent by created_at Important, // Highest importance first Typed, // Filter by MemoryType with configurable sort}
Hybrid search is the default — used by branches when the user asks a question.Recent and Important are metadata-only queries (no embeddings, no FTS).Typed filters by MemoryType and sorts by Recent, Importance, or MostAccessed.
During context compaction, the compactor worker extracts memories from summarized messages:
// From src/agent/compactor.rs// Compaction worker has memory_save toollet system_prompt = r#"You are a compaction worker. Your job:1. Summarize the provided conversation turns2. Extract any memorable facts, decisions, or preferences3. Save them using memory_save"#;
This ensures context that gets compacted away is preserved as structured knowledge.
The cortex creates observations and consolidates memories system-wide:
// From src/agent/cortex.rs// Cortex notices patterns across channelsif user_mentioned_timezone_3_times { memory_save( "User is based in America/New_York timezone", MemoryType::Identity, 0.9 );}
Memory importance is influenced by:Explicit importance — Set by the LLM or derived from memory typeAccess frequency — Memories that are recalled often get boosted
// From src/memory/store.rspub async fn record_access(&self, id: &str) -> Result<()> { sqlx::query( "UPDATE memories SET last_accessed_at = ?, access_count = access_count + 1 WHERE id = ?" ) .bind(chrono::Utc::now()) .bind(id) .execute(&self.pool) .await?;}
Recency — Recent memories score higher in searchGraph centrality — Memories with many connections are more important
let all_memories = store.get_all().await?;for memory in all_memories { let embedding = embedding_model.embed_one(&memory.content).await?; embedding_table.upsert(&memory.id, &embedding).await?;}
The cortex generates a periodically refreshed summary of the agent’s knowledge:
// From src/agent/cortex.rslet bulletin_prompt = r#"You are the cortex. Generate a brief memory bulletin.Recall memories across these dimensions:- Identity (who the user is)- Recent events- Active goals- Important decisions- Key preferencesSynthesize into a 500-word briefing."#;
This bulletin is injected into every channel’s system prompt:
let bulletin = runtime_config.memory_bulletin.load();
Every channel gets ambient awareness without querying the database.
CREATE TABLE memories ( id TEXT PRIMARY KEY, content TEXT NOT NULL, memory_type TEXT NOT NULL, importance REAL NOT NULL, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, last_accessed_at TIMESTAMP NOT NULL, access_count INTEGER NOT NULL DEFAULT 0, source TEXT, channel_id TEXT, forgotten BOOLEAN NOT NULL DEFAULT 0);CREATE TABLE associations ( id TEXT PRIMARY KEY, source_id TEXT NOT NULL, target_id TEXT NOT NULL, relation_type TEXT NOT NULL, weight REAL NOT NULL, created_at TIMESTAMP NOT NULL, FOREIGN KEY (source_id) REFERENCES memories(id), FOREIGN KEY (target_id) REFERENCES memories(id));