ASK KNOX
beta
LESSON 590

Namespaces & Authority: Who May Know What

A memory store without access control is a single shared truth for every agent — and one wrong write poisons the fleet.

8 min read·Agent Knowledge Systems

The Problem with One Namespace

The simplest possible memory store has one namespace for everything. Every agent writes to it. Every agent reads from it. At small scale — one agent, one project — this works. At fleet scale, it creates a problem that compounds with every agent added.

Consider a fleet of agents: a content reviewer, a code analyst, a trading monitor, a session summarizer. The code analyst learns that a particular build configuration causes failures in one project. It stores that lesson as a high-confidence memory. On the next session, the trading monitor hydrates its context and receives that memory. The memory is not wrong — it is just irrelevant to every agent except the one that learned it. At 20 agents, each writing lessons into shared space, the signal-to-noise ratio degrades toward noise.

The fix is namespace scoping: partitioning the store into logical regions with explicit read and write rules. Not separate databases — the same store, the same index, the same embeddings — with a WHERE clause that enforces which regions a given agent may access.

Three Scopes

The namespace architecture has three tiers.

Global is the highest-trust region. Any agent in the fleet may read it. Only memories that are universally true — architectural facts, org-wide protocols, hard constraints — belong here. The write cost is higher: a write to global requires elevated confidence and review because a mistake propagates to every agent that hydrates. One wrong lesson in global scope is not a local failure; it is a fleet-wide one.

Per-agent is private. An agent writes its own namespace freely, without review gates. Its observations, working hypotheses, and session-specific lessons stay there. No other agent reads them by default. This isolation is not a restriction — it is a feature. One agent's wrong lesson cannot infect another agent's behavior if the namespace boundary holds.

Shared/team is a working group's collaboration space. An explicit membership list controls who may read and write. A content team shares style guides and feedback patterns. A trading fleet shares halt procedures and configuration notes. Membership is the access primitive: being on the list is what grants access, not namespace knowledge.

ACL in the WHERE Clause

The most important implementation rule is where the access check happens. The wrong approach: fetch all memories, then filter by namespace in application code. This feels equivalent to a WHERE clause but it is not.

When you fetch all rows and filter in TypeScript, the database transmits private rows over the wire. They pass through query logging. They pass through your database connection pool metrics. A bug in your filter logic — a missed case, a typo in the namespace string — silently exposes them. The caller's query also reveals the existence of private data through its cost profile: a slow query with no results tells a sophisticated observer that something is there but gated.

// WRONG: post-hoc filter — private rows are transmitted then discarded
const allMemories = await pool.query("SELECT * FROM memories WHERE deleted_at IS NULL")
const filtered = allMemories.rows.filter(row => allowedNamespaces.includes(row.namespace))

// CORRECT: ACL enforced at the database level
const result = await pool.query(
  "SELECT * FROM memories WHERE namespace = ANY($1) AND deleted_at IS NULL",
  [allowedNamespaces]
)

This is the same principle as the RAG-operations lesson's retrieval ACL filter from the prerequisite track. Tenant isolation in a RAG system and namespace authority in a memory store solve the same class of problem: the enforcement point must be the retrieval itself, not a wrapper applied after the fact.

Write Authority

Read scoping prevents cross-contamination at retrieval time. Write authority prevents it at write time — which is where the more expensive mistakes happen, because a write persists.

Write authority has two gates. The first is agent identity: for namespaces with an explicit allowedWriters list, an agent not on that list is denied regardless of what it wants to write. The global namespace, because of its fleet-wide impact, should have a small, named list of writers. Per-agent namespaces have implicit write authority for the owning agent; no other agent can write there. Shared namespaces use the membership list for both read and write by default, though read-only membership is useful for observers.

The second gate is confidence. A memory that an agent is not certain about — confidence 0.5, synthesized from a single session, unverified — should not be written to global even if the agent is on the writers list. A minimum confidence threshold for global writes is a soft quality floor: it does not stop determined low-quality writes (the agent can inflate its confidence), but it creates friction that correlates with importance.

function checkWriteAuthority(
  agentId: string,
  memory: { namespace: string; confidence: number },
  policy: NamespacePolicy
): { allowed: boolean; reason: string } {
  // Gate 1: identity
  if (policy.allowedWriters.length > 0 && !policy.allowedWriters.includes(agentId)) {
    return { allowed: false, reason: "agent-not-in-writers" }
  }
  // Gate 2: quality
  if (memory.confidence < policy.minWriteConfidence) {
    return { allowed: false, reason: "confidence-below-threshold" }
  }
  return { allowed: true, reason: "authorized" }
}

Cross-Agent Contamination

The failure mode that namespace isolation prevents is cross-agent contamination: one agent's wrong lesson poisoning the beliefs of every other agent through global scope.

A content agent learns that a certain phrase is considered promotional and should be avoided. It stores this as a high-confidence global memory. The trading monitor picks it up on the next hydration. The trading monitor now has a behavioral constraint that was meant for the content team. The constraint is not harmful for trading — it just adds irrelevant context and nudges behavior in ways the operator did not intend.

Now consider the more dangerous version: the content agent stores an incorrect lesson about an API endpoint. It is wrong — the endpoint was renamed, and the agent did not verify. That wrong lesson propagates to every agent that touches that API, each of which now tries to call the old endpoint.

Global scope is the highest-trust surface in the fleet. Treat writes to it with the same caution as writes to a shared production configuration.

Namespace Design for a New Fleet

When standing up a new agent fleet, the namespace architecture starts with three questions. First: what is universally true for every agent? That is the global namespace. Second: what does each agent need to know that no other agent should see? That is per-agent. Third: which agents collaborate on shared state? Those are the shared namespaces, one per working group.

The default for a new memory should be per-agent. Promote to shared or global only when you have confirmed it is both correct and broadly applicable. The cost of demotion — moving a memory back from global to per-agent — is higher than the cost of promotion: the wrong memory may have already propagated to sessions you cannot undo.

What's Next

The memory-hygiene lesson takes the memory store at rest and asks: what happens to its contents over time? Facts decay. APIs change. Endpoints move. The store does not receive world-change events — it only knows what was written. The hygiene discipline — expiring working memories, resolving supersede chains, and verifying before trusting — is what prevents a growing store from becoming a graveyard of confident falsehoods.