Skip to content

Wallets + agents

An agent in Sigil is anything that signs without a human in the loop — an autonomous LLM workflow built on agents.sigilkeys.com, a cron-driven treasury script, an external trading bot, an AI assistant integrated over A2A. They all sign through the same lane: an as_live_… session token, bound to one wallet, gated by a policy.

This page explains how an agent ties to a wallet. For the wallets themselves, start at Wallets — overview.

TEE wallets only

Agent signing requires the wallet to be in TEE mode. The reason is simple: a client-mode wallet’s signing private key only exists inside the user’s browser iframe. There’s no path for a backend process to ask for a signature on the user’s behalf — by design.

A TEE wallet has no end-user device in the loop; the signing private key is reconstructed inside the hardware-attested workload on demand. The agent (or your backend) calls the Sigil API, the policy engine checks the request, the TEE signs, your agent gets a signature back.

If you try to mint an agent session against a client-mode wallet, the API rejects with wallet_not_tee_mode.

The session model

You don’t hand your secret key to the agent. You mint a session token scoped to one wallet, with caps on what it can spend, what chains it can use, and what methods it can call. The agent holds only that token.

Terminal window
curl -X POST https://api.sigilkeys.com/v1/s2s/agent-sessions \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"wallet_id": "WALLET_UUID",
"name": "trading-bot-prod",
"max_spend_per_tx_native": "100000000000000000",
"max_spend_total_native": "1000000000000000000",
"allowed_chains": ["base", "arbitrum"],
"allowed_methods": ["signMessage", "sendTransaction"],
"expires_at": "2026-12-31T23:59:59Z"
}'

Response includes a token that starts with as_live_…. It’s returned exactly once — store it where your agent can read it (env var, secret manager). Sigil doesn’t retain a copy.

Revoke any time:

Terminal window
curl -X POST https://api.sigilkeys.com/v1/orgs/{orgID}/agent-sessions/{sessionID}/revoke \
-H "Authorization: Bearer sk_live_..."

Revocation is immediate. The next signing call with that token returns 401.

What the agent sees

From the agent’s perspective, the SDK looks like a tiny version of the wallet SDK:

import { SigilAgent } from '@sigilkeys/sdk';
const agent = new SigilAgent({
apiBaseUrl: 'https://api.sigilkeys.com',
sessionToken: process.env.SIGIL_AGENT_TOKEN!,
});
// Inspect what the session is allowed to do.
const profile = await agent.getSession();
console.log(profile.walletAddress, profile.spentNative, profile.maxSpendTotalNative);
// Sign.
const sig = await agent.signMessage('login challenge', { network: 'base' });
const { signature } = await agent.sendTransaction({
network: 'base',
to: '0x...',
value: '50000000000000000', // 0.05 native
});

The agent cannot widen its own limits, switch wallets, or read the underlying secret key. Every call goes through the policy engine before the TEE is asked to sign.

Smart accounts owned by TEE wallets

A TEE wallet can own a smart account exactly like a client wallet can:

Terminal window
curl -X POST https://api.sigilkeys.com/v1/s2s/wallets/{walletID}/smart-accounts \
-H "Authorization: Bearer sk_live_..." \
-d '{"chain": "base"}'

The agent then sends through the smart account — Sigil sponsors the gas under the standard €10 / wallet / month cap. The TEE signs the userOpHash the same way it signs any EIP-191 message.

This combination — TEE-custodied signing + 4337 sponsorship — is the recommended setup for production agent workloads: no key in client memory, no gas-funding chore for operations.

Policies, in 90 seconds

Every signature an agent makes is gated by two layers, stricter side always wins:

  1. Per-agent policy — limits you set at agent or session creation (max_spend_per_tx_native, allowed_chains, allowed_recipients, etc.).
  2. Organisation global rules — limits the org owner sets centrally (blocked_chains, max_native_per_tx_cap, token_mode, etc.). These are the floor; per-agent limits can only narrow them.

A widening operation that contradicts the org rules is silently bounded by the org rules — not an error, just clipped to the stricter limit.

For the full data model, evaluation order, error codes, and a worked example, see Policies.

How A2A delegation interacts with wallets

When one Sigil agent delegates to another (e.g. Orchestrator → Compliance), the child agent runs against its own wallet and policies — not the parent’s. The runner spawns a child run with parent_run_id set, the parent pauses with status=awaiting_delegate, and the child’s terminal state triggers the parent’s resume.

For external A2A callers (other vendors’ agents calling yours), the session token is the standard as_live_… flow with the same policy gating.

See Architecture for the A2A primitives, and Pause and resume for the run-state machine.

What the portal shows you

Every signing attempt — allowed or rejected — produces an event. The portal renders them at:

  • /v1/orgs/{orgID}/agents/{agentID}/runs/{runID}/events for autonomous agents.
  • /v1/orgs/{orgID}/agent-sessions/{sessionID}/events for as_live_… sessions.

Both surfaces show the chain, target, value, and (for rejections) the policy reason code. Operations is your visibility into what an agent actually tried to do, not what its prompt asked for.

Where to go next