Spectron uses two complementary mechanisms:
Contexts — hard isolation between separate products or deployments (each with its own database and keys).
Scope — tags on memory records that partition data within a Context (org, user, project, and so on).
Scope is not the same as permissions. Scope says which bucket a fact belongs to. Principals and grants say who may read or write at which scope paths. Together they define what each caller can trust to see. A principal may delegate grants to another principal, but only up to what they already hold — you cannot grant access you do not have.
Contexts
A Context is the fundamental unit of isolation. Each Context maps to its own SurrealDB (namespace, database) pair holding documents, turns, entities, traces, and configuration. Nothing crosses Context boundaries.
Typical reasons for separate Contexts:
Separate products with no shared memory
Distinct business units
Test versus production environments
Contexts are created through the management API:
API keys are issued per Context — a key for acme-prod cannot access another Context.
Scope tags (data partitioning)
Within a Context, memory records carry scope as an OR of conjunctive clauses — each clause names one or more hierarchical scope paths that must all apply together (AND within the clause, OR across clauses). Typical single-owner facts use one clause; co-ownership uses multiple clauses so more than one principal can read the same record.
You still choose dimensions that match your app: org, user, team, project, region, env, and so on — expressed as paths like org/acme/user/alice/.
How visibility works
On each read, Spectron resolves your grant into the scope nodes you may cover, then finds which scope-set clauses on each record are fully satisfied. A record is visible when at least one clause matches (fail-closed: empty or unmatched scope sees nothing).
For the common case — a single clause with one or two tags — behaviour matches intuitive subset semantics:
| Record clause (simplified) | Query / grant covers | Visible? |
|---|---|---|
{org/acme} only | {org/acme, user/alice} | Yes — org-wide fact visible in user queries |
{org/acme, user/alice} | {org/acme} only | No — user-specific fact hidden from org-only reads |
{org/acme, user/alice} | {org/acme, user/alice} | Yes |
{org/other} | {org/acme, user/alice} | No |
Co-ownership: a document deduplicated across two uploaders may carry two clauses — one per owner — so both can read the same content-addressed file without a separate copy.
Org-wide facts appear in user-level queries; user-specific facts do not appear in org-only queries.
Wire format (ScopeSets)
On the wire, scope selectors use disjunctive normal form — an OR of conjunctive clauses:
| Intent | scopes / lens value |
|---|---|
| Tag or read at one path | [["org/acme/user/alice"]] — or a bare string "org/acme/user/alice" (accepted as a singleton clause) |
| Co-own across two owners (OR) | [["org/acme/user/alice"], ["org/acme/user/bob"]] |
| Require two paths together (AND) | [["org/acme", "org/acme/team/eng"]] |
Writes use
scopeson facts, sessions, uploads, and MCP tools. The legacy field namescopeis still accepted as an alias.Reads use
lenson/query,/context, and MCP recall — same DNF shape, but the lens filters by involvement within your grant; it never widens access.
Warning
Example queries
As a specific user (read lens):
Matches org-wide facts at org/acme and user-specific facts at org/acme/user/alice when your grant covers both.
At org level:
Matches org-wide memory only — not Alice’s private rows unless your grant includes her path.
Register paths before first use: spectron scopes create org/acme/user/alice.
Default write region
When a write omits an explicit scopes selector — Playground chat, a document upload without metadata scopes, or remember without --scope — Spectron tags the new records with the caller's resolved memory:write region (the scope paths your key or brokered token already covers).
Those facts are real and queryable immediately. The Scopes UI lists registered vocabulary paths; an empty tree does not mean no memory exists yet — it means you have not registered named paths for navigation. Use Memory or GET /profile to inspect what was stored under your principal's region, then register paths such as org/acme/user/alice when you want hierarchical partitioning.
On Surrealist, a new context's Overview count of one scope is usually that root write region. Register additional paths (for example surrealdb/employee_1 and surrealdb/employee_2) when you want explicit folders for grants and uploads — see Surrealist dashboard quickstart.
Tombstone vs erase
Two destructive operations sound similar but differ:
| Operation | What it affects | Reversible? |
|---|---|---|
Tombstone scope node (scope:delete, Scopes UI) | The folder entry in the scope vocabulary | Soft-delete — node marked tombstoned; facts may still exist until erased separately |
Scoped forget (POST /scopes/forget) | All facts tagged under a scope subtree | No — permanent erasure for compliance |
See Forgetting memories.
Permissions and delegation
Scope tags partition data. Grants partition access:
A principal receives grant verbs (
memory:read,memory:write,grant:manage, …) on scope paths.Granting to someone else can only convey part or all of what you already have — not broader access.
API keys bind a principal to a scope floor; the server clamps requests that try to escalate.
See Scope as security boundary and API keys and delegation.
Geographic scope
Scope dimensions can include geometry (points, polygons) for territory-based partitioning — e.g. a service region polygon. Spatial predicates compose with semantic and graph signals in the same ranker.
Use cases
Multi-tenancy: One Context, one API key per customer org scoped to org/<id>/.
Per-user isolation: Tag interactions with user/<id>/ so personal memory stays private unless the query includes that user path.
Shared org knowledge: Tag policies with org/acme/ only; tag personal notes with org/acme/user/alice/.
Project context: Add a project/… segment so project-specific instructions surface only in that project’s scope.
Labels, lens, and scope views (reads)
Recall and context endpoints accept optional parameters beyond flat scope tags:
labels— descriptivekey=valuetags (for examplesubject=alice) that filter results within what scope and permissions already allow. Labels help you find facts about something; they do not grant access by themselves.lens— optional hierarchical scope paths that filter by involvement within your grant. A lens ofregion/eureturns every readable clause that includeseu— for example both{eu}and{eu, macbook}— rather than shrinking your access region to exact{eu}matches only.scope_view— controls how broadly results are folded within the caller’s grant:strict(default) — the caller’s own read region only.crossTeam— cross-principal shared reads where grants allow; resolves likestrict.merged— same-fact records at narrower scopes with provenance preserved; resolves likestrict.
None of these widen past a principal’s grant. See REST API for /query and /context request fields.