Skip to main content
Every pact submission includes two top-level JSON arrays:
Completion conditions define when the pact automatically ends — time elapsed, transactions executed, or amount spent. The pact is revoked as soon as any one condition is met. Policies define what the agent is allowed to do while the pact is active — which chains, tokens, contracts, or message types are permitted, and what limits apply.

Completion conditions

Completion conditions determine when a pact automatically ends. At least one is required. The pact completes when any condition is satisfied, after which access is revoked immediately. Types cannot be duplicated within a pact.
This pact ends after 12 transactions or 90 days, whichever comes first.

Policies

Policies are the rules that constrain what an agent can do within a pact. Every operation the runtime submits is evaluated against the policies you define.

How the engine works

The policy engine evaluates every operation against all applicable policies and outputs one of three decisions: allow, require_approval, or deny.

Evaluation order (within a policy)

  1. Match when conditions — if not matched, the policy is skipped
  2. Check deny_if — if hit, deny immediately
  3. Check review_if / always_review — if hit, pause for owner approval
  4. Otherwise, allow

Default-deny semantics

Pact-level policies use fail-closed semantics: if the operation does not match any policy’s when conditions, it is automatically denied. Every operation the agent needs to perform must be explicitly covered by a policy.

Final decision

When multiple policies apply:
  • Any deny → deny
  • No deny, but any review triggered → require_approval
  • Otherwise → allow

Policy structure

Each policy in the policies array has this shape:
Constraints:
  • deny_if takes priority over review_if / always_review
  • deny effect policies cannot have review_if or always_review
  • allow + review_if requires a non-empty when
  • allow requires either a non-empty when or always_review: true

Transfer policies

Use "type": "transfer" to control token transfers.

when — allowlist conditions

All fields are AND conditions. All specified fields must match.

deny_if — hard-block limits

Each rolling window supports: amount_gt, amount_usd_gt, tx_count_gt.

review_if — approval thresholds

Supports the same fields as when (chain_in, token_in, destination_address_in), plus:

Examples


Contract call policies

Use "type": "contract_call" to control smart contract interactions. EVM and Solana use different target fields.

when — allowlist conditions (EVM)

when — allowlist conditions (Solana)

params_match rule

Used to match on decoded function parameters. Requires function_abis to be set. params_match is only supported on EVM chains. Multiple rules are AND conditions.

function_abis

Required when using params_match. Provide the ABI fragment for each function selector you reference:

deny_if — hard-block limits

review_if — approval thresholds

Supports the same fields as when (chain_in, target_in, program_in, params_match), plus amount_gt and amount_usd_gt.

Examples


Message sign policies

Use "type": "message_sign" to control EIP-712 typed-data signing. There are no amount_gt / amount_usd_gt fields — rate limits use request_count_gt instead.

when — allowlist conditions

All when fields are AND conditions.

Path syntax for domain_match and message_match

Use dot notation to address nested fields: Wildcard semantics — for multi-value paths like items.*.token:
  • eq, in, gt, gte, lt, lte: matches if any element satisfies the condition
  • neq, not_in: matches only if all elements satisfy the condition
Supported operators: eq, neq, in, not_in, gt, gte, lt, lte

Path resolution failures

When a path cannot be resolved, the rule does not match:

deny_if — rate limits

review_if — approval thresholds

Supports the same fields as when (chain_in, primary_type_in, source_address_in, domain_match, message_match).

Chain ID validation

For EVM chains, the engine checks that the request chain_id matches domain.chainId in the typed data. A mismatch results in an immediate deny with reason eip712_domain_chain_id_mismatch.

Examples


Amount units

amount_gt, amount_spent, and related fields use the token’s transfer unit — the same unit passed when submitting a transfer:
  • "1.5" for USDC means 1.5 USDC (not 1,500,000 micro-USDC)
  • "0.01" for ETH means 0.01 ETH (not wei)
USD-based conditions (amount_usd_gt, amount_spent_usd) only apply to tokens with available price data. For tokens without price data, use token-denominated limits (amount_gt, amount_spent) instead.