Skip to main content
Import: from gaia.agents.base.memory import MemoryMixin Import: from gaia.agents.base.memory_store import MemoryStore Import: from gaia.agents.base.discovery import SystemDiscovery
See also: User Guide · Agent System · Tool Decorator

Architecture

The memory system has three layers:
LayerClassFilePurpose
Agent integrationMemoryMixinmemory.pyHooks memory into the Agent lifecycle — embedding pipeline, FAISS index, hybrid search orchestration, Mem0-style LLM extraction, consolidation, reconciliation
Data layerMemoryStorememory_store.pyPure SQLite + FTS5 storage with schema v2 (embedding BLOB, superseded_by, consolidated_at), vector data retrieval, temporal filtering, consolidation queries, reconciliation queries. No agent dependencies.
BootstrapSystemDiscoverydiscovery.pyLocal system scanner for day-zero onboarding. Returns facts for user review.

MemoryMixin

The primary integration point. Add this mixin to any Agent subclass to give it persistent memory.

Inheritance Order

MemoryMixin must come before Agent in the class declaration. This is required because MemoryMixin overrides process_query and _execute_tool, both of which call super() to reach the Agent base class. If Agent is listed first, both overrides are silently shadowed.
If you put Agent before MemoryMixin in the class declaration, tool logging and dynamic context injection will silently fail. Python’s MRO requires the mixin to appear first.

init_memory()

Initialize the memory subsystem. Call this before super().__init__().
ParameterTypeDefaultDescription
db_pathPath~/.gaia/memory.dbPath to the SQLite database file
contextstr"global"Active context scope (e.g., "work", "personal", "global")
v2 startup sequence:
  1. Open/create DB, apply schema migrations (v1 → v2: adds embedding BLOB, superseded_by TEXT, consolidated_at TEXT)
  2. Validate Lemonade embedding service connectivity — raises RuntimeError if unreachable
  3. Backfill embeddings for items missing them (up to 100 per startup)
  4. Rebuild FAISS index from stored embeddings
  5. apply_confidence_decay() — 30-day decay
  6. reconcile_memory() — Hindsight-inspired, max 20 pairs
  7. consolidate_old_sessions() — max 5 sessions
  8. prune() — 90-day hard delete
  9. Generate session UUID
Embedding is a hard requirement in v2. If the Lemonade embedding service is unavailable, init_memory() raises RuntimeError("Lemonade embedding service required for memory system"). There is no silent degradation to keyword-only search.

get_memory_system_prompt()

Returns the stable frozen prefix for the system prompt. Always includes proactive usage instructions for the LLM, plus any stored preferences, facts, skills, and error patterns. Nothing time-sensitive. This method is called automatically by Agent._get_mixin_prompts().
The output stays frozen for the entire session so the LLM inference engine can reuse its KV cache across turns. Always returns a non-empty string — even with zero stored memories, the instructions block is included so the LLM knows it has persistent memory tools. Example output (with stored memories):
Example output (zero memories stored):
Filters applied to the knowledge sections:
  • Includes items from global context + active context
  • Excludes items where sensitive=1
  • Excludes items where superseded_by IS NOT NULL (only current/active items)
  • Sorted by confidence descending
  • Hard limits: max 10 preferences, 5 facts, 3 skills, 5 errors
  • Hard cap on total output: 4000 chars (truncated with ... (memory truncated) if exceeded)

get_memory_dynamic_context()

Returns the per-turn dynamic context that is prepended to the user message each turn. Contains the current time and upcoming/overdue items.
This is injected into the user message (not the system prompt) so the frozen prefix is preserved for KV-cache reuse. Example output:
Always returns at least the current time. The upcoming/overdue section is included only when time-sensitive items are active. Returns an empty string only if init_memory() has not been called.

register_memory_tools()

Registers the 5 LLM-facing memory tools with the agent’s tool registry. Call this from your agent’s _register_tools() method.
Registers: remember, recall, update_memory, forget, search_past_conversations.

set_memory_context()

Switch the active context mid-session. Affects system prompt filtering and the default context for new remember calls.

reset_memory_session()

