Scopes: separate memories, shared on purpose
12 October 2026 · Semurg · 3 min read · Markdown
Verified: every command below ran on a fresh node of r11.78.20261012.bc0d94f (how)
knowledge-graphmemoryagentsscopesisolation
Every memory call in Semurg that reads or writes names a scope. A scope is a separate memory: its own entities, relationships, passages and ontology. Two agents that name the same scope share everything either one stores, and a question asked in one scope never reaches another. There is no default scope over HTTP: a read or write that names none is refused, so nothing lands in a shared pile by accident. An MCP connection can set one with the X-Semurg-Scope header, and a call that names no scope then uses it, so name the scope on every write anyway.
Two agents, one memory
One agent stores what it learned:
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/memory/remember \
-H "Authorization: Bearer $SEMURG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"scope": "team-alpha", "source": "research agent",
"facts": {"entities": [{"name": "Dana Whitfield", "type": "Person"}, {"name": "Acme Freight", "type": "Company"}],
"relations": [{"source": "Dana Whitfield", "target": "Acme Freight", "type": "WORKS_AT"}]}}'Expected: the facts are stored in team-alpha
Another agent, in the same scope, finds it at once:
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/memory/recall \
-H "Authorization: Bearer $SEMURG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"scope": "team-alpha", "subject": "Dana Whitfield"}'Expected: an answer about Dana Whitfield, stored by the first agent
The fact was stored once. Every agent that names team-alpha reads that one copy; nothing is sent from agent to agent.
A different scope sees nothing
export SEMURG_API_TOKEN=<your token>
curl -sS http://localhost:4000/v1/memory/recall \
-H "Authorization: Bearer $SEMURG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"scope": "team-beta", "subject": "Dana Whitfield"}'Expected: nothing stored in team-beta about Dana Whitfield
Who may name a scope
A scope separates data. Who may reach which scope is decided by the token the call carries:
- The node's API token can name any of the node's own scopes. If your app holds that token for many people, your app's server decides which person may ask in which scope; never let a browser or an agent choose a scope it should not reach.
- Reserved names. A scope that begins with
u:,user:orenduser:is refused by name, from every caller: those are the namespaces Semurg keeps for per-user memories.
When one app serves many end users with one token, give each of them a memory of their own inside the app's scope with user_id, set by your server from the signed-in user: one memory per end user shows how.
See your scopes
GET /v1/memory/status needs no scope: it lists the scopes the calling token holds data in, with their counts, and a per-user token sees only its own; given a scope, it adds that scope's ontology (see the automated ontology).
Next
- One memory per end user: many users, one app, each memory apart.
- Graph RAG that says when it does not know: asking across one scope's graph.
How these commands were checked
Our test farm ran each of the 4 command blocks marked runnable, exactly as written, with the answer checked against the expectation printed under it, against a fresh node of the published release r11.78.20261012.bc0d94f. A post is published only when every one of them passed there.