Chio/Docs

LearnAnatomy of a Governed Call

Budgets & Metering

A capability token can limit both the tools an agent may call and the amount it may spend.

A budget travels with the token through delegation. Each charge records its path to the root budget holder, making the token a spending authorization. Autonomous Commerce introduces that identity. Each charge described here is recorded as a priced, signed receipt; Receipts covers the receipt format.

MonetaryAmount

MonetaryAmount represents money as minor-unit integers with an ISO 4217 currency code:

rust
pub struct MonetaryAmount {
    /// Value in the currency's minor unit (e.g., cents for USD).
    pub units: u64,
    /// ISO 4217 currency code (e.g., "USD", "EUR", "USDC").
    pub currency: String,
}

Monetary values use u64minor units. Budget calculations do not use floating-point values.

The meaning of one unit depends on the currency:

Currency1 unit equalsMinor units per major unit
USD1 cent100
EUR1 cent100
GBP1 penny100
JPY1 yen1
USDC / USDT1 micro-dollar106
BTC1 satoshi108
ETH1 wei1018

Integer amounts

Budget checks, cost comparisons, and attenuation validation use integer minor-unit arithmetic. USDC is 6 decimals, so balances are tracked as u64 micro-USDC. BTC uses 108 satoshis. EUR is 2 decimals. Floating-point numbers do not appear in the budget path.

Three-tier budget model

Each ToolGrant in a capability token carries up to three independent budget constraints: per-invocation (max_cost_per_invocation), per-grant total (max_total_cost), and an invocation count cap (max_invocations). All three are optional and can be combined freely:

The kernel enforces all three limits atomically before the tool runs. If any limit would be exceeded, the call is denied and a receipt is produced with the attempted cost recorded.

capability-token.yaml
grants:
  - server_id: srv-ai-inference
    tool_name: generate_text
    operations: [invoke]
    # Per-call cap: no single call can cost more than $0.50
    max_cost_per_invocation:
      units: 50
      currency: USD
    # Aggregate cap: total spend cannot exceed $10.00
    max_total_cost:
      units: 1000
      currency: USD
    # Call count cap: maximum 200 invocations
    max_invocations: 200

Independent limits

A grant can set any combination of the three limits. Setting only max_invocations creates a free-tier with a call count limit. Setting only max_total_cost creates a pay-per-use budget with no per-call cap.

Budget enforcement flow

The budget lifecycle has four operations: authorize, capture, release, and reconcile. The kernel reserves cost before dispatch, captures the tool's reported cost on success, and reconciles the reservation afterward. If a call is denied after authorization or does not run, it releases the reserved amount. The phases below show the success path.

Chio budget enforcement cycleBudget Enforcement CyclePhase 1 — Authorize: atomically debit max_cost_per_invocation and check max_total_cost / max_invocations before any tool code runs.AUTHORIZEreserve worst-casePhase 2 — Capture: tool executes; on success the kernel captures the actual cost reported via ToolInvocationCost.CAPTURErun + capturePhase 3 — Reconcile: compare the tool's actual reported cost with the authorized amount; credit back, record overrun, or leave as-is.RECONCILEactual vs authorizeddebit worst-case costmax_cost_per_invocationtool reports actualToolInvocationCostcompare actual vs authorizedfinalize_tool_output_with_cost()Budget check failed: max_cost_per_invocation, max_total_cost, or max_invocations would be exceeded. Tool does not run.DENYbudget exceededThe tool is executing; the kernel is holding the authorized amount until a cost is reported or the call fails.in flightawaiting resultActual reported cost was lower than the authorized amount. The difference is credited back to the budget.actual < chargedcredit differenceActual reported cost matched the authorized amount exactly; no adjustment needed.actual = chargedexact matchActual reported cost exceeded the authorized amount; settlement_status is set to Failed and the overrun is recorded in the receipt.actual > chargedcost overrunIf a guard or validation step denies the request after the hold is authorized, the kernel fully reverses the debit so the agent is not billed for a tool call that never executed.reverse_budget_charge()refund debit on guard failurebudget okresult + costcheck failsrefundno-opoverrunguard failsrefundinvariant: pessimistic authorize ≥ actual cost (or reconciled)solid = happy path · dashed = failure / refund
For a priced tool call, the kernel reserves max_cost_per_invocation, captures the reported ToolInvocationCost on success, then reconciles the amount. A guard failure after authorization calls reverse_budget_charge().

