Skip to content

Memory

system.agents.memory is the per-actor memory store. It lives in the same SQLite database as sessions and embeddings, but on different tables. Its job is to let an agent or its caller persist freeform text records, search them by content, and group them by mount and target.

What's stored

From schema.sql:22-33 (memories):

ColumnPurpose
idautoincrement primary key
mountthe actor mount this memory belongs to
target_keyoptional: the target the memory is about
profile_keyoptional: the agency profile that wrote it
scopeone of actor (default), subtree, class, instance, session, profile (see MemoryScope in profiles/AgencyProfile.ts:3)
contentthe memory text
tagsJSON array of strings
realmoptional realm tag (cross-actor grouping)
created_atepoch-ms

There is also an FTS5 virtual table (memories_fts) and triggers that mirror inserts/deletes from the main table.

What's NOT stored

Memory is not the place for:

  • Inference call traces (those go to observability via actorLog and to session-level appendActivityFrames).
  • Tool call records (those live in session_messages rows).
  • Embeddings of the memory content (those go to memory_embeddings keyed by memory_id).
  • Inference credentials. Ever.

Search tiers

MemoryActor declares an accept op memory.searchTier that returns which tier is active. Three tiers exist (MemoryActor.ts and AgentsStore.ts:231-249):

TierMethodWhen
likeSQLite LIKE %query%always available
fts5FTS5 MATCH with BM25 ranking, Porter stemming, unicode61 tokenizerwhen sqlite was built with FTS5 (hasFts5 is true)
hybridVector + FTS5, falls back to FTS5, falls back to LIKEwhen EmbeddingService has a working provider

The "search degrades gracefully" promise is enforced by checking hasFts5 and provider availability at call time.

Scope cascade

memoryBelongsToCascade in skills/MemoryCascade.ts decides whether a stored memory is visible to a given query based on its scope. The intended order (broadest to narrowest) per MemoryScope:

global  >  class    >  subtree  >  actor
                   >  profile  >  instance
                                       >  session  >  none

A query at scope: 'actor' returns memories saved at actor, subtree, class, and global. A query at scope: 'session' returns only the current session's memories.

Plans

The same actor (MemoryActor) also owns plans (schema.sql:59-82) — structured work plans with steps, status (pending/in-progress/done/skipped), and execution tracking (plan_executions records who started a step, when it completed, and the output). plan.create, plan.update, plan.active, plan.complete, plan.history, plan.execute, plan.execution-complete, plan.executions are all in MemoryActor.accepts.

Audit trail

memory_access_log (schema.sql:129-138) records every cross-actor read/write. memory.audit-trail returns it, scoped to a target mount, with limit pagination. This is application-level audit — system-level observability lives in system.observability.

See also

Source: projects/matrix-3/packages/agents/src/MemoryActor.ts:79-102 (accepts), projects/matrix-3/packages/agents/src/AgentsStore.ts:182-265 (memory CRUD), projects/matrix-3/packages/agents/schema.sql:22-140 (tables and audit log).