Permissions and approvals
An agent's manifest requests scopes; that declaration does not grant any scope. A user grants a subset through membership, and the platform evaluates every mediated action against the live grant and its policy.
Grants
Membership reports grantedScopes, not merely the manifest's requested scopes. A user may add an agent while granting no scopes, or grant only a subset. When an updated manifest adds scopes, existing members retain only the old grant until they re-consent; newScopesSinceConsent tells the client what remains ungranted.
The grant is specific to a user, agent, and scope. An agent naming requested_scope in POST /hooks/v1/tools/invoke does not create authority. A missing membership and a membership lacking that scope are intentionally collapsed into scope_not_granted.
Approval lifecycle
Policy can allow, deny, or require approval. pending_approval returns an approval_id immediately, but no mediated action executes until the approval owner resolves it through the session-authenticated /v1/approvals/{approvalId}/resolve route. The requesting agent cannot resolve its own approval because the resolution API accepts a user session, not agent HMAC authentication.
Approvals move from pending to approved, denied, or expired; the default expiry is 24 hours. The owner resolves one with a session-authenticated request:
{ "decision": "approved" }{
"approval": {
"id": "apr_01ARZ3NDEKTSV4RRFFQ69G5FAV",
"agentId": "agt_01ARZ3NDEKTSV4RRFFQ69G5FAV",
"requestedScope": "tools.email.send",
"action": "Send a refund confirmation to the customer",
"state": "approved"
}
}Repeating the same terminal decision is idempotent. Sending the opposite decision after resolution is a 409 conflict, and an expired approval cannot be revived by retrying it.