Phase 1: authorize

Before the tool executes, the kernel calls check_and_increment_budget(). This function atomically:

  • Increments the invocation count and checks it against max_invocations
  • Debits the worst-case cost (max_cost_per_invocation) from the running total and checks it against max_total_cost

If either check fails, the kernel denies the call before tool code runs. Authorization reserves the maximum max_cost_per_invocation before the tool runs.

Phase 2: capture

The tool executes. On success the kernel captures the actual cost the tool reports via ToolInvocationCost; if the call fails, the hold is released and nothing is charged:

rust
pub struct ToolInvocationCost {
    /// Actual cost in minor units.
    pub units: u64,
    /// ISO 4217 currency code.
    pub currency: String,
    /// Optional cost breakdown as an arbitrary JSON value (tool-defined keys).
    pub breakdown: Option<serde_json::Value>,
}

The breakdown field allows tools to itemize costs: for example, separating compute, I/O, and network charges. Keys are tool-defined and the shape is opaque JSON, which the kernel copies through into the financial receipt for auditability.

Phase 3: reconcile

After the tool returns, the kernel calls finalize_budgeted_tool_output_with_cost_and_metadata() to reconcile the authorized amount with the actual cost. It takes the request, the tool output, the elapsed time, the timestamp, the matched grant index, and a FinalizeToolOutputCostContext (the charge result, the reported cost, the payment authorization, and the cap). When there was no budget charge to reconcile, an unbudgeted call, it falls back to the plain finalize_tool_output_with_metadata path. When there was, it settles the difference:

  • Actual < charged: the difference is credited back to the budget
  • Actual > charged: a cost overrun has occurred; settlement_status is set to Failed and the overrun is recorded in the receipt
  • Actual = charged: exact match, no adjustment needed

Guard failure after authorize

If a guard or validation step denies the request after the hold has already been authorized, the kernel calls reverse_budget_charge() to fully reverse the debit. The agent is not charged for a tool call that never executed.

Financial receipt metadata

Every tool invocation that exercises a monetary grant produces a FinancialReceiptMetadata record embedded in the receipt's metadata field. This struct captures the complete economic state of the transaction:

rust
pub struct FinancialReceiptMetadata {
    /// Index of the grant within the capability token.
    pub grant_index: u32,
    /// Actual cost charged (after reconciliation).
    pub cost_charged: u64,
    /// Currency of the charge.
    pub currency: String,
    /// Budget remaining after this invocation.
    pub budget_remaining: u64,
    /// Total budget for the grant.
    pub budget_total: u64,
    /// Depth in the delegation chain (0 = root).
    pub delegation_depth: u32,
    /// Identity of the root budget holder.
    pub root_budget_holder: String,
    /// External payment reference for settlement.
    pub payment_reference: Option<String>,
    /// Settlement status of this charge.
    pub settlement_status: SettlementStatus,
    /// Itemized cost breakdown from the tool, as an arbitrary JSON value.
    /// Keys are tool-defined.
    pub cost_breakdown: Option<serde_json::Value>,
    /// Oracle conversion evidence (for cross-currency).
    pub oracle_evidence: Option<OracleConversionEvidence>,
    /// Cost that was attempted (present in denial receipts).
    pub attempted_cost: Option<u64>,
}

The SettlementStatus enum tracks the lifecycle of the financial transaction:

rust
pub enum SettlementStatus {
    /// No monetary cost (e.g., free-tier grant).
    NotApplicable,
    /// Cost recorded, awaiting settlement.
    Pending,
    /// Settlement completed successfully.
    Settled,
    /// Settlement failed (e.g., cost overrun).
    Failed,
}

Budget hold lineage

FinancialReceiptMetadata is the settled summary. Underneath it, the authorize path records the budget hold itself. When check_and_increment_budget authorizes a charge it opens a hold via authorize_budget_hold, and three sibling records capture that hold's lineage on the receipt:

  • FinancialBudgetHoldAuthorityMetadata: the authority behind the hold: authority_id, lease_id, lease_epoch.
  • FinancialBudgetAuthorizeReceiptMetadata: the authorize step: exposure_units and the committed_cost_units_after the hold was opened.
  • FinancialBudgetTerminalReceiptMetadata: the terminal step: the hold's disposition, the realized_spend_units, and the committed total after reconcile.

