Permission an AI agent
An AI agent that acts onchain is a role member with a special property: you must assume that its key will misbehave. Prompt injection, software defects, and key theft all end in the same event — the agent sends a transaction that you did not want.
The Roles Modifier is built for this case. It enforces the limits at the account level, onchain. The role defines what the agent’s key can do at all. Design the role so that a fully compromised agent stays affordable.
Rules in the agent’s prompt are requests. The agent can ignore them. The Roles Modifier enforces its rules onchain, on every call. Use both layers, but only trust the second one.
Prerequisites: a Safe with a Roles Modifier, set up as in the Roles quickstart.
An agent runtime has no browser for the sign-in of bun pull. Write an
existing API key to .env as ZODIAC_API_KEY instead. The key writes
workspace drafts only; onchain changes still need the Safe signature.
The pattern
- Give the agent its own address.
- Assign a dedicated role with pinned venues.
- Meter the role with allowances.
- Route high-impact actions through a Delay Modifier.
- Watch the role and prepare the revoke transaction.
Step 1: give the agent its own address
The agent signs with an address that exists only for this purpose: an externally owned account whose key lives in the agent runtime, or a smart account. Do not reuse the address for anything else.
Never give an agent a Safe owner key, and never make the agent’s address an owner. An owner signs for everything. A role member can only use its role.
Step 2: assign a dedicated role
Create a separate role, for example agent_ops. Do not add the agent to a role that
humans use — you want to tune and revoke it independently.
Scope the role to the exact venues and functions the agent needs, with conditions that pin recipients to the Safe. Presets from DeFi Kit carry safe defaults for common protocols:
import { defikit } from '@zodiaceco/sdk/actions'
import type { Permissions } from '@zodiaceco/sdk'
export default [
defikit.aave_v3.deposit({
label: 'Lend on Aave',
market: 'Core',
targets: ['WETH', 'USDC'],
}),
] satisfies PermissionsFor token swaps, use order-based venues: the SDK’s swap() action creates permissions
for CoW Protocol order signing with pinned sell and buy token lists. To find the minimal
permission set for a new workflow, record a real session with Zodiac Pilot and derive
the permissions from the recording.
Step 3: meter the role with allowances
An allowance limits how fast an agent can spend. Give an agent role two meters:
- A budget. Meter transfer and deposit amounts with
WithinAllowance, for example 10,000 USDC per day. See Allowances for the exact values. - A rate limit. Meter the number of calls with
CallWithinAllowance, for example 10 calls per hour. A looping agent then stops early, before it drains a budget.
An allowance limits amounts, not destinations. Always combine it with
conditions on the recipient, such as EqualToAvatar.
Step 4: route high-impact actions through a Delay
Point the target of the agent’s Roles Modifier at a
Delay Modifier. Every action then waits in a queue, and the Safe
owners can cancel it during the cooldown. The Delay quickstart
shows the setup.
When the agent needs both speed and reach, split the lanes: deploy two Roles Modifiers. The fast lane targets the Safe and carries only low-risk permissions. The slow lane targets the Delay Modifier and carries the high-impact permissions. The agent is a member of both roles.
Step 5: watch the role and prepare the revoke
- Subscribe to the
TransactionAddedevent of the Delay Modifier and to the execution events of the Safe. Alert a human on every queued transaction. - Prepare the kill switch before you need it: a signed-but-unsent Safe transaction with
assignRoles(agentAddress, [roleKey], [false]). One execution removes all power of the agent. - Rehearse the revoke once, like the cancel path of the Delay Modifier.
Test before you connect funds
Run the agent against a test Safe on a testnet or a fork first. Give it the real role
configuration and let it work. Every ConditionViolation revert in the test log is a
permission you must decide on — widen the role or change the agent, before real assets
are behind it.
Limits, and the road ahead
Conditions check calldata, not outcomes. A role cannot see prices or slippage. Prefer venues where the order parameters carry the protection, and keep budgets small enough that a bad trade stays affordable.
Roles v3 develops features that fit agent setups: session keys, roles that expire, and a
WithinRatio operator for slippage protection. See
the v3 preview — the plans can change.
Next steps
- The agent’s runtime call: Execute as a role member
- The veto window: Quickstart: Delay
- The threat model: Security