---
title: "Scopes: separate memories, shared on purpose"
slug: knowledge-layer-6-scopes
date: 2026-10-12
author: Semurg
section: how-to
tags: [knowledge-graph, memory, agents, scopes, isolation]
summary: Every memory read or write names a scope, a separate memory. Agents that name the same scope share what they learn; a question in one scope never reaches another. Who may name a scope is decided by the token, or by your server.
status: published
covers: [route:POST /v1/memory/remember, route:POST /v1/memory/recall, route:GET /v1/memory/status, mcp:memory_remember, mcp:memory_recall]
---
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

> Diagram scopes: Two agents that name the same scope read and write one shared memory; an agent that names a different scope reaches a separate memory and sees nothing of the first.

One agent stores what it learned:

```bash runnable kind=shell-node needs=token
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"}]}}'
```

```expect
expect: the facts are stored in team-alpha
assert: json:.ok==true
```

Another agent, in the same scope, finds it at once:

```bash runnable kind=shell-node needs=token
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"}'
```

```expect
expect: an answer about Dana Whitfield, stored by the first agent
assert: json:.state=="answered"
```

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

```bash runnable kind=shell-node needs=token
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"}'
```

```expect
expect: nothing stored in team-beta about Dana Whitfield
assert: json:.state=="nothing_stored"
```

## 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:` or `enduser:` 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](/blog/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](/blog/knowledge-layer-2-the-automated-ontology)).

### For coding agents: Rules for an agent using Semurg memory scopes

- [ ] Name the scope on every memory call that reads or writes; an MCP connection's X-Semurg-Scope header is only a default, and a write that relies on it can land in the wrong memory.
- [ ] Use the same scope name as every agent and program that should share what you learn, and a different one for anything that must stay apart.
- [ ] Never choose a scope the user did not give you or the app did not assign; a scope separates data, and the app decides who may reach it.
- [ ] Treat nothing_stored in one scope as knowing nothing there, never as knowledge about another scope.

The check that proves it:

```bash
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"}'
```

Passes when: a fact stored in another scope is not found here

## Next

- [One memory per end user](/blog/one-memory-per-end-user): many users, one app, each memory apart.
- [Graph RAG that says when it does not know](/blog/knowledge-layer-4-graph-rag): asking across one scope's graph.