Together, these records identify the hold authority, authorization, and terminal reconciliation.

Here is a complete receipt with financial metadata for a tool call that cost $1.50 against a $10.00 budget:

receipt-with-financial.json
{
  "id": "rcpt-econ-001",
  "timestamp": 1710000100,
  "capability_id": "cap-budget-001",
  "tool_server": "srv-ai-inference",
  "tool_name": "generate_text",
  "action": {
    "parameters": {
      "prompt": "Summarize this document",
      "max_tokens": 500
    },
    "parameter_hash": "sha256:7f3a9b..."
  },
  "decision": {
    "verdict": "allow"
  },
  "receipt_kind": "mediated_decision",
  "boundary_class": "prevent",
  "tool_origin": "caller_executed",
  "redaction_mode": "none",
  "content_hash": "sha256:c4d5e6f7...",
  "policy_hash": "abc123def456",
  "evidence": [
    {"guard_name": "forbidden-path", "verdict": true, "details": null},
    {"guard_name": "path-allowlist", "verdict": true, "details": null},
    {"guard_name": "shell-command", "verdict": true, "details": null},
    {"guard_name": "egress-allowlist", "verdict": true, "details": null},
    {"guard_name": "mcp-tool", "verdict": true, "details": null},
    {"guard_name": "secret-leak", "verdict": true, "details": "no secrets detected"},
    {"guard_name": "patch-integrity", "verdict": true, "details": null},
    {"guard_name": "velocity", "verdict": true, "details": null}
  ],
  "metadata": {
    "financial": {
      "grant_index": 0,
      "cost_charged": 150,
      "currency": "USD",
      "budget_remaining": 850,
      "budget_total": 1000,
      "delegation_depth": 0,
      "root_budget_holder": "agent-orchestrator-001",
      "payment_reference": "pay-ref-abc123",
      "settlement_status": "pending",
      "cost_breakdown": {
        "compute": 120,
        "io": 30
      },
      "oracle_evidence": null,
      "attempted_cost": null
    }
  },
  "trust_level": "mediated",
  "kernel_key": "9c7b3f2e8a1c4d5b6f0a9e8d7c6b5a4f...",
  "signature": "e5f6a7b8c9d0e1f2a3b4c5d6e7f8091a..."
}

Cross-currency enforcement

A capability token's budget may be denominated in one currency while a tool reports its cost in another. For example, a grant with a USD budget invoking a tool that charges in USDC. When this happens, the kernel resolves the exchange rate through an oracle via chio-link before the budget check.

The conversion uses integer arithmetic. The rate is a rate_numerator/rate_denominator pair, and the cost is carried as both original_cost_units (what the tool charged) and converted_cost_units (what the budget was debited). The quote's freshness is bounded explicitly: updated_at records when the feed reported the rate, max_age_seconds caps how stale it may be at use, and cache_age_seconds records how old the cached rate actually was at conversion time.

The conversion evidence is embedded in the receipt as OracleConversionEvidence:

rust
pub struct OracleConversionEvidence {
    /// Wire schema id ("chio.oracle-conversion-evidence.v1").
    pub schema: String,
    /// Base currency of the quoted pair.
    pub base: String,
    /// Quote currency of the quoted pair.
    pub quote: String,
    /// Identifier of the oracle authority that issued the quote.
    pub authority: String,
    /// Exchange-rate numerator (integer representation).
    pub rate_numerator: u64,
    /// Exchange-rate denominator.
    pub rate_denominator: u64,
    /// Oracle source identifier.
    pub source: String,
    /// Address of the price feed the rate was read from.
    pub feed_address: String,
    /// Timestamp the feed reported the rate.
    pub updated_at: u64,
    /// Maximum age (seconds) the rate may be at use.
    pub max_age_seconds: u64,
    /// Age (seconds) of the cached rate at conversion time.
    pub cache_age_seconds: u64,
    /// Converted cost in the grant currency's minor units.
    pub converted_cost_units: u64,
    /// Original cost in the tool's charged-currency minor units.
    pub original_cost_units: u64,
    /// Currency the tool actually charged in.
    pub original_currency: String,
    /// Currency the grant budget is denominated in.
    pub grant_currency: String,
    /// Oracle's public key, when the quote is signed.
    pub oracle_public_key: Option<PublicKey>,
    /// Oracle's signature over the quote, when signed.
    pub signature: Option<Signature>,
}

