Capabilities
Hierarchical capability names, caveats, delegation, and how the SecurityGateway matches them at request time.
Every operation on every protocol requires a capability. Capabilities are hierarchical strings; the security gateway matches them against the caller's resolved identity using exact / protocol-wildcard / global-wildcard semantics.
The naming scheme
map.{protocol_id}.{operation}| Capability | Grants |
|---|---|
map.macs.auth_negotiation | Exactly one operation |
map.macs.* | Every operation on MACS |
map.*.* | Every operation on every protocol (admin) |
map.mind.read | Read-side operations on MIND (alias for store_memory.read, etc.) |
The exact-match path is preferred. Wildcards are a convenience for ops/admin tenants and for treaties that grant a counterparty an entire protocol surface.
The struct
pub struct AgentCapability {
pub name: String,
pub expires_at: Option<chrono::DateTime<Utc>>,
pub limits: Option<CapabilityLimits>,
pub caveats: Vec<String>,
}
pub struct CapabilityLimits {
/// Per-call max spend in basis-points of tenant budget.
pub max_per_call_bps: Option<u32>,
/// Per-hour rate cap.
pub max_per_hour: Option<u32>,
/// Hard token ceiling per call (overrides MEAL default).
pub max_tokens: Option<u32>,
}caveats is a free-form vector of policy strings the policy engine (MAXIM) interprets. Common caveats:
time:09-17— only valid 09:00–17:00 UTCjurisdiction:eu— only valid for EU-tagged requestsweekly_budget:5000— bound to a weekly spend cap
Where capabilities come from
ResolvedAgentIdentity.capabilities
= OAS_document.declared_capabilities
+ Aegis.active_delegations(did)
+ MOAT.active_treaty_capabilities(tenant, foreign_tenant)
- revokedThe composition happens during MACS::derive and runs every request. Caching is per-tenant with a short TTL (default 60s) so revocations propagate quickly.
How matching works
fn is_operation_allowed(caps: &[AgentCapability], protocol: &str, op: &str) -> bool {
let exact = format!("map.{}.{}", protocol.to_lowercase(), op);
let proto_w = format!("map.{}.*", protocol.to_lowercase());
let global = "map.*.*";
caps.iter()
.filter(|c| !c.is_expired())
.filter(|c| c.caveats_satisfied_in_current_context())
.any(|c| c.name == exact || c.name == proto_w || c.name == global)
}This runs at Stage 4 of the pipeline. A miss returns CoreError::CapabilityDenied { protocol, operation }.
Wildcard rules
map.*alone — does not match. Wildcards must terminate a leaf segment.map.macs.*— matches every MACS operation.map.*.read— does not match. Cross-protocol wildcards are not allowed.map.*.*— admin escape hatch. Reserved for ops tenants.
The restriction on map.*.read is deliberate. It prevents accidental over-granting when the same operation name appears in multiple protocols.
Reading capabilities inside a protocol module
fn require_capability(id: &ResolvedAgentIdentity, op: &str) -> Result<(), ProtocolError> {
let needed = format!("map.{}.{}", "marc", op);
if id.has_capability(&needed) {
Ok(())
} else {
Err(ProtocolError::MissingCapability(needed))
}
}The engine has already checked at Stage 4 — but protocols often re-check inside invoke to enforce fine-grained permissions (e.g., MARC::synthesize may require both map.marc.synthesize and map.mind.snapshot to bind the world model).
Delegations
Via Aegis::delegate, an entity can issue a bounded capability to another entity. The delegation is a signed token that includes:
pub struct DelegationToken {
pub from_did: String,
pub to_did: String,
pub capabilities: Vec<AgentCapability>,
pub max_redelegation_depth: u32, // anti-amplification
pub expires_at: chrono::DateTime<Utc>,
pub revocation_url: Option<String>,
pub signature: Signature,
}The no-amplification rule is enforced at delegation time: the delegate cannot receive capabilities the delegator does not hold. Aegis::delegate rejects amplifying tokens.
Treaty capabilities
A MOAT treaty grants a foreign tenant a bounded capability set inside your tenant. The treaty is a signed document on both sides; MACS::derive includes treaty grants in the composed capability set when the caller's tenant matches the foreign side.
# Treaty example (yaml)
treaty:
parties:
- tenant: org_acme
- tenant: org_globex
grants_to_globex:
- map.mind.recall_memory
- map.maven.cite
- map.made.economic_contract_settle (caveats: [weekly_budget:50000])
expires_at: 2026-12-31T00:00:00ZTreaty grants are revoked instantly by MOAT::terminate; all in-flight requests complete, new requests fail at security gating.
Treaties unlock the legitimacy loop. Two institutions can collaborate without merging; their audit chains stay separate; the boundary is policed by MOAT. The price of a treaty is the discipline of declaring it.
See also
- Identity & lineage
- MAXIM — the policy engine that evaluates caveats
- MOAT — the treaty primitive
- Aegis adapter — delegation tokens