Appearance
Governance
Memory governance covers three things: who is allowed to read or write memory, how access is recorded, and how tenants are kept apart.
Tenant isolation
Hard. The agents SQLite database is per-Host, per-authority-root. A Host running for tenant A reads and writes its own <host-home>/data/agents/store.db — it has no path to tenant B's database. No cross-tenant query is possible from within the agent platform.
This is not the agent platform's invention; it inherits the bus-level authority root invariant. AgentsRoot.onBootstrap (AgentsRoot.ts:236-244) opens the database at <MATRIX_HOME>/data/agents/store.db, where MATRIX_HOME is set by the Host process for the active authority root.
Per-actor scope
The _resolveScope method on MemoryActor (MemoryActor.ts:115-122) decides which mount a memory write or read is on behalf of:
- If the call comes from
system.agents.<child>, the scope is the payload'smount(the child agent saving for the actor it serves). - If the call comes from
cliorcli-gateway, the caller is admin and may set any mount. - Otherwise, the scope is the caller's own mount (from
meta.from, the bus-set authenticated identity).
This guarantees that a non-admin caller cannot save a memory pretending to be a different actor.
Audit trail
memory_access_log (schema.sql:129-138) records every cross-actor memory access. Columns:
id, accessor_mount, target_mount, op, query, result_count, search_tier, tsA read of own memory is also logged. memory.audit-trail returns the log scoped to a target mount with limit pagination (MemoryActor.accepts.['memory.audit-trail']).
The log is application-level — it does not replace system.observability traces. They are complementary: observability captures which actor invoked which op; audit captures what memory rows were touched.
Cascade enforcement
The cascade (see project memory) is enforced at query time by memoryBelongsToCascade (skills/MemoryCascade.ts). Every result must pass the test against the calling cascade query, which is built from the active profile. There is no path to bypass cascade — even an admin caller's reads are filtered by the cascade specified in the call.
What is NOT yet enforced
- Per-tag deny lists.
permissions.denyexists inToolContextSpec(and is referenced in tool-permission docs) but there is no equivalent on memory queries. - Time-windowed scoping. "Only memories saved in the last 7 days" is not a first-class scope; callers must filter results client-side.
- Encrypted memories at rest. The SQLite database is not encrypted at the column level; rely on filesystem-level disk encryption.
- Per-principal quotas on memory writes. No write-rate limit; large agents could fill the database.
Operator controls
For administrative cleanup, the canonical surface is the $sessionClearAll op on AgentsRoot, which drops sessions, messages, and state — but does not delete memory rows or plans. Memory survives a session clear. To wipe memory entirely, drop the SQLite file (the schema is rebuilt on next boot).
See also
Source:
projects/matrix-3/packages/agents/src/MemoryActor.ts:115-130(scope resolution),projects/matrix-3/packages/agents/src/AgentsStore.ts:584-606(audit log read/write),projects/matrix-3/packages/agents/schema.sql:129-140.