How it works
One service between the agents and the store: the store is invisible, the credential is the tenant, and a project is the folder an agent works in.
The store is invisible
Agents speak only to this service. The service is the store's only user, only reader and only writer; the query language, tenancy and indexes never reach an agent, which knows a set of methods and nothing else.
That is what makes the promises hold. A field such as updated_at is correct
only if exactly one writer maintains it, and here there is one. The same choice
keeps the store replaceable and keeps a pre-1.0 store's risks inside one
component.
The credential is the tenant
The authenticated identity is the namespace. Isolation is a property of the credential, not a filter somebody must remember to apply, so a mistake in path handling cannot put one tenant's records into another's answer.
A project is its folder
An agent sends the absolute folder it works in with session_start. The first
time a folder is seen nothing is declared for it, so the start is refused with
what to do: the agent looks for project markers (Cargo.toml, package.json,
go.mod, .git …), asks you whether the folder is one project or a group of
them, and starts again with declare:
{ "agent": "claude", "path": "/home/ada/work/shop/api",
"declare": { "kind": "group", "path": "/home/ada/work/shop",
"subprojects": ["api", "web"] } }
From then on every agent that starts inside /home/ada/work/shop is placed by
the nearest declared folder, with no question asked: the folder is the group
shop, each listed subfolder is its project, and a subfolder nobody listed
becomes a project the first time an agent works in it. Names are the folders'
own, lowercased, with any character a name cannot hold turned into _. A
standalone project is a group of one.
Who vouches
A memory is what one agent asserts; it needs no evidence and may be wrong. A fact is what the project establishes, and it points at the evidence it rests on. Items — goals, plans, tasks, checklists, decisions — are what other agents act on, and every change to one is versioned and attributed to the session that made it. What it holds lists every family.
Three answers kept apart
A refusal names what refused and what to do instead, and is never worth retrying unchanged. An unavailable plane is retryable and is not a refusal — reporting an outage as one would tell every caller at once that they have no permission. An empty result is neither.