L2 Policy
L2 is the rules layer. Every agent payment passes through it before any network hears about the transaction. Six rule primitives compose the spending envelope. The engine evaluates them in memory with atomic counter operations.
What it does
Given an agent_id and a tx_intent, L2 returns an allow verdict plus a Merkle inclusion proof of the policy that authorized the decision. If the policy rejects, the payment never leaves the SDK.
Policies are versioned. Every update produces a new Merkle root, signed by the Oris MPC ring, anchored on OrisL2PolicyRegistry on Base.
Six rule primitives
| Primitive | What it checks |
|---|---|
max_per_tx | Single-transaction ceiling in USD-e6. |
max_daily | Cumulative spend in the configured timezone day. |
max_monthly | Cumulative spend in the configured timezone month. |
counterparty_whitelist | Destination address or domain allowlist. |
allowed_categories | Merchant category restrictions (e.g. cloud_compute). |
escalation_threshold | Above this amount, the payment routes to human approval. |
Combine them to draw a tight envelope per agent. A finance team can lock a procurement bot to a single vendor under $50 / day with no escalation needed.
Performance
The engine caches active policies in Redis with atomic Lua-backed counter updates. Latency budget at p95:
| Step | Budget |
|---|---|
| Policy cache read | < 1 ms |
| Rule evaluation | < 3 ms |
| Counter atomic update (Lua) | < 2 ms |
| Audit log write | < 4 ms |
| p95 total | < 10 ms |
The cache is invalidated atomically on every policy update. The next transaction evaluation sees the new policy. There is no propagation delay between dashboard edit and live enforcement.
On-chain commitment
Every policy version is committed to the L2 Merkle tree. The root is signed by the Oris MPC ring and stored in:
OrisL2PolicyRegistry Base Sepolia0xb43a7d6efdd2df1F11af130133965f00C99dE356The compliance bundle carries:
policy_root— the active root at evaluation timepolicy_proof— Merkle inclusion proof of the rule that fired
A verifier can independently confirm that the agent was bound by exactly that policy when the payment moved.
Hashing scheme
L2 uses Sparse Merkle Tree with Keccak256 hashing in v1. The migration to Poseidon-2 is queued behind the L4 ZK boundary (v2). Until ZK proofs ship, Keccak256 is the simpler primitive with no on-chain hash function divergence.
SDK example
from oris import OrisClient
client = OrisClient(...)
client.policies.create( agent_id=agent.id, max_per_tx=50.00, max_daily=500.00, max_monthly=5000.00, allowed_categories=["cloud_compute", "api_consumption"], counterparty_whitelist=["0xA1b2...", "0xC3d4..."], escalation_threshold=200.00,)
# Evaluate before sending (optional, payments.send() does it inline)verdict = client.policies.evaluate( agent_id=agent.id, to_address="0xA1b2...", amount=12.50, category="api_consumption",)assert verdict.allow is Trueprint(verdict.policy_root) # 0x...print(verdict.policy_proof_len) # in bytesimport { OrisClient } from 'oris-sdk';
const client = new OrisClient({ ... });
await client.policies.create({ agentId: agent.id, maxPerTx: 50.00, maxDaily: 500.00, maxMonthly: 5000.00, allowedCategories: ['cloud_compute', 'api_consumption'], counterpartyWhitelist: ['0xA1b2...', '0xC3d4...'], escalationThreshold: 200.00,});
const verdict = await client.policies.evaluate({ agentId: agent.id, toAddress: '0xA1b2...', amount: 12.50, category: 'api_consumption',});
if (!verdict.allow) throw new Error('policy denied');console.log(verdict.policyRoot);console.log(verdict.policyProofLen);Policy lifecycle
1. Operator edits in dashboard or API │ ▼2. Policy AST signed by operator identity, staged │ ▼3. Redis cache invalidated for the agent │ ▼4. Next evaluation reads the new policy │ ▼5. Merkle root commit batched with other tenants │ ▼6. OrisL2PolicyRegistry on-chain commit (every minute)There is no deploy step, no compile pass, no migration window. Updates take effect on the next transaction.
What flows into the bundle
L2 contributes two fields to every Compliance Bundle:
policy_root— the active L2 root at evaluation time.policy_proof— Merkle proof showing the rule that authorized the payment.
A verifier can replay the rule trace deterministically from these two fields.
Where to go next
- L3 Veris for the compliance attestation that runs after policy clearance.
- Spending policies feature for the operator-facing view.
- Policy configuration guide for write, version, and deploy workflow.