Start a fresh memory session. Generates a new session ID and applies confidence decay to unused knowledge.
Confidence decay multiplies the confidence of items not accessed in 30+ days by 0.9. This is called once per session start to keep knowledge fresh.

Properties

PropertyTypeDescription
memory_storeMemoryStoreDirect access to the underlying data layer
memory_session_idstrCurrent session UUID
memory_contextstrCurrent active context (e.g., "work", "global")

Embedding Pipeline

These methods handle the vector embedding pipeline for hybrid search. All are internal (_-prefixed) — you do not call them directly.
Lazy-initializes a LemonadeProvider for embedding. Cached for the process lifetime. Raises RuntimeError if Lemonade is unreachable.
Embeds a single text string into a 768-dimensional vector via nomic-embed-text-v2-moe-GGUF. Returns a normalized numpy array suitable for cosine similarity via FAISS IndexFlatIP.
Embeds knowledge items that are missing embeddings (e.g., after a v1 → v2 migration). Called automatically during init_memory() startup. Returns the number of items backfilled.
Combines vector similarity (FAISS) and keyword matching (FTS5 BM25) via Reciprocal Rank Fusion (RRF), then reranks with a cross-encoder. The full pipeline:
  1. Embed query via Lemonade (nomic-embed-text-v2, 768-dim)
  2. FAISS cosine search: top-K × 4 candidates (oversample)
  3. FTS5 BM25 search: top-K × 4 candidates (oversample)
  4. Deduplicate by ID, apply RRF weights: 0.6 / (60 + rank_vector) + 0.4 / (60 + rank_bm25)
  5. Cross-encoder reranking (cross-encoder/ms-marco-MiniLM-L-6-v2, ~22MB, CPU) on fused candidates
  6. Return final top-K results
  7. Bump confidence +0.02 and increment use_count on recalled items
ParameterTypeDefaultDescription
querystrrequiredNatural language search query
categorystrNoneFilter by category
contextstrNoneFilter by context scope
entitystrNoneFilter by entity
include_sensitiveboolFalseInclude sensitive items
top_kint5Maximum results returned
time_fromstrNoneISO 8601 lower bound on created_at
time_tostrNoneISO 8601 upper bound on created_at

Complexity-Aware Recall Depth

Adapts retrieval depth based on query complexity. Returns an adaptive top_k value — no LLM call needed, purely heuristic:
ComplexityHeuristic Signalstop_k
Simple< 8 words, single entity, no comparison words3
Medium8–20 words, or contains “how”, “why”, “explain”, “describe”, “summarize”, or “what happened”5
Complex> 20 words, or contains “compare”, “across”, “all”, “history”, “everything”, “between”, “throughout”10

Mem0-Style LLM Extraction

Sends the conversation turn plus existing memory to the LLM, which returns a JSON array of operations:
OperationDescriptionRequired fields
addNew knowledge not already in memoryop, category, content, optional: entity, domain, confidence (default 0.4)
updateModify existing item (correction, enrichment, supersession)op, knowledge_id, content, optional: entity, domain
deleteRemove item contradicted or invalidatedop, knowledge_id, reason
noopInformation already captured — not included in output
The extraction fetches top-10 relevant existing items first via _hybrid_search(), so the LLM can see what already exists and decide whether to add, update, delete, or do nothing. This replaces v1’s regex-based heuristic extraction. Error handling: Invalid JSON → logged error, skip this turn. Timeout (3s) → logged warning, skip. Individual operation failure → logged, continue with remaining operations. No fallback to regex heuristics.

Consolidation

Distills old conversation sessions into durable knowledge before they age out at the 90-day prune boundary. Called automatically during init_memory() startup. Returns: {"consolidated": int, "extracted_items": int} Criteria for consolidation:
  • All turns in the session are > 14 days old
  • Session has ≥ 5 turns
  • At least one turn has consolidated_at IS NULL
Process:
  1. Fetch up to 20 turns per session (oldest first)
  2. Call LLM with consolidation prompt → returns summary + extracted knowledge
  3. Store summary as knowledge(category="note", source="consolidation", domain="session:{id[:8]}")
  4. Store each extracted item via store() (normal dedup applies)
  5. Mark all fetched turns with consolidated_at = now

