Skip to main content

Policy Schema Versioning

Overview

1Claw uses versioned policy schemas to ensure backward compatibility as the policy engine evolves. Every policy carries a policy_schema_version field that determines which evaluation features are available.

Expression engine — Live at signing time

policy_schema_version: 2 and tx_conditions.expression are persisted and evaluated during transaction and sign policy checks via domain/policy_engine.rs and domain/expression_engine.rs. Expressions are AND-combined with v1 field-matching when both are present on the same policy.

Schema Versions

Version 1 (Legacy)

The original field-matching schema. All policies created before the expression engine default to version 1.

Features:

  • tx_conditions JSON with field-level matching (function_name_in, chain_in, to_address_in, etc.)
  • match_mode (all / any)
  • consensus_trigger with structured conditions
  • skip_when / require_when composability

Evaluation: Each field in tx_conditions is matched against the TransactionContext. All fields combined per match_mode.

Version 2 (Expression + field matching)

Adds the expression engine and action_kind matching. Backward compatible — all v1 fields continue to work unchanged.

Additional features:

  • tx_conditions.expression — mini-DSL for predicate logic (see below)
  • action_kind_in on consensus triggers — version-agnostic action matching (e.g. signing_key matches signing_key.export, .import, .rotate, .deactivate)
  • Expanded control-plane action taxonomy

Evaluation: When both field conditions and an expression are present, both must pass (AND). Expression-only policies (no field conditions that match) evaluate the expression alone. Fail-closed behavior is effect-aware: parse/eval errors cause deny policies to match and allow policies to not grant access.

Migration Guide

Existing policies (no action required)

All existing policies automatically operate at version 1. No migration is needed — they continue to work exactly as before.

Upgrading to version 2

When creating new policies, set policy_schema_version: 2 to enable expression support. Existing v1 policies can remain unchanged indefinitely.

Example — v1 field-matching:

{
"tx_conditions": {
"chain_in": ["ethereum", "base"],
"to_address_in": ["0x1234..."]
}
}

Equivalent v2 with expression:

{
"policy_schema_version": 2,
"tx_conditions": {
"expression": "(chain == 'ethereum' || chain == 'base') && to == '0x1234...'"
}
}

Combining field-matching and expressions

Both are AND-combined at signing time:

{
"policy_schema_version": 2,
"tx_conditions": {
"chain_in": ["ethereum"],
"expression": "value_gwei > 1000000000 && function_name != 'approve'"
}
}

The transaction must satisfy the field-level conditions and the expression.

action_kind for consensus triggers

Use action_kind_in for forward-compatible governance policies that automatically cover new actions added to a kind:

{
"consensus_trigger": {
"conditions": [
{ "type": "action_kind_in", "kinds": ["signing_key", "credential"] }
],
"approval": { "min_approvals": 2 }
}
}

This matches signing_key.export, signing_key.import, signing_key.rotate, signing_key.deactivate, credential.create, and credential.delete, including future actions added to these kinds.

Expression Engine Reference

Supported operators

OperatorDescriptionExample
==Equality (case-insensitive for strings)chain == 'ethereum'
!=Inequalityintent_type != 'personal_sign'
>, >=, <, <=Numeric comparisonvalue_gwei > 1000000000
&&Logical ANDchain == 'ethereum' && to == '0x...'
||Logical ORchain == 'ethereum' || chain == 'base'
!Logical NOT!decode_failed
inMembership testchain in ['ethereum', 'base']
containsSubstring (case-insensitive)function_name contains 'transfer'

Available context fields

FieldTypeDescription
chainstringChain name (e.g. "ethereum")
chain_familystringChain family (e.g. "evm")
chain_idnumberNumeric chain ID
intent_typestringSign intent type
tostringDestination address
value_weistringTransaction value in wei
value_gweinumberTransaction value in gwei
function_namestringDecoded function name
function_selectorstring4-byte function selector
erc20_transfer_tostringERC-20 transfer recipient
erc20_transfer_amount_rawstringERC-20 transfer amount (raw)
decode_failedbooleanWhether calldata decode failed
program_idstringSolana program ID
token_mintstringToken contract/mint address

Security properties

  • Fail-closed: Parse or evaluation errors deny allow-policies and match deny-policies (effect-aware)
  • Step budget: Max 1000 evaluation steps prevents DoS
  • Depth cap: Max 16 levels of AST nesting
  • Length cap: Max 1024 characters per expression
  • Field allowlist: Only the listed context fields are accessible
  • No side effects: Pure boolean evaluation over read-only context

Deprecation Policy

  • Fields deprecated in a schema version remain functional indefinitely
  • Deprecated fields generate dashboard warnings but do not break evaluation
  • New schema versions are always additive — they never remove or change existing behavior
  • The policy_schema_version on existing policies is never auto-upgraded