> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altheia.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# The Policy object

> A Move shared object holding per-asset caps, allowed actions, protocol scope, expiry, and state.

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.

<Frame>
  <img src="https://mintcdn.com/altheia/FaUWnizMhLhPg3t5/images/landing-how.png?fit=max&auto=format&n=FaUWnizMhLhPg3t5&q=85&s=9d08ecf02b375dc53c82183c0a5db506" alt="One policy between the agent and your money" width="3024" height="1674" data-path="images/landing-how.png" />
</Frame>

## Shape

```move theme={null}
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`.

| Cap           | Type               | Meaning                                               |
| ------------- | ------------------ | ----------------------------------------------------- |
| `per_tx_cap`  | `u64` (base units) | Max per single action. `0` disables the per-tx check. |
| `per_day_cap` | `u64` (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`:

| Action               | Id  | Builder                      |
| -------------------- | --- | ---------------------------- |
| `transfer`           | `0` | —                            |
| `deepbookSwap`       | `1` | `buildSwap`, `buildSellSwap` |
| `deepbookLimitOrder` | `2` | `buildPlaceLimit`            |
| `deepbookCancel`     | `3` | `buildCancelAll`             |

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

| State   | Field           | Abort            | Reversible    |
| ------- | --------------- | ---------------- | ------------- |
| Expired | `expires_at_ms` | `policy_expired` | no            |
| Paused  | `paused`        | `agent_paused`   | yes (unpause) |
| Revoked | `revoked`       | `policy_revoked` | no            |

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](/sdk/reads).

<Card title="Next: Vault and AgentCap" icon="arrow-right" href="/concepts/vault-and-agentcap" horizontal>
  Where funds live, and the capability that binds the agent to one vault and one policy.
</Card>