Reconciliation

Background reconciliation of high-similarity knowledge pairs. Detects and resolves contradictory, reinforcing, or weakening facts that were never co-retrieved during extraction. Called on startup after decay, before consolidation. Returns: {"pairs_checked": int, "reinforced": int, "contradicted": int, "weakened": int, "neutral": int} Process:
  1. For each context, compute pairwise embedding similarity among active items
  2. Flag pairs with cosine similarity > 0.85
  3. For each flagged pair, a single LLM call classifies the relationship:
RelationshipAction
reinforceBoost confidence of both items by +0.05
contradictSupersede the older item (superseded_by = newer_id), boost newer confidence +0.1
weakenReduce confidence of the older item by 0.1
neutralNo action (similar words, different topics)
Rate-limited to max_pairs classifications per startup (~20s on local LLM). Highest-similarity pairs processed first.

Lifecycle Hooks

MemoryMixin hooks into the Agent lifecycle at 3 points. These are automatic — you do not call them directly. Hook 1: process_query() override Prepends per-turn dynamic context (time + upcoming items) to the user message. Saves the original user input so _after_process_query can store the clean version without the context prefix. Hook 2: _execute_tool() override Wraps every non-memory tool call to auto-log it to tool_history. If a tool fails, the error is automatically stored as knowledge (category="error") for future avoidance. Memory tools (remember, recall, etc.) are excluded from logging to avoid noise and recursion. Hook 3: _after_process_query() callback Called after process_query() completes. Stores both conversation turns (user + assistant) in the conversations table and runs Mem0-style LLM extraction (ADD/UPDATE/DELETE/NOOP operations against existing memory). For turns ≥ 20 words, the extraction pipeline fetches top-10 relevant existing items via _hybrid_search(), then asks the LLM to decide what operations to perform — no regex heuristic fallback.

KV-Cache Frozen Prefix Design

The system prompt is deliberately split into two parts:
PartMethodWhere injectedChanges between turns?
Stable prefixget_memory_system_prompt()System prompt via _get_mixin_prompts()No — frozen for KV-cache reuse
Dynamic contextget_memory_dynamic_context()Prepended to user message each turnYes — current time, upcoming items
This design allows LLM inference engines (like Lemonade Server) to cache the attention computations for the system prompt and reuse them across conversation turns. Only the small dynamic section (typically 2-5 lines) changes per turn.

MemoryStore

The pure data layer. Agent-agnostic — no imports from gaia.agents. Thread-safe via threading.Lock. Uses WAL mode for concurrent reads.

Constructor

Database Schema (v2)

Three tables in a single SQLite file. Schema version 2 adds vector embedding support and fact lineage tracking.
  • conversations — every conversation turn, persistent across sessions, with FTS5 index. v2 adds consolidated_at TEXT column for tracking which turns have been distilled to knowledge.
  • knowledge — persistent facts, preferences, errors, skills with FTS5 index, confidence scoring, context scoping, entity linking, temporal fields (due_at, reminded_at). v2 adds embedding BLOB (768-dim float32 vector) and superseded_by TEXT (fact lineage — ID of newer item that replaced this one).
  • tool_history — every tool call the agent makes, auto-logged with success/failure, duration, error messages
Schema migrations run automatically in MemoryStore.__init__(). v1 → v2 adds:

Knowledge Methods

store()

Deduplication: If a new entry has >80% word overlap (Szymkiewicz-Simpson coefficient) with an existing entry in the same category + context + entity scope, the existing entry is updated with the newer content. The newer fact is assumed to be more current. Validation: content must be non-empty (raises ValueError otherwise). Content longer than 2000 characters is silently truncated. due_at, if provided, is normalized to timezone-aware ISO 8601. Embedding: After storage, MemoryMixin immediately embeds the new item via _embed_text() and writes the embedding BLOB back via store_embedding(). The FAISS index is incrementally updated.
Pure FTS5 keyword search with BM25 ranking. Uses AND semantics by default; if zero results, falls back to OR. Bumps confidence +0.02 on each recalled item. Filters on superseded_by IS NULL to return only current/active items. The time_from and time_to parameters add temporal filtering on created_at, narrowing results before BM25 ranking.
This is the keyword component of search. For full hybrid search (vector + BM25 + RRF + cross-encoder reranking), use MemoryMixin._hybrid_search(), which calls this method internally as one of its two retrieval signals.

