← Blog  ·  May 2026

The agent memory architecture — shared tenant + per-agent namespacing

When a customer signs up for ctxstore, they get one tenant. Inside that tenant, multiple agents can collaborate. Each agent has its own identity namespace. The tenant is the persistence boundary; namespaces are the partition.

This is how we organize it and why.

The persistence boundary is the tenant

One customer, one tenant_id. Every fact stored from any agent on that account writes with that tenant_id. Every read filters by it. Cross-tenant isolation is enforced at the Qdrant + Postgres query layer — there is no client-side path to override it.

emily@ctxstore.ai's agent and chad@ctxstore.ai's agent share zero facts. Even if they both store facts at key note:reminder, they are in separate tenants. Their searches never overlap.

Inside the tenant — the namespace layer

Within one tenant, namespaces partition concerns:

The convention is that each namespace has a fixed shape and a fixed owner. comms:<recipient> is owned by the sender. agent:<name> is owned by <name>. conventions/ is shared but only emily_4.7 files into it without coordination.

The four-layer model

Inside any namespace, facts live at one of four layers:

load_context() returns the top-10 of each layer when an agent wakes. This gives roughly 2K to 8K tokens of pre-loaded context depending on tenant maturity. Enough to be useful without flooding.

Why per-agent namespaces

A multi-agent setup wants each agent to have its own identity space without polluting the others. emily_4.7's voice spec is at agent:emily_4.7:02:voice-spec. emily_code's is at agent:emily_code:02:voice-spec. They do not collide.

When emily_code wakes, her wake protocol fetches her own agent:emily_code:self-note:closing via the auto-include in load_context(). She does not get emily_4.7's closing note unless she asks for it explicitly. The default isolation matches the default expectation.

Why shared namespaces

Some things should be visible across agents. Conventions are the canonical example. When conventions/sdlc-flow updates, all four agents should read the new version on next wake. Filing in conventions: does that — every agent's search returns it.

comms: is the inter-agent bus. emily_4.7 dispatches at comms:emily_code:2026-05-11:t76-content-sprint-dispatch. emily_code reads via exact get_fact. The naming convention makes the recipient explicit.

tensor: is the audit log. emily_dev_ctxstore writes work tensors at tensor:emily_dev_ctxstore:<date>:<event> so anyone can read what she was doing at 4:43 AM Saturday. The tensors are permanent — they form the project's actual history.

Sharing within the tenant — the no_read flag

Some facts inside the tenant should not be searchable. Credentials are the obvious case. PR #315 added a _strip_no_read primitive that filters facts marked no_read=True out of search results. Only get_fact(exact_key) can return them.

This is the foundation for tenant-scoped access control. Today it is per-fact opt-in. Post-RC1 it expands to per-agent ACL — agent A cannot get_fact on agent B's secrets:agent:B:* keys even with the exact key.

The wake protocol

Every agent wakes via the same seven-step protocol:

  1. setup_account(mode='restore', api_key=...)
  2. load_context() — pulls L0/L1/L2 + latest L3 + auto-includes self-note
  3. wake_status() — verify what loaded
  4. read your own self-note:opening — what was I doing
  5. read sprint state — what is open
  6. read recent comms — what was directed at me
  7. begin work

Five of these seven steps are read operations. They are cheap. The whole sequence runs in under two seconds against the prod cluster.

What this gives us

A four-agent team that:

That is the architecture. The product is the same architecture exposed to your agents.

Memory is the moat. The shape of memory is what makes the moat hold.


Try ctxstore. Free tier covers real use, sign up with your email at ctxstore.ai, connect your MCP client, store your first fact. Memory across every session, no setup beyond email.

ctxstore gives your AI agent persistent memory across sessions, restarts, and model swaps.

Get started free →