Roles, Grants, and Selectors
How GoodMem expresses authority — operations paired with selectors, granted directly or bundled into roles — and the rules for changing who has it.
Roles, Grants, and Selectors
Every authorization decision in GoodMem reduces to the same question: does this principal hold this operation over this target? This page explains the vocabulary used to answer it — operations, selectors, grants, and roles — and the rules that govern handing authority out. For where these pieces sit in the overall request flow, start with the security model.
Operations
An operation names one thing a caller can do: READ_MEMORY, CREATE_SPACE, DELETE_USER, MANAGE_ACCESS. Operations are specific to a resource kind — READ_MEMORY applies to memories and nothing else. The full catalog, with each operation's resource kind and the selectors it accepts, is in the operations and selectors reference.
An operation alone says nothing about which memories or spaces it covers. That is the selector's job.
Selectors
A selector scopes an operation to a set of targets. There are four:
| Selector | Covers |
|---|---|
ANY | Every resource the operation applies to, regardless of owner. |
OWN | Resources the principal owns. |
EXACT | One named resource. |
DIRECT_MEMBERS_OF | Resources whose container is the named resource. |
A permission is the pair. READ_MEMORY with ANY reads every memory on the instance. READ_SPACE with EXACT on space X reads space X and no other.
DIRECT_MEMBERS_OF deserves a closer look, because it covers a container's members without covering the container. READ_MEMORY with DIRECT_MEMBERS_OF on space X reads the memories directly contained by X. It does not read X itself, does not reach memories in a sibling space Y, and does not extend to resources X merely references, such as its configured embedders.
A selector is a rule, evaluated fresh on every request. A DIRECT_MEMBERS_OF permission on space X covers every memory X contains now and every memory added to X later; nobody has to update the grant when content arrives. Likewise, OWN follows ownership: if a space is transferred to Sarah, her OWN permissions start covering it at that moment. For a memory, the owner is defined as whoever currently owns its space — memories have no owner of their own.
Direct Grants
A direct grant is the simplest unit of policy: one audience, one operation, one selector, and — for EXACT and DIRECT_MEMBERS_OF — the assigned resource. Granting Sarah READ_SPACE EXACT on space X lets her read X. Granting her READ_MEMORY DIRECT_MEMBERS_OF on X lets her read its memories. Each grant supplies exactly what it names.
The audience is either a single principal or the all-authenticated audience, described next.
All-Authenticated Grants
AllAuthenticatedPrincipals is an audience meaning every human and service identity on the instance, after they authenticate. A grant to this audience is how a space becomes readable by everyone:
(AllAuthenticatedPrincipals, READ_SPACE, EXACT space Y)
(AllAuthenticatedPrincipals, LIST_MEMORY, EXACT space Y)
(AllAuthenticatedPrincipals, READ_MEMORY, DIRECT_MEMBERS_OF space Y)Two restrictions keep this audience bounded. It can receive only EXACT and DIRECT_MEMBERS_OF grants — never ANY or OWN, which have no fixed assigned resource — and it can never receive MANAGE_ACCESS, so shared content access cannot grow into shared policy control.
Authentication is still required; anonymous callers get nothing from these grants. And a caller using a scoped API key still needs a ceiling that covers the request — the audience grant supplies live authority, and the ceiling caps it as usual.
The Share a Space guide shows the commands.
Roles
Granting the same four or five permissions to every collaborator gets old, so GoodMem defines roles: fixed bundles of capabilities defined in the server's code. An administrator cannot edit or redefine them, so a deployment cannot quietly change what ADMIN means.
A role assignment always has the same shape:
(principal, role, assigned resource)The assigned resource determines what the role's capabilities resolve against, and each role is assignable on exactly one kind of resource:
- Instance roles —
USERandADMIN— are assigned on the GoodMem instance and resolveANYorOWNcapabilities.USERis the ordinary bundle for a person or workload operating its own resources;ADMINis the broad administrative bundle. - Space roles —
SPACE_VIEWER,SPACE_CONTRIBUTOR,SPACE_CONTENT_MANAGER, andSPACE_ADMIN— are assigned on one memory space and resolveEXACTorDIRECT_MEMBERS_OFcapabilities on that space. Assigning SarahSPACE_VIEWERon space X gives her read authority over X and its memories. It says nothing about space Y. Sharing Y takes a second assignment.
ROOT appears in the catalog but is a mirror of instance ownership, carries no ordinary capabilities, and cannot be assigned through the API. It moves only when instance ownership moves.
The exact capability set behind each role is tabulated in the built-in roles reference.
Roles and direct grants are additive with each other. A principal's live authority is the union of its direct grants, its role capabilities, and any all-authenticated grants covering the target — plus the ownership-derived rights described below.
Listing and the Two Gates
Reading one resource and enumerating a collection are separate authorities. Every list operation involves two gates:
LIST on the collection — may the caller enumerate at all?
READ on each row — may the caller see this particular item?For top-level catalogs (spaces, embedders, rerankers, LLMs, extensions, users, service identities), the LIST_* gate targets the instance. For memories, LIST_MEMORY targets the space being enumerated.
The gates are independent, and each combination means something:
READwithoutLIST: a direct get succeeds when the caller knows the identifier, but enumeration is denied withPERMISSION_DENIED.LISTwithoutREADon some rows: the list call succeeds and those rows are silently filtered out.
Semantic retrieval follows the same logic. For every space named in a retrieval request, the caller needs LIST_MEMORY EXACT on that space and READ_MEMORY DIRECT_MEMBERS_OF on it. Retrieval across several spaces is all-or-nothing: if either gate fails for any requested space, the whole request is denied rather than quietly searching a subset.
Administering Policy: MANAGE_ACCESS
Creating and revoking grants, and assigning and removing roles, are themselves authorized operations. The operation is MANAGE_ACCESS, and its target is the resource whose policy is changing — the space a role is assigned on, the embedder a grant attaches to. A permission with ANY or OWN has no single assigned resource, so granting one counts as instance policy and requires MANAGE_ACCESS on the instance.
Two sources of this authority exist without any grant, and no grant revocation can remove them:
- An active principal always administers the policy of resources it owns.
- The instance owner administers policy on every resource on the instance, including resources whose recorded owner has been deleted.
Beyond that, MANAGE_ACCESS can be delegated like any other permission: ANY for an instance-wide policy administrator, or EXACT on one resource for a local one. SPACE_ADMIN carries MANAGE_ACCESS EXACT on its assigned space for exactly this purpose.
Delegation has deliberate boundaries:
- Every policy mutation is authorized against the state before the mutation. A principal cannot grant itself the authority that the mutation requires; the request is checked while that authority is still missing.
- A space administrator on X can grant content authority on X and its memories, and can appoint or remove another administrator of X. They cannot manufacture
ANYorOWNpermissions, and they cannot touch policy on Y. - An administrator may revoke their own last delegated permission. Afterward they have lost the authority, while the resource's owner and the instance owner remain — so a space can never be administered into a state nobody can repair.
Ownership Transfer
Transferring a resource to a new owner sits outside the grant system. Two dedicated operations exist:
TRANSFER_RESOURCE_OWNERSHIPmoves an ordinary owned resource — a space, a service identity, an embedder. The current owner, the instance owner, or an instance administrator may perform it. A space role does not suffice, evenSPACE_ADMINwith itsMANAGE_ACCESSon that exact space.TRANSFER_INSTANCE_OWNERSHIPmoves the instance itself, and only its current owner may perform it.ADMIN,MANAGE_ACCESSANY, and every other combination are insufficient.
Neither operation can appear in a direct grant or an all-authenticated grant. The one revocable delegation is the instance administrator role's authority over ordinary resources; nothing delegates transfer of the instance. This keeps an ACL edit — however broad — from ever manufacturing the authority to displace an owner.
A transfer changes ownership and nothing else. Grants, role assignments, and API keys all survive it; from then on, OWN permissions resolve against the new owner, as selectors always do.
See Also
- Built-in Roles — the capability tables behind each role.
- Operations and Selectors — the full catalog and rule syntax.
- Share a Space — the common sharing workflows, with commands.