Capabilities control what tools an agent can use. They are:
- Immutable during execution
- Checked before every tool call
- Logged for audit
domain:action:scope
| Domain | Description | Example |
|---|---|---|
fs |
File system | fs:read:/tmp |
network |
Network access | network:http:get |
process |
Process execution | process:exec:* |
env |
Environment | env:read:PATH |
read- Read datawrite- Write/modify dataexec- Execute codedelete- Remove data
*- Wildcard (all)- Specific path/resource - e.g.,
/tmp,https://api.example.com
let capabilities = CapabilitySet::new([
Capability::new("fs:read:*"),
Capability::new("network:http:get"),
]);
if capabilities.has(&Capability::new("fs:read:/tmp/file")) {
// Granted
}Before tool execution:
fn check_and_execute(
tool: &Tool,
capabilities: &CapabilitySet,
) -> ToolResult<Vec<u8>> {
for required in tool.required_capabilities() {
if !capabilities.has(required) {
return Err(ToolError::Denied {
capability: required.to_string(),
reason: "Not granted".to_string(),
});
}
}
tool.execute(input, context)
}When a tool is denied, an event is logged:
Event {
kind: EventKind::CapabilityDenied,
payload: CapabilityDeniedPayload {
capability: Capability::new("fs:write:*"),
tool_name: "file_writer".to_string(),
reason: "Capability not granted".to_string(),
},
// ...
}// File system
fs:read:*
fs:write:/tmp
// Network
network:http:get
network:https:*
// Process
process:exec:/usr/bin/grep
// Environment
env:read:PATH
env:read:HOME- Principle of least privilege: Grant only what's needed
- Specific scopes: Use specific paths instead of wildcards
- Audit denials: Review denied capability events
- Document requirements: Each tool declares required capabilities
- Immutable: Capabilities cannot change during execution
- Explicit: All capability checks are visible in code
- Logged: All checks (grant/deny) produce events
- Deterministic: Same capability set produces same grant/deny results