Skip to content

Build1 publisher3 min readPublished

Enforcing agent memory isolation at the storage prefix costs one dataset per user

A runnable two-agent example moves every refusal into the catalog that vends credentials, because a key covers a storage prefix and there are no rows at the point of enforcement. The author works on that catalog.

The Engineer · Build desk

Illustration accompanying Enforcing agent memory isolation at the storage prefix costs one dataset per user

What happened

  • A dev.to post publishes a runnable example in which two agents keep private memory in one catalog, file skill proposals they cannot publish, and wait for a human to promote them.
  • The usual scoping column cannot be enforced there, because the catalog vends a credential for a storage prefix and at the moment of enforcement there are no rows to filter, only bytes at a path.
  • Tagging rights are delegated apart from data rights, so a reviewer can label a dataset they cannot read and a writer cannot strip a sensitivity label from data they can rewrite.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost Per-user isolation is priced in datasets, one per user, and whoever provisions pays for the boundary they pick; grouping by tenant is cheaper only when the tenant really is the trust boundary.
  • decision The trust boundary has to be settled before provisioning, because the grant attaches to a dataset and application code cannot narrow it afterwards.
  • capability Audit trails stop depending on the agent's honesty about its own identity, since a forged byline would require credentials for another agent's queue.
  • constraint The argument binds only where the agent itself holds the keys; when a service keeps the credential and filters rows for callers, enforcement sits back in code this design treats as compromised.

Ask this catalog for access and what comes back is a credential for a location: a prefix in object storage, scoped to a dataset [5]. Everything under that prefix is reachable by whoever holds the keys [5]. In the post's words, "at the moment of enforcement there are no rows" [6]. A user_id filter therefore has to be applied by code that already holds the bytes, and in this design that code is the agent. The agent is assumed hostile, and every refusal comes from the catalog [3].

The second leak is the index. One shared recall dataset lets anyone who can read it vector-search every memory it indexes, whatever the paths inside look like [7]. "Similarity does not respect a whose column," the author wrote [8]. So a scope is entries plus the index beside them: a dataset of entries, a Lance index, each a separate registered object with its own grant [10]. Only the decision log at the end of the build is Iceberg [10].

Count the objects in the published example. Two agents that must not read each other get two datasets, in two namespaces, with two grants [9]. Each proposer also gets its own queue dataset [17]. With a Lance index beside each memory dataset, that comes to at least six grantable objects for two agents [23].

The queue was supposed to be write-only. "An inbox: you may post, you may not rummage," the post says [14]. The relationship model would not express it: reading data resolves through a relation that includes writing it, so granting modify confers select, along with can_drop, can_rename and can_set_protection [15]. A shared queue would have been readable by every agent that could write to it, and droppable by any one of them [16]. Per-proposer queues change what attribution is, because an agent cannot file under another agent's name without credentials for that dataset [17].

Tag rights are split from data rights. A compliance reviewer can label something they cannot read, and someone who can rewrite a dataset cannot quietly strip the label, because removing a tag is gated on the tag rather than on the object [19]. Under the relationship model this build runs, no authorizer reads the tag value and the grant stays the gate [20]. The author says Cedar, which the catalog also supports, decides from attributes on the resource, and that is the direction the work is heading [20].

The bill is object count. Per-user isolation means a dataset per user [12]. Where the team or the tenant is the real boundary, the post says one dataset for the group is correct and cheaper [12]. "The dataset is the unit of access, so it has to equal the unit of trust," the author wrote [13]. The post does not give a per-dataset cost.

For any of this to transfer, your enforcement point has to look like this one: keys handed to the agent, scoped to a path [5]. Where a memory service holds the credential itself and never hands it over, the row filter is enforced by that service's code, and this design starts from the assumption that such code is compromised [3]. The author states the interest plainly: "I work on the catalog in question, so read the comparisons below with that in mind" [2]. The comparisons named are mem0's user_id, a vector database metadata filter and a Databricks key [4].

Review is the part the post concedes does not scale: forty proposals arrive overnight, one matters, and the reviewer reads all forty or none [21]. One in forty is 2.5 percent [22].

What to watch

  • Whether Cedar policies in this catalog let a tag value decide access, which the relationship model does not do today.
  • Whether a dataset per user holds up at thousands of users, and what the catalog charges per registered dataset.
  • Whether mem0 or vector database vendors answer the claim that row and metadata scoping cannot be enforced against a hostile agent.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories