Skip to content

Session schema

Three tables hold session state in <host-home>/data/agents/store.db. Schema version is 2 (schema.sql:9).

Table: sessions

sql
CREATE TABLE sessions (
  id            TEXT PRIMARY KEY,
  target_key    TEXT NOT NULL,
  profile_key   TEXT NOT NULL DEFAULT 'default',
  principal_id  TEXT,
  title         TEXT,
  turn_count    INTEGER DEFAULT 0,
  created_at    INTEGER NOT NULL,
  last_active   INTEGER NOT NULL
);
CREATE INDEX idx_session_target         ON sessions(target_key, last_active);
CREATE INDEX idx_session_target_profile ON sessions(target_key, profile_key, last_active);

TypeScript view (AgentsStore.ts:63-72):

ts
interface SessionMeta {
  id: string;
  targetKey: string;
  profileKey: string;
  principalId: string | null;
  title: string | null;
  turnCount: number;
  createdAt: number;
  lastActive: number;
}

Table: session_messages

sql
CREATE TABLE session_messages (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  session_id    TEXT NOT NULL REFERENCES sessions(id),
  role          TEXT NOT NULL,        -- user | assistant | tool
  content       TEXT NOT NULL,
  tool_name     TEXT,
  tool_call_id  TEXT,
  tool_target   TEXT,
  tool_op       TEXT,
  tool_args     TEXT,                 -- JSON
  tool_result   TEXT,                 -- JSON
  tool_duration_ms INTEGER,
  trace_id      TEXT,
  span_id       TEXT,
  model_id      TEXT,
  ts            INTEGER NOT NULL
);
CREATE INDEX idx_msg_session ON session_messages(session_id, ts);

TypeScript view (AgentsStore.ts:74-88):

ts
interface SessionMessage {
  role: 'user' | 'assistant' | 'tool';
  content: string;
  toolName?: string;
  toolCallId?: string;
  toolTarget?: string;
  toolOp?: string;
  toolArgs?: unknown;
  toolResult?: unknown;
  toolDurationMs?: number;
  traceId?: string;
  spanId?: string;
  modelId?: string;
  ts: number;
}

Table: session_state

sql
CREATE TABLE session_state (
  session_id   TEXT NOT NULL REFERENCES sessions(id),
  key          TEXT NOT NULL,    -- 'repl_state' | 'snapshot' | custom
  value        TEXT NOT NULL,    -- JSON
  updated_at   INTEGER NOT NULL,
  PRIMARY KEY (session_id, key)
);

Known keys today: repl_state (omega-lisp REPL serialization) and snapshot (target-actor introspect tree at session start). Callers may use additional keys for application-specific state.

Activity-frame log (NOT in SQLite)

Activity frames are persisted via the IAgentSessionStore interface, not in the agents/store.db. Two backends:

  • FileAgentSessionStore — frames written to <host-home>/sessions/<sessionId>/activity-<requestId>.jsonl (one JSON object per line).
  • RecordBackedSessionStore — frames written as records into the observability record store.

The ActivityFrame shape is documented under Trace schema.

Cascading deletes

AgentsStore.deleteSession(sessionId) (AgentsStore.ts:562-570) runs in a transaction:

ts
DELETE FROM session_messages WHERE session_id = ?
DELETE FROM session_state    WHERE session_id = ?
DELETE FROM sessions         WHERE id         = ?

Activity frames in the file/record backend are NOT deleted — that is the responsibility of the backend's own retention policy. To wipe everything for a session, drop the row and any matching <host-home>/sessions/<sessionId>/ directory.

See also

Source: projects/matrix-3/packages/agents/schema.sql:146-184 (the three tables), projects/matrix-3/packages/agents/src/AgentsStore.ts:63-88 (TypeScript shapes), projects/matrix-3/packages/agents/src/IAgentSessionStore.ts:36-50 (alternate SessionMeta shape used by file/record backends).