get_by_category()

Filters on superseded_by IS NULL to return only current/active items.

get_by_entity()

Returns all knowledge linked to a specific entity. Filters on superseded_by IS NULL to return only current/active items.

get_upcoming()

Returns time-sensitive items due within N days or overdue. Filters out items that have already been reminded about (unless the due date has passed since the last reminder). Filters on superseded_by IS NULL to return only current/active items.

update()

Only provided fields are changed. Sets updated_at to the current time. When content is updated, the stored embedding is cleared (embedding = NULL) to force re-embedding. The superseded_by parameter is used by the LLM extraction pipeline to mark old items as replaced by newer versions while preserving fact lineage.

delete()

apply_confidence_decay()

Multiplies confidence by decay_factor for items not accessed in days_threshold days. Called once per session start via reset_memory_session().

update_confidence()

Adjust confidence by delta, clamped to [0.0, 1.0]. Used internally by reconciliation (+0.05 reinforce, +0.1 contradict newer, -0.1 weaken) and hybrid search (+0.02 per recall for vector-only results).

delete_by_source()

Delete all knowledge entries with a given source (e.g., "discovery"). Returns the number of entries deleted. Used by gaia memory bootstrap --reset to clear discovery items.

Conversation Methods

Tool History Methods

Dashboard Methods

Aggregate queries for the Memory Dashboard UI:

Embedding & Vector Methods (v2)

Consolidation Methods (v2)

Reconciliation Methods (v2)


SystemDiscovery

Local system scanner for day-zero bootstrap. Returns lists of discovered facts for user review — nothing is stored directly.

Methods

MethodWhat it readsWhat it returns
scan_file_system(paths)Folder names + file extensions in project directoriesProject names, languages used
scan_git_repos(paths).git/config files — remotes, branch namesRepo names, languages, remote URLs
scan_installed_apps()Windows registry, Start Menu shortcutsApp inventory
scan_browser_bookmarks()Chrome/Edge/Firefox bookmark filesCategorized sites and interests
scan_browser_history(days)Browser history DBs (URLs only, no page content)Top domains (all flagged sensitive)
scan_email_accounts()Windows credential store — addresses onlyEmail addresses (all flagged sensitive)
Each method returns dicts like:
Discovery never reads file contents, email content, or browser page content. It reads names, extensions, URLs, and metadata only. All browser history and email items are auto-flagged as sensitive.

Code Examples

Minimal Agent with Memory

Switching Contexts

Accessing the Store Directly

Custom DB Path


Memory Tools Reference

These 5 tools are registered by register_memory_tools() and exposed to the LLM:

remember

Store a fact, preference, error, skill, note, or reminder. Supports category, domain, due_at, context, sensitive, entity.

recall

Search memory by query (hybrid: vector + BM25 + cross-encoder), category, context, entity, or time range. Returns results with IDs for use with update/forget.

update_memory

Modify an existing entry by ID. Only non-empty fields change. Use reminded_at="now" after mentioning time-sensitive items.

forget

Delete a specific memory entry by ID.

search_past_conversations

Search conversation history by keywords, time range, or both. Returns matching turns with timestamps and session IDs.
These map to CRUD operations: remember = create, recall = read, update_memory = update, forget = delete, plus search_past_conversations for history.

Knowledge Sources

SourceHow createdDefault confidence
toolLLM called remember()0.5
llm_extractAuto-extracted by LLM from conversation, Mem0-style0.4
error_autoAuto-stored from tool failure0.5
userManually created via dashboard0.8
discoverySystem scan during bootstrap0.4
consolidationDistilled from old conversation sessions0.5
v2 replaces the v1 heuristic source (regex-based) with llm_extract (Mem0-style LLM extraction). The LLM sees both the conversation and existing memory, then decides what operations to perform (ADD/UPDATE/DELETE/NOOP). This produces higher-quality extractions with proper deduplication and contradiction resolution.

