Capabilities and actions
How the action surface is declared, how capabilities gate it, and why an undeclared action has no call path.
Two different things
An action is something an embodiment can physically attempt. A capability is permission to attempt it. The adapter declares actions; the role grants capabilities. Both must line up before the planner will consider an action at all.
A gantry adapter declares hoist. The port.crane_operator role grants machine.hoist. Remove the grant and the crane still physically has a hoist — it simply will never be planned.
Declaring an action
Each action declares three things:
- Parameters — typed, and validated before the action reaches the validator.
- Preconditions — conditions over the observation frame that must hold.
- Cost — what it spends from declared resource budgets.
Preconditions
Preconditions are evaluated against the frozen observation frame, not against live state. This is what makes a plan meaningful: every step was checked against the same view of the world, so a plan is either coherent or rejected as a whole.
A precondition that fails produces a typed rejection with the observation fields it decided from. That evidence is what turns “the crane did nothing” into “the crane refused to hoist because payload exceeded the role’s limit”.
Costs
Costs are declared per action and settled per plan. The ledger reserves the full cost of a plan before anything actuates. A plan that cannot pay for itself is discarded whole — there is no partial execution to unwind.
Why this matters
Because the planner can only build plans from the declared surface, there is no dynamic dispatch into arbitrary code at decision time. An action that is not declared has no reachable call path — not a blocked one, an absent one. That property is what makes the authority model checkable rather than aspirational.