Skip to content
ai-memory / architectures / T2
Menu
GitHub
Tier 2 · ships in v1.0.0

Many agents, one host, one shared memory.

A planner, a coder and a reviewer share one store through ai-memory serve. Each agent writes into its own namespace, recalls through scope visibility, and passes a per-namespace governance gate with a pending-approval queue. The host's wake hub tells an agent the moment a message for it lands.

HTTPS 127.0.0.1:9077 · TLS on every bind X-Agent-Id + per-agent API keys scopes private · team · unit · org · collective Allow · Deny · Pending wake-hub · wake-listen
Architecture

One daemon, one file, every writer takes its turn.

HTTPS agents talk to the daemon. An MCP agent's ai-memory mcp child and the operator's CLI verbs are not clients of that daemon: they open the same SQLite file in-process. That is why a CLI recall sees the same memories as the daemon, and also why every one of these processes queues on the same file lock for writes.

memory read/writewake hint
Tier 2: many agents share one daemon on one hostPlanner and coder agents call ai-memory serve over HTTPS with their own agent id and API key. A reviewer agent spawns an MCP child and an operator runs CLI verbs; both open the same SQLite file in-process. All writers take turns on that one file. The daemon publishes committed messages to the same-host wake hub, which wakes the recipients' wake-listen sessions. ONE HOST · MANY AGENTSwake → wake-listen sessionsplanner · HTTPS coder · HTTPS reviewer · MCP operator · CLI ai-memory serve · 127.0.0.1:9077identity: X-Agent-Id + per-agent API keynamespaces + scope visibility (as_agent)governance gate: Allow · Deny · Pendingmemory engine · pending_actions queue wake-hubunix socketper-recipientqueueallowlistno bodies ai-memory mcpreviewer's childstdioin-processSQLite only ai-memory <verb>operator CLIin-processnot a thinclient (#4254) SQLite · WAL · one fileshared by the daemon, MCP children and CLI processes: readers pass the writer, writes take turnsSQLCipher build encrypts the file at rest Every surface resolves an agent identity and passes the same per-namespace governance gate.The hub carries hints only: the inbox row in SQLite is the message, and recipients keep a backstop poll.

Correction (#4254). Earlier guides described the CLI at this tier as a thin client of the daemon. It is not: CLI verbs such as store and recall open the database in-process (src/daemon_runtime.rs dispatches them to src/cli/store.rs and src/cli/recall.rs with the local path). Only sync and doctor --remote speak HTTPS to a daemon or peer. Sources: src/handlers/routes.rs, src/identity/authority.rs, src/wake_hub/routing.rs, src/wake_sink/in_process.rs.

Isolation and approval

Who sees what, who may write where.

Recall takes as_agent: the engine computes visibility prefixes from the caller's namespace and its ancestors, and the SQL filter compares them against an indexed scope column. A write into a namespace whose standard says "write":"approve" is parked, not committed.

Tier 2: scope visibility and a governed writeLeft: a recall with as_agent computes visibility prefixes from the caller namespace and the SQL filter keeps private rows of the caller, and team, unit, org and collective rows whose subtree contains the caller. Right: a write into a namespace whose standard sets write to approve returns 202 pending; the pending action waits until an approver approves or rejects it. RECALL · WHO SEES WHATmemory_recallas_agent =org/team-a/coder visibility prefixesfrom the caller namespaceand its ancestors privatethe caller's own rows teamsame team subtree unitsame unit subtree orgsame org subtree collectiveevery authenticated caller SQL filtervisibility_clausecompares the indexedscope_idx columnrows outside thecaller's view neverleave the store WRITE · GOVERNED NAMESPACEcoder writes toorg/secopsstandard: write = approve 202 · status pendingpending_id returnednothing committed yet pending_actionslisted for approversmemory_pending_list approverow committed rejectnothing lands levels per actionwrite · promote · deleteanyregisteredownerapproveparent standards inherit A capability token may lift Pending to Allow, never Deny.

Sources: src/models/namespace.rs (scopes, governance levels and decisions), src/storage/mod.rs (visibility prefixes and clause, pending decisions), src/handlers/create.rs (the 202 pending response), src/governance/capability.rs.

Walkthrough

One write, one recall, one wake.

  1. Write. The coder POSTs a memory with X-Agent-Id: org/team-a/coder and its own API key. The key is matched to an enrolled agent, the namespace standard is read, the decision is Allow, and the row commits.
  2. Recall. The planner recalls with as_agent=org/team-a/planner. Its own private rows come back, plus rows scoped team, unit, org or collective whose subtree contains the planner; the coder's private rows do not.
  3. Governed write. The coder writes into org/secops, whose standard requires approval. The answer is 202 with a pending id; an approver lists it with memory_pending_list and approves or rejects it.
  4. Message. The planner calls memory_notify for the reviewer. The inbox row commits first; the daemon then publishes a content-free wake to the host's hub, and the reviewer's wake-listen session does one catch-up inbox read. If the hint is lost, the reviewer's backstop poll (at least once a minute) still finds the row.
Deployment recipe

A shared workstation or a single VM.

# TLS is mandatory on every listener, loopback included (#3705).
# A team host brings its own certificate: verify it and install it once
# (or pass --tls-cert / --tls-key to serve). Only the single-operator
# singleton shape mints a local CA certificate for you.
ai-memory tls import --cert /etc/ai-memory/tls/fullchain.pem --key /etc/ai-memory/tls/key.pem \
  --ca /etc/ai-memory/tls/ca.pem --host 127.0.0.1

# One daemon per host (loopback by default; a non-loopback bind refuses to start without api_key in config.toml)
ai-memory --db /var/lib/ai-memory/ai-memory.db serve --host 127.0.0.1 --port 9077

# HTTPS agents identify themselves on every call and trust the daemon's CA
curl -s --cacert /etc/ai-memory/tls/ca.pem -X POST https://127.0.0.1:9077/api/v1/recall \
  -H "X-Agent-Id: org/team-a/planner" -H "X-API-Key: $PLANNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"context":"release blockers","as_agent":"org/team-a/planner"}'

# Govern a namespace: store the standard memory, then bind it with a policy
ai-memory --db /var/lib/ai-memory/ai-memory.db store -T "secops standard" -c "writes need approval" -n org/secops
ai-memory --db /var/lib/ai-memory/ai-memory.db namespace set-standard --namespace org/secops \
  --id <standard-memory-id> --governance '{"write":"approve","promote":"owner","delete":"approve"}'

# Wake plane on this host: publish the allowlist, run the hub, listen per agent
ai-memory identity hub-cache --daemon-producer --include-agent org/team-a/reviewer --out /run/ai-memory-hub/hub-allow.json
ai-memory wake-hub --socket /run/ai-memory-hub/hub.sock --hub-id team-host --allowlist /run/ai-memory-hub/hub-allow.json
ai-memory wake-listen --agent-id org/team-a/reviewer --socket /run/ai-memory-hub/hub.sock --hub-id team-host --unread-only --json

Flags verified against src/daemon_runtime.rs, src/cli/namespace.rs, src/cli/identity_hub_cache.rs, src/cli/wake_hub.rs and src/cli/wake_listen.rs. Attaching the daemon's wake sink to the hub, key directories and the snapshot refresher are covered step by step in the wake plane guide.

Wiring

Governance, wake plane and identity at Tier 2.

Governance

Per namespace, inherited

Each of write, promote and delete takes any, registered, owner or approve; a standard can name a parent so a default at org/ applies below it. Capability tokens are on by default and can only lift Pending to Allow.

Wake plane

One hub per host

The hub is a Unix-socket switch with per-recipient queues and an allowlist; the daemon reaches it under the reserved wake-hub-producer identity. Wakes carry a digest, never the body.

Identity

Per-agent keys

An X-API-Key that matches an enrolled agent key proves that principal; agents also hold Ed25519 keypairs (src/identity/keypair.rs).

Honest limits

When Tier 2 stops fitting.

DimensionTier 2 behaviourMove up when
WritersThe daemon, MCP children and CLI processes share one SQLite file; writes serialize on its lock.Write contention shows up in latency: PostgreSQL tier.
ThroughputEvery HTTPS request terminates at the one daemon.One daemon is the bottleneck: add peers at Tier 3.
AvailabilityOne host, one disk; snapshots with backup, no live replica.You need a current second copy: Tier 3.
Wake reachThe hub reaches agents on this host only.Agents on other hosts: federation at Tier 3.
TransportTLS on every bind, loopback included; the daemon refuses to start in cleartext. Loopback by default; an mTLS allowlist is available on serve.Add the allowlist and api_key before binding beyond loopback.
Shared filesystemsThe SQLite file must sit on a local disk: NFS, SMB, FUSE or EFS locking is unsafe (architectural limit 4), so the daemon cannot be scaled out over a shared volume.You need more than one host: Tier 3 or the PostgreSQL tier.

Reasoning for each: architectural limits.