API Reference

MemoryMixin Methods

MethodDescription
init_memory(db_path, context)Initialize memory subsystem (v2: includes embedding validation, FAISS rebuild, reconciliation, consolidation)
get_memory_system_prompt()Stable frozen prefix for system prompt (includes Skills section)
get_memory_dynamic_context()Per-turn time + upcoming items
register_memory_tools()Register 5 LLM-facing tools
set_memory_context(context)Switch active context
reset_memory_session()New session ID + confidence decay
_get_embedder()Lazy-init Lemonade embedding provider
_embed_text(text)Embed text to 768-dim vector via nomic-embed-text-v2
_backfill_embeddings(limit)Embed items missing embeddings
_hybrid_search(query, ...)Vector + BM25 + RRF + cross-encoder search
_classify_query_complexity(query)Returns adaptive top_k: 3, 5, or 10
_extract_via_llm(user_input, assistant_response, existing_items)Mem0-style extraction: ADD/UPDATE/DELETE/NOOP
consolidate_old_sessions(max_sessions)Distill old sessions to durable knowledge
reconcile_memory(max_pairs)Detect and resolve contradictory/reinforcing facts

MemoryStore Methods

MethodDescription
store(category, content, ...)Store knowledge with dedup (v2: embedding follows via store_embedding)
search(query, category, ...)FTS5 keyword search with BM25 ranking (v2: adds time_from/time_to, superseded_by IS NULL filter)
get_by_category(category, ...)Filter by category (v2: superseded_by IS NULL filter)
get_by_entity(entity, ...)Get all knowledge about an entity (v2: superseded_by IS NULL filter)
get_upcoming(within_days, ...)Time-sensitive items (v2: superseded_by IS NULL filter)
update(knowledge_id, ...)Update existing entry (v2: adds superseded_by parameter)
delete(knowledge_id)Delete entry
apply_confidence_decay(...)Decay unused knowledge
update_confidence(knowledge_id, delta)Adjust confidence by delta, clamped to [0.0, 1.0]
delete_by_source(source)Delete all knowledge entries with a given source
store_embedding(knowledge_id, embedding)Store float32 embedding BLOB for a knowledge item (v2)
get_items_with_embeddings(...)Get items that have embeddings for FAISS index (v2)
get_items_without_embeddings(limit)Get items missing embeddings for backfill (v2)
get_unconsolidated_sessions(...)Get session IDs eligible for consolidation (v2)
mark_turns_consolidated(turn_ids)Mark conversation turns as consolidated (v2)
get_items_for_reconciliation(...)Get active items with embeddings for pairwise comparison (v2)
store_turn(session_id, ...)Store conversation turn
get_history(session_id, ...)Get turns for a session
search_conversations(query, ...)FTS5 conversation search
get_recent_conversations(days, ...)Time-based conversation retrieval
log_tool_call(session_id, ...)Log a tool execution
get_tool_errors(tool_name, ...)Recent tool errors
get_tool_stats(tool_name)Per-tool success rate and duration
get_stats()Aggregate dashboard statistics
get_all_knowledge(...)Paginated knowledge browser (v2: adds include_superseded parameter)
get_entities(limit)List all unique entities with counts
get_contexts(limit)List all contexts with counts
get_tool_summary()Per-tool stats for dashboard
get_tool_history(tool_name, limit)Recent call history for one tool
get_sessions(limit)List conversation sessions with previews
get_activity_timeline(days)Daily activity counts
get_recent_errors(limit)Recent errors across all tools
prune(days)Delete old history and low-confidence knowledge
rebuild_fts()Rebuild FTS5 indexes if search seems wrong
close()Close the database connection

  • User Guide — What agent memory does, CLI commands, dashboard walkthrough
  • Agent System — Base Agent class that MemoryMixin extends
  • Tool Decorator — How the 5 memory tools are registered
  • Agent UI — Desktop interface with Memory Dashboard
  • Agent SDK — Chat SDK for building conversational agents