Guides
Mandates & budgets
A standing mandate is the “don't ask me again” lane: the human signs caps once, and runs inside those caps go silent. It exists because asking on every $0.50 action is consent fatigue — and it is safe because the caps are server-authored, passkey-signed, counted in cents by a fail-closed ledger, and revocable in one tap without the agent's cooperation.
Minting rides the approval ceremony
There is no separate mandate flow. The approval page offers a checkbox whose terms are server-authored — the platform, the per-action cap, the daily budget, the validity window — and folds them into the same WebAuthn challenge as the approval itself. One assertion signs the approval and the standing grant, indivisibly: a mandate can never exist without a biometric signature over its exact caps. A fresh mint supersedes the previous active grant for the same platform and key.
The autonomy box
| Limit | Default | What it does |
|---|---|---|
| Per-action cap | $2.00 | The most any single covered run may cost. A pricier quote steps up and asks the human. |
| Daily budget | $5.00 | Total covered spend in a rolling 24-hour window. Exhausted budget → step up and ask. |
| Validity | 30 days | The mandate expires on its own; expiry inside a quote's window refuses before anything runs. |
| Hard stop | $5.00 | The price tier no mandate can ever cover, regardless of its minted caps. |
These are the shipped defaults (tunable server-side); whatever the values, the human signs the exact numbers shown on their approval page, and 'always' actions sit above every mandate — the hard rung no standing consent reaches.
Scope: per platform, bound to a verified key
Coverage requires an identity the door verified — a managed bak_ key. Anonymous and custom-custody callers on a 'mandate' action ask every time, and network-wide mandates are deliberately deferred (they are the prompt-injection drain vector).
Evaluated twice, like policy
- At quote: a covered quote is born plain — zero human interaction. An uncovered or over-budget one steps up to
needs_approval, with the remaining budget stated in the response and on the approval page, so both sides see why it asked. - At confirm, pre-flight: the mandate is re-read live and the budget re-summed. Revocation or expiry inside the quote's 10-minute window refuses before anything runs — quote intact, and the refusal invites a fresh quote, which asks the human directly.
The ledger counts cents, fail-closed
One spend row per executed confirm, keyed by the quote id and written before the winner-only consume — so exactly-once budget decrement is structural, inherited from the exactly-once execution machinery. Durable sums (per mandate, per key per day, per door per day) are the authority. Both failure directions close: a budget sum that cannot be read refuses the confirm; a spend row that cannot be written refuses before the consume. A leaked quote id, ctx token, or transcript is never worth a mandate's budget — spend authority lives only in this server-side ledger, never in any token an agent holds.
Revocation is one tap, agent-free
bubblio.dev/approvals lists every mandate this passkey granted, remaining budget computed live, with a revoke button. Revocation is winner-only and immediate: the next quote skips the dead mandate, and a confirm on a quote it covered re-reads it live and refuses. See the security model for where this sits in the fail-open/fail-closed map.