Concepts: Scopes
A scope is the unit of authorization throughout AcasoOS — a colon-delimited string such as users:read or agents:team-finder:run. Every privileged endpoint, RLS policy, and tool call resolves yes/no against the caller's effective scope set using one segment-wise matching rule.
Anatomy
namespace : resource ( : action )?Examples:
users:readlist and view users.agents:team-finder:runrun the agent namedteam-finder.team:engineeringa tenant-specific scope.acaso_os:adminthe super-scope.
The full canonical catalog is served by GET /v1/scopes/catalog and rendered in the Role editor's picker. See Reference: Scope catalog for the v1 list.
Segment-wise matching
A holder scope matches a required scope when each segment matches. A * segment is a single-segment wildcard.
| Required | Holder | Result |
|---|---|---|
context:read | context:read | match |
team:engineering | team:* | match |
team:engineering:senior | team:* | no match (segment count differs) |
| anything | acaso_os:admin | match (short-circuit) |
context:read | * | no match (bare * is rejected at write time) |
acaso_os:admin short-circuits to true against any required scope. Bare * is rejected at write time so nobody can grant unbounded access by accident.
The same algorithm runs in Postgres (acaso_scope_matches_one, acaso_scopes_match) for RLS policies and in Python (acaso_shared.auth.scope_matching) for tool and agent listing filters. A parity test keeps the two in sync. The same matching also bounds an application's scope_ceiling — see Concepts: Applications.
Where scopes are checked
Scopes gate four surfaces, each independently:
Sidebar visibility
Nav items declare requiredScopes and are hidden when the active connection's effective_scopes does not satisfy them.
Page direct access
Routes render an "Insufficient permissions" empty state rather than issue a request that would 403.
RLS policies
Tenant-scoped tables have tenant_and_scope_isolation. A row gated by required_scopes is invisible to a caller whose session scopes do not match.
Tool invocation
Agent.required_scopes and @tool(required_scopes=...) both gate the LLM's tool list AND re-check at call time. Double lock.
Custom scopes
Tenant-specific scopes such as team:engineering or project:atlas live outside the canonical catalog. Add them to roles via the Role editor's free-form chips input. The matching rules apply identically; the catalog is just reference metadata for the picker.
Note: Custom scopes are syntax-validated as lowercase segment-wise strings. Bare
*is rejected at every write surface.