Verifying a conversion

A cross-currency receipt includes the rate, feed timestamp, and oracle authority. When the quote is signed, it also includes the oracle's oracle_public_key and signature, so the rate can be checked against the oracle's key.

Budget attenuation in delegation

When an agent delegates a capability token to a child agent, the economic constraints may be narrowed. The Attenuation enum. Three of its variants govern the budget tiers directly:

Attenuation VariantEffect
Attenuation::ReduceCostPerInvocationTightens max_cost_per_invocation on the child token
Attenuation::ReduceTotalCostTightens max_total_cost on the child token
Attenuation::ReduceBudgetLowers max_invocations on the child token

The same enum carries four non-monetary narrowings: RemoveTool and RemoveOperation drop a tool or operation from scope, AddConstraint tightens a tool's parameter constraints, and ShortenExpiry pulls the expiry. Each variant narrows the parent token.

The kernel requires each attenuated value to be less than or equal to the corresponding parent value. Lean 4 proof P1 covers this monotonic attenuation property.

bash
Orchestrator token (root):
  max_total_cost: 1000 USD  ($10.00)
  max_cost_per_invocation: 100 USD  ($1.00)
  max_invocations: 200

  └─ Research agent (delegated):
       max_total_cost: 500 USD  ($5.00)     ← tightened
       max_cost_per_invocation: 50 USD  ($0.50)  ← tightened
       max_invocations: 50 tightened

       └─ Sub-agent (delegated again):
            max_total_cost: 100 USD  ($1.00)     ← tightened further
            max_cost_per_invocation: 25 USD  ($0.25)  ← tightened further
            max_invocations: 10 tightened further

Child budgets cannot exceed parent budgets

The kernel rejects any delegation attempt where a child's budget exceeds the parent's. The check occurs when the token is issued. A wider token also fails signature-chain verification.

Budget state persistence

Budget state (the running invocation count and total cost charged) is persisted in a SQLite store. Each budget entry is keyed by the tuple (capability_id, grant_index), ensuring that different grants within the same token have independent budgets.

The store tracks two values per key:

  • invocation_count: how many times this grant has been exercised
  • total_cost_charged: the running sum of all costs charged against this grant

For high-availability deployments, budget state is replicated across cluster nodes using a deterministic leader with sequence-based replication (per HA_CONTROL_AUTH_PLAN). This avoids last-writer-wins state and maintains monotonic budget accounting through failover.

Atomicity at the store level

The check_and_increment_budget() function uses a single SQLite transaction to read the current state, validate against limits, and write the updated state. This prevents race conditions in concurrent invocations against the same grant.

Budget guarantee levels

Each budget store uses BudgetGuaranteeLevel to declare the guarantee behind its holds. A store can report ha_linearizable only when a replicated quorum store backs the hold. The enum has four variants:

LevelWhat it claims
single_node_atomicHold and reconcile are atomic on one node
ha_linearizableThe hold is linearizable across a replicated quorum store
partition_escrowedThe hold is escrowed so a network partition cannot double-spend it
advisory_posthocNo enforced hold; spend is recorded after the fact, and is not authorization

The level accompanies the hold model described above. The kernel authorizes the maximum exposure before the call (the max_cost_per_invocation, or the quoted cost when present), then reconciles the hold to the realized spend after the tool returns. A denial or abort reverses the full hold. The authorize and reconcile records together determine spend. See Authoritative Spend for the receipt field and validation rules, and Reconciliation & Watchdog for the same reconciliation cycle.


Related components

Per-call budgets and the authorize / capture / reconcile cycle support other components. Each charge has a signed receipt linked to its capability and budget lineage:

  • Markets. chio-market, chio-open-market, and chio-listing turn priced tool calls into biddable, listable offers.
  • Credit and insurance. chio-credit models credit facilities, bonds, scorecards, and exposure ledgers; chio-underwriting turns receipt history into underwriting input.
  • Settlement and anchoring. chio-settle, chio-anchor, and chio-web3 carry a settled charge onto external and on-chain rails.

This page covers the per-call budget mechanics shared by those components. A signed receipt records the authorization, cost, budget holder, and any oracle rate used for the call. Autonomous Commercedescribes how these records support settlement and underwriting.