Design capability-safe execution
Model explicit authority, attenuate child Runs, classify risk and effects, enforce policy, and prevent identity from becoming permission.
Authority model
Runifold represents executable authority as CapabilityDescriptor values with
stable identity, kind, schema, semantic version, effect class, and risk level.
A CapabilitySet belongs to a Run. No callable, resource, child Agent, or
extension is usable merely because application code can reach it.
Authentication answers who the caller is. Authorization policy translates that identity and request into a Capability Set. Keep those decisions outside Prompt text.
Registration vs grant
Registration defines what an Agent, MCP server, or registry knows how to call. Granting defines what this execution may call. Both checks must succeed at the terminal boundary.
Never treat a Tool name, route name, URI, Task ID, tenant ID, Worker ID, or model hint as proof of permission. Identifiers select objects only after authorization.
Attenuation
Child Runs receive an explicit Capability Set that is equal to or narrower than the parent. Delegation, Workflow branches, MCP handlers, Tools, and retrieval lookups should each receive the minimum authority required for that operation.
Middleware may transform input or deny work, but must not replace the resolved route or captured parent authority. Retry creates a new terminal attempt and rechecks cancellation, deadline, capability, depth, and budget.
Policy boundaries
Use typed policy decisions for approval, data-loss prevention, tenant access, rate limits, high-risk writes, and governance. Distinguish denial from policy backend failure; both fail closed, but they require different operator action.
Classify Effects accurately: Pure, ReadOnly, IdempotentWrite, NonIdempotentWrite, Destructive, or Unknown. Risk level supports review and telemetry; effect class controls recovery and race eligibility.
Security checklist
- construct root capabilities after authentication;
- attenuate every child;
- recheck at the actual execution boundary;
- bind tenant scope in Store queries;
- keep credentials outside Run metadata and model content;
- require independent approval for destructive governance;
- record safe denial reason and policy outcome;
- test unknown, unauthorized, stale, duplicate, and cross-tenant identities;
- default new capability kinds and unknown Effects to deny.
Grant authority at the root
let weather = Arc::new(current_weather_tool());
let mut capabilities = CapabilitySet::new();
capabilities.grant(weather.descriptor().capability());
let run = RunContext::root(
BudgetTracker::new(Budget::default()),
capabilities,
);
let agent = runtime
.agent("assistant")
.shared_tool(weather)
.build()?;
let outcome = agent.prompt("Weather in Shanghai?", &run).await?;Registration makes the Tool discoverable to this Agent; the grant makes the same descriptor callable in this Run. Omitting either must deny execution. Build root capabilities after authenticating the request, then attenuate them for each child Agent, Workflow branch, MCP session, or retrieval source. Never construct authority from names supplied by the model.