Use this file to discover all available pages before exploring further.
Before your runtime can transfer tokens or call contracts, it needs an active pact. A pact is the agreement between the wallet owner and your runtime: it captures the program’s intent, the execution plan, the policy boundaries the owner enforces, and when the authority ends. When the owner approves a pact, Cobo Agentic Wallet creates a scoped delegation with enforced policies so the runtime can operate — but only within the approved boundaries.
The pact flow has three phases: propose, approve, operate.
1. Runtime proposes a pact └── "I want to DCA $500/week into ETH on Base for 3 months" └── Specifies: spending limits, allowed contracts, and completion conditions2. You review and approve └── Pact appears in the Cobo Agentic Wallet app └── You see the intent, execution plan, and spending rules └── You can revise the policies before approving └── Approve → runtime gets scoped access. Reject → nothing happens.3. Runtime operates within the pact └── Every transaction is checked against the pact's policies └── Exceeds a limit → denied with a clear reason └── Exceeds your threshold → paused for your approval └── Completion conditions are met or the owner revokes → access removed automatically
For the conceptual overview of the four elements, see What is a pact. The following table maps those elements to PactSpec fields:
Field
What it controls
Intent
A plain-language description of what the runtime wants to do — e.g., “DCA $500/week into ETH on Base for 3 months”
Execution plan
A detailed markdown plan explaining the runtime’s strategy, steps, and rationale — helps the owner understand how the program intends to accomplish the intent
Submit ──► PENDING_APPROVAL | ┌────┴────┐ approved│ │rejected v v ACTIVE REJECTED ┌──┬──┐ │ │ │ done ◄─┘ │ └─► owner revokes ──► REVOKED v vCOMPLETED EXPIRED
State
What it means
PENDING_APPROVAL
Runtime submitted the pact. Waiting for owner approval in the Cobo Agentic Wallet app.
ACTIVE
Owner approved. The runtime now has a scoped delegation and API key to operate within the pact’s boundaries.
REJECTED
Owner rejected the pact. No access was granted.
COMPLETED
A completion condition was met (e.g., 12 transactions completed). Access revoked automatically.
EXPIRED
The pact expired because approval timed out or a time-based completion condition elapsed. Access revoked automatically.
REVOKED
Owner revoked the pact manually. Access revoked immediately.
When a pact reaches any terminal state (COMPLETED, EXPIRED, REVOKED), the delegation and its pact-scoped API key are both revoked. The runtime can no longer submit onchain operations.
When you approve a pact, Cobo Agentic Wallet creates the underlying infrastructure automatically:
Pact (what you approve) │ ├── Delegation (scoped access grant) │ └── derived scope, wallet, operator, expiry │ ├── Inline policies (spending rules) │ └── transfer limits, contract allowlists, rolling budgets │ └── Pact-scoped API key (operator credential) └── bound to the delegation, returned only to the runtime
You don’t need to create delegations or policies manually when using pacts — the pact does it for you.
The example below submits a simple one-time transfer pact that allows a single USDC transfer of up to $101 on Base.
CLI
Python SDK
TypeScript SDK
caw pact submit \ --intent "Transfer 100 USDC to 0xRecipient... on Base" \ --original-intent "Send 100 USDC to 0xRecipient... on Base" \ --execution-plan "# SummaryTransfer 100 USDC to 0xRecipient... on Base.# Operations- Transfer 100 USDC to 0xRecipient... on BASE_ETH# Risk Controls- Per-tx cap: \$101- One-time transfer only" \ --policies '[ { "name": "usdc-transfer", "type": "transfer", "rules": { "effect": "allow", "when": { "chain_in": ["BASE_ETH"], "token_in": [{"chain_id": "BASE_ETH", "token_id": "BASE_USDC"}], "destination_address_in": [{"chain_id": "BASE_ETH", "address": "0xRecipient..."}] }, "deny_if": { "amount_usd_gt": "101" } } } ]' \ --completion-conditions '[{"type": "tx_count", "threshold": "1"}]'
Required flags are --intent, --execution-plan, --policies, and --completion-conditions. The wallet UUID is resolved from the active wallet profile. The command prints a pact_id — save it to poll for approval and execute transactions.
from cobo_agentic_wallet import WalletAPIClientasync with WalletAPIClient(base_url=API_URL, api_key=AGENT_API_KEY) as client: result = await client.submit_pact( wallet_id=WALLET_UUID, intent="Transfer 100 USDC to 0xRecipient... on Base", spec={ "policies": [ { "name": "usdc-transfer", "type": "transfer", "rules": { "effect": "allow", "when": { "chain_in": ["BASE_ETH"], "token_in": [{"chain_id": "BASE_ETH", "token_id": "BASE_USDC"}], "destination_address_in": [{"chain_id": "BASE_ETH", "address": "0xRecipient..."}], }, "deny_if": { "amount_usd_gt": "101" }, }, } ], "completion_conditions": [{"type": "tx_count", "threshold": "1"}], "execution_plan": ( "# Summary\n" "Transfer 100 USDC to 0xRecipient... on Base.\n\n" "# Operations\n" "- Transfer 100 USDC to 0xRecipient... on BASE_ETH\n\n" "# Risk Controls\n" "- Per-tx cap: $101\n" "- One-time transfer only" ), }, ) pact_id = result["pact_id"] print(f"Submitted: {pact_id}")
After submission, the pact is in pending_approval state. If the wallet is paired with the Cobo Agentic Wallet app, the owner must approve it there. If the wallet is not yet paired, it activates automatically.Poll until the status changes:
CLI
Python SDK
TypeScript SDK
caw pact status --pact-id <PACT_ID>
import asynciowhile True: pact = await client.get_pact(pact_id) status = pact["status"] if status == "active": break if status in ("rejected", "revoked", "expired"): raise RuntimeError(f"Pact {status} — cannot proceed") await asyncio.sleep(3)print("Pact active — ready to execute")
const poll = async (): Promise<void> => { while (true) { const pact = (await pactsApi.getPact(pactId)).data.result; if (pact.status === 'active') break; if (['rejected', 'revoked', 'expired'].includes(pact.status ?? '')) { throw new Error(`Pact ${pact.status} — cannot proceed`); } await new Promise(res => setTimeout(res, 3000)); }};await poll();
# Show full pact detailcaw pact show --pact-id <PACT_ID># Check status (also triggers lazy activation)caw pact status --pact-id <PACT_ID># List all pactscaw pact list# List active pacts onlycaw pact list --status active
# Get a specific pactpact = await client.get_pact(pact_id)print(pact["status"]) # pending_approval, active, rejected, completed, expired, revoked# List pacts with status filterpacts = await client.list_pacts(status="active")
// Get a specific pactconst pact = (await pactsApi.getPact(pactId)).data.result;console.log(pact.status); // pending_approval, active, rejected, completed, expired, revoked// List pacts with status filterconst pacts = (await pactsApi.listPacts('active')).data.result;
Completion conditions — what triggers automatic completion
You can approve, reject, or revise before approving. If the agent’s proposed policies are too broad (or too narrow), you can adjust them directly before granting access — the agent will operate under your revised terms, not its original proposal. You can also revoke an active pact at any time.