The handbook
TenantsUsers and rolesApplicationsScopesAgentsContext (graphium)CultivatorsChatsTracingAudit log
Concepts

Concepts: Users and roles

Users and roles model identity and authorization within a tenant. A user is the person an application acts as — the human a request runs on behalf of, not the application that makes the call (those live under Applications). A role is a named bundle of scopes. The binding lives in dh_user_roles.

The console exposes both as the Users and Roles pages.

Users

A user record (dh_users) holds the durable identity within a tenant.

FieldPurpose
idUUID, immutable.
display_nameFree text. Self-editable without users:write.
emailLookup key for human users.
external_idOptional handle linking the user to a customer-side identity.
kindperson (impersonable) or system (not). Finer labels live in metadata.subtype.
statusactive or archived. Soft-revocation.
extra_scopesPer-user scopes that augment role scopes. Cannot be self-granted.

The console fetches the current operator's identity via GET /v1/users/me, which also returns the tenant, roles, and effective_scopes in one round trip.

Roles

A role (dh_roles) is a named scope bundle.

FieldPurpose
slugURL handle, immutable.
nameHuman-friendly name.
scopesThe list of scopes granted to anyone assigned this role.
is_defaultWhen true, the role cannot be deleted but can still be edited.

Three default roles ship with every tenant:

  • adminholds acaso_os:admin, the super-scope.
  • memberholds context:write.
  • viewerholds context:read.

Effective scopes

A user's effective scope set is the union of:

  1. An implicit subject:<user_id> scope so policies can self-reference.
  2. The scopes of every role assigned to the user.
  3. The user's extra_scopes.

Adding or removing a role triggers a Redis pubsub event on acaso:key:invalidated so cached entries on other replicas drop within roughly 60 seconds. The console reflects the change on the user's detail page within the same window.

Self-edit rules

  • Any user can edit their own display_name and metadata without holding users:write.
  • A user cannot self-grant extra_scopes. The API returns 403 and the console surfaces the error inline.
  • A user cannot delete themselves.

Audit attribution

Every write through the API records an audit row with actor_key_id set to the session key. Session keys inherit on_behalf_of_subject_id from their parent, so the audit log can resolve every action back to a single human.

Tip: Sharing keys between humans defeats audit attribution. Mint per-human keys.

PreviousConceptsTenantsNext ConceptsApplications