Skip to main content
A Policy is a Move shared object. It holds the budget, the scope, and the live state for one agent. Because it is shared, its cumulative spend persists across transactions: an agent cannot bypass a cap by splitting a spend across multiple PTBs.
One policy between the agent and your money

Shape

public struct Policy has key {
    id: UID,
    agent_id: vector<u8>,
    caps: VecMap<TypeName, AssetCap>,   // per-asset caps, keyed by coin type
    allowed_packages: vector<address>,  // protocol scope
    allowed_actions: VecSet<u8>,        // capability allowlist, default-deny
    expires_at_ms: u64,
    revoked: bool,
    paused: bool,
    version: u64,
    max_slippage_bps: u64,              // value-guard
    base_scalar: u64,
}

public struct AssetCap has store, copy, drop {
    per_tx_cap: u64,
    per_day_cap: u64,
    spent_today: u64,
    day_window_started_ms: u64,
}

Per-asset caps

Caps govern budget deployment, not what the vault may hold. The funded budget asset (for example SUI) carries an AssetCap. Each gated spend of a capped asset checks per_tx_cap and per_day_cap, then records the amount against spent_today. The day window rolls forward 24h after day_window_started_ms. An asset with no cap entry is default-deny for transfer-out, but a position the agent acquired through a permitted swap is uncapped: it can be sold back, because the proceeds settle into the vault. Exfiltration of an uncapped asset is blocked by assert_transferable.
CapTypeMeaning
per_tx_capu64 (base units)Max per single action. 0 disables the per-tx check.
per_day_capu64 (base units)Max cumulative spend in a rolling 24h window.
Amounts are in base units. 50_000_000 is 0.05 SUI (9 decimals).

Allowed actions

allowed_actions is a default-deny VecSet<u8>. The SDK action ids mirror altheia::actions:
ActionIdBuilder
transfer0
deepbookSwap1buildSwap, buildSellSwap
deepbookLimitOrder2buildPlaceLimit
deepbookCancel3buildCancelAll
An action absent from the set aborts action_not_allowed.

Protocol scope

allowed_packages is the set of package or pool addresses the agent may touch. check_and_consume asserts the target is in the set before any coin leaves the vault. An out-of-scope target aborts package_not_allowed.

Expiry, pause, revoke

StateFieldAbortReversible
Expiredexpires_at_mspolicy_expiredno
Pausedpausedagent_pausedyes (unpause)
Revokedrevokedpolicy_revokedno
Pause freezes the agent without ending it; unpause resumes. Revoke is terminal: once revoked is set, every gated action aborts. There is no path back. Provision a new agent.

Value-guard

max_slippage_bps and base_scalar are operator-set. The agent cannot supply them. For swaps, the per-action params (set with buildSetValueGuard or at provision time) define a minimum output rate, so a swap that would settle below the operator’s floor reverts on-chain rather than executing at a bad price.

Reading the policy

readPolicyObject(client, policyId) reads the live caps, actions, scope, expiry, and state straight from chain — no backend dependency. See the SDK reference.

Next: Vault and AgentCap

Where funds live, and the capability that binds the agent to one vault and one policy.