Scopes
A scope is a string that names a specific action an agent is authorized to take. Every
DelegationCert.scope field is a list of scope strings, and the verifier checks that the
action being attempted is covered by the chain’s effective scope (the lex-sorted
intersection of every cert in the chain).
The full canonical vocabulary at v1.0.0-alpha.7:
┌──────────────────────────────────────────────────────────────┐│ Ratify v1 scope vocabulary ││ ││ 53 canonical scopes • 14 wildcards • custom: extension │└──────────────────────────────────────────────────────────────┘Stability: every scope listed below is stable in v1. New scopes can be added in minor versions without breaking existing certs; nothing on this page is going to be renamed or removed.
Why a canonical vocabulary
Section titled “Why a canonical vocabulary”Without one, every integrator invents their own scope strings — read, read:files,
files.read, Files.Read, FILE_READ — all meaning the same thing and none of them
cross-compatible. That’s the OAuth scope graveyard. Ratify fixes it by having the protocol
define the set: every SDK exports the same constants, every verifier recognizes the same
vocabulary, every issuer signs against the same strings.
The full list lives in
scope.go (Go),
scope.ts
(TypeScript), scope.py
(Python), scope.rs
(Rust), and ratify.h
(C/C++). All five are byte-for-byte aligned via the conformance suite.
The 16 domains
Section titled “The 16 domains”The 53 canonical scopes group into 16 first-level domains. Sensitive scopes are marked with a 🔒 — they are NEVER introduced by wildcard expansion (§9.1) and must always be granted explicitly.
Meetings (6 scopes)
Section titled “Meetings (6 scopes)”| Scope | Purpose |
|---|---|
meeting:attend | Join a meeting as a listener |
meeting:speak | Speak / transmit audio in a meeting |
meeting:video | Transmit video in a meeting |
meeting:chat | Post messages in meeting chat |
meeting:share_screen | Share screen in a meeting |
meeting:record 🔒 | Record a meeting |
Communications (8 scopes)
Section titled “Communications (8 scopes)”| Scope | Purpose |
|---|---|
comms:message:read | Read direct / group messages |
comms:message:send | Send messages |
comms:message:delete 🔒 | Delete sent messages |
comms:email:read | Read email |
comms:email:send | Send email |
comms:email:delete 🔒 | Delete email |
comms:calendar:read | Read calendar events |
comms:calendar:write | Create / modify calendar events |
Files (2 scopes)
Section titled “Files (2 scopes)”| Scope | Purpose |
|---|---|
files:read | Read files |
files:write 🔒 | Create / modify files |
Identity (2 scopes)
Section titled “Identity (2 scopes)”| Scope | Purpose |
|---|---|
identity:prove | Present proof of identity (used for authn flows) |
identity:delegate 🔒 | Sub-delegate authority to another agent. Required on the parent cert for any sub-delegation to be accepted. |
Transactions (2 scopes)
Section titled “Transactions (2 scopes)”| Scope | Purpose |
|---|---|
transact:purchase | Buy a good or service |
transact:sell | Sell a good or service |
Payments (3 scopes)
Section titled “Payments (3 scopes)”| Scope | Purpose |
|---|---|
payments:send | Initiate an outbound payment |
payments:receive | Accept an inbound payment |
payments:authorize 🔒 | Authorize movement of funds — separated from send so a delegation can be “may receive but never debit” |
Contracts (2 scopes)
Section titled “Contracts (2 scopes)”| Scope | Purpose |
|---|---|
contract:read | Read contract terms |
contract:sign 🔒 | Enter into a binding agreement |
Data (5 scopes)
Section titled “Data (5 scopes)”| Scope | Purpose |
|---|---|
data:read | Read data records |
data:write 🔒 | Create or modify data records |
data:delete 🔒 | Delete data records |
data:export 🔒 | Bulk export — data-exfiltration concern, separated from read |
data:share | Share specific records with a third party |
Execute (2 scopes)
Section titled “Execute (2 scopes)”| Scope | Purpose |
|---|---|
execute:tool | Invoke a tool / function call (MCP-style) |
execute:code 🔒 | Execute arbitrary code on the principal’s behalf |
Generate (2 scopes)
Section titled “Generate (2 scopes)”| Scope | Purpose |
|---|---|
generate:content | Generate content (text, image, etc.) |
generate:deepfake 🔒 | Generate content intended to impersonate someone — separated so platforms can refuse this scope universally |
Physical (4 scopes)
Section titled “Physical (4 scopes)”| Scope | Purpose |
|---|---|
physical:enter | Enter a physical zone (badge access, geofence cross) |
physical:exit | Exit a physical zone |
physical:actuate 🔒 | Activate a physical actuator — valve, motor, switch, robot end-effector |
physical:manipulate 🔒 | Manipulate physical objects (grasping, moving, assembling) |
Robots (3 scopes)
Section titled “Robots (3 scopes)”| Scope | Purpose |
|---|---|
robot:operate | General robot operation — sensor readings, state queries |
robot:move | Autonomous locomotion (the robot may move in space) |
robot:interact | Interact with humans or other robots (gesture, speech, handoff) |
Robot scopes are not individually marked sensitive, but high-stakes robot operations
(picking up a knife, opening a valve) should be composed with physical:manipulate 🔒 or
physical:actuate 🔒 so the human consent is explicit.
Drones (3 scopes)
Section titled “Drones (3 scopes)”| Scope | Purpose |
|---|---|
drone:fly 🔒 | Fly a drone — sensitive because of airspace + safety risks |
drone:deliver | Deliver a package via drone |
drone:capture | Capture imagery / sensor data from a drone |
Vehicles (3 scopes)
Section titled “Vehicles (3 scopes)”| Scope | Purpose |
|---|---|
vehicle:operate 🔒 | Operate a vehicle (drive, ride, command) |
vehicle:transport | Use a vehicle as a passenger / payload carrier |
vehicle:charge | Initiate vehicle charging or refueling |
Infrastructure (3 scopes)
Section titled “Infrastructure (3 scopes)”| Scope | Purpose |
|---|---|
infrastructure:monitor | Read infrastructure metrics (temperature, flow, voltage) |
infrastructure:control 🔒 | Control infrastructure systems (HVAC, power, water) |
infrastructure:access 🔒 | Gain administrative access to infrastructure |
Actuators (3 scopes)
Section titled “Actuators (3 scopes)”| Scope | Purpose |
|---|---|
actuate:valve 🔒 | Open / close a physical valve |
actuate:motor 🔒 | Energize / de-energize a motor |
actuate:switch 🔒 | Flip an electrical switch |
Every actuator scope is sensitive by design — physical-world actions get explicit delegation.
Sensitive scopes — what the marker means
Section titled “Sensitive scopes — what the marker means”There are 22 sensitive scopes in v1 (every 🔒 above). The protocol enforces three rules around them:
- No wildcard introduction. A wildcard like
comms:*expands to its non-sensitive members only. Grantingcomms:*does NOT includecomms:message:delete🔒 orcomms:email:delete🔒 — those must be listed explicitly in the cert’s scope. - No
identity:delegateshortcut. Even withidentity:delegate🔒 on the parent cert, the child cert can only sub-delegate scopes the parent itself held. The sub-delegation gate (delegation_not_authorized) keeps the chain bounded. - Verifier UX recommendation. Verifiers SHOULD highlight sensitive scopes in any user-facing prompt (“Agent wants to delete your messages, are you sure?”) even when the delegation is valid.
The authoritative list is
sensitiveScopes in
the Go reference. All five SDKs expose is_sensitive(scope) / IsSensitive(scope) /
isSensitive(scope) — in C, use ratify_scope_is_sensitive(scope).
Wildcards
Section titled “Wildcards”For ergonomics, Ratify defines 14 wildcards that expand into a set of non-sensitive scopes from the same domain:
| Wildcard | Expands to (non-sensitive members only) |
|---|---|
meeting:* | meeting:attend, meeting:speak, meeting:video, meeting:chat, meeting:share_screen (excludes meeting:record 🔒) |
comms:message:* | comms:message:read, comms:message:send (excludes comms:message:delete 🔒) |
comms:email:* | comms:email:read, comms:email:send (excludes comms:email:delete 🔒) |
comms:* | All of comms:message:*, comms:email:*, and comms:calendar:read + comms:calendar:write |
transact:* | transact:purchase, transact:sell |
payments:* | payments:send, payments:receive (excludes payments:authorize 🔒) |
data:* | data:read, data:share (excludes data:write 🔒, data:delete 🔒, data:export 🔒) |
execute:* | execute:tool (excludes execute:code 🔒) |
generate:* | generate:content (excludes generate:deepfake 🔒) |
physical:* | physical:enter, physical:exit (excludes physical:actuate 🔒, physical:manipulate 🔒) |
robot:* | robot:operate, robot:move, robot:interact |
drone:* | drone:deliver, drone:capture (excludes drone:fly 🔒) |
vehicle:* | vehicle:transport, vehicle:charge (excludes vehicle:operate 🔒) |
infrastructure:* | infrastructure:monitor (excludes infrastructure:control 🔒, infrastructure:access 🔒) |
files:*, identity:*, contract:*, and actuate:* are not defined as wildcards —
every scope in those domains is either sensitive or singleton, so wildcards would either
expand to nothing useful or introduce a sensitive scope (which the protocol forbids).
When a wildcard appears in a DelegationCert.scope list, the SDK expands it during
verification — the cert’s signable bytes still contain the wildcard form, but the effective
scope used for intersection / required-scope checks contains the expanded set.
Custom scopes
Section titled “Custom scopes”If you need an application-specific scope outside the canonical set, prefix it with
custom::
custom:acme:invoice:approvecustom:my-platform:moderate-contentcustom:internal:archive:purgeCustom scopes:
- Are accepted by
validate_scopes()/ValidateScopes()without lookup against the canonical list. - Pass through
expand_scopes()/ExpandScopes()unchanged (they don’t participate in wildcard expansion). - Are treated as non-sensitive by default unless the application opts in via out-of-band policy.
- Do not have cross-application meaning —
custom:acme:invoice:approveissued by Acme Corp is meaningless to a verifier outside Acme’s ecosystem.
The intent is to let teams ship Ratify-secured features that aren’t yet part of the canonical vocabulary, without forking the protocol. If a custom scope sees broad adoption, file a proposal to add it to the canonical set in a minor version.
Effective scope across a chain
Section titled “Effective scope across a chain”When a chain has more than one cert, the effective scope is the lex-sorted intersection of every cert’s expanded scope list:
Alice → Agent A: ["meeting:attend", "meeting:speak", "identity:delegate"]Agent A → Agent B: ["meeting:attend"]
Effective scope of [A→B, Alice→A]: ["meeting:attend"]Two implications:
- A child can never have more than the parent. The intersection is monotonically shrinking.
identity:delegatedoesn’t propagate downward. Even though Alice granted Aidentity:delegate, B’s effective scope doesn’t include it — A didn’t grant it onward. B cannot mint further sub-delegations.
This is the foundation of Ratify’s least-privilege story: every link in the chain can only narrow, never broaden, what the previous link granted.
Programmatic access
Section titled “Programmatic access”All five SDKs export the canonical scope strings as constants. Use them so the compiler / linter catches typos before they reach the verifier:
// Goimport "github.com/identities-ai/ratify-protocol"ratify.ScopeMeetingAttend // "meeting:attend"ratify.ScopeIdentityDelegate // "identity:delegate"ratify.IsSensitive(s) // boolratify.ExpandScopes(scopes) // []string with wildcards expandedratify.IntersectScopes(a, b, c) // []string lex-sorted intersection// TypeScriptimport { SCOPE_MEETING_ATTEND, SCOPE_IDENTITY_DELEGATE, isSensitive, expandScopes, intersectScopes,} from "@identities-ai/ratify-protocol";# Pythonfrom ratify_protocol import ( SCOPE_MEETING_ATTEND, SCOPE_IDENTITY_DELEGATE, is_sensitive, expand_scopes, intersect_scopes,)// Rustuse ratify_protocol::{ SCOPE_MEETING_ATTEND, SCOPE_IDENTITY_DELEGATE, is_sensitive, expand_scopes, intersect_scopes,};Where to next
Section titled “Where to next”- Constraints — geo / time / amount / rate gates that ride on top of scopes
- Delegate → Present → Verify — how scopes flow through the protocol
- Provider architecture — the §17 hooks for policy / revocation / audit