AGENTS.md
Top-level Context
Circuit is a consumer interface and general-purpose infrastructure for executing programmatic financial strategies (called “agents”) on self-custodial wallets. It lets users run algorithmic agents—ranging from simple yield farming scripts to complex AI-assisted trading strategies—on their own wallets across Ethereum, Solana, Hyperliquid, Polymarket, and other blockchains, without ever giving up custody of their private keys.Agent Requirements Checklist
- ABIs MUST be in a separate constants file, most constants SHOULD be in a separate constants file.
- Use viem (TypeScript) or web3py (Python) for most onchain tasks such as calldata encoding or RPC calls - almost everything except signing a transaction.
- Use DefiLlama as your primary source of truth for high-quality data.
- Logs should be interesting to a human audience, including live stats (APY, TVL, entry price) or new world information, and explain why the agent did what it did.
- Focus on clear simple understandable auditable financial logic - they must be trustworthy and reliable since people will run money through them.
Agent Developer — Building Circuit Agents with the SDK + CLI
End-to-End Workflow Summary
- Install CLI and SDK
- Authenticate with
circuit signin - Initialize project with
circuit new - Install dependencies (
bun installoruv sync) - Write agent logic in
run()andunwind()functions - Test locally with
circuit runthencircuit unwind - Publish with
circuit publish
Installation
Prerequisites:- Bun (required for CLI and TypeScript)
- Python 3.12+ (for Python agents)
- A Circuit account
- Python: uv (package manager), ruff (linter), ty (typechecker)
- TypeScript: Bun (runtime), Biome (linter)
Project Structure
Aftercircuit new, you get:
TypeScript:
The circuit.toml Configuration File
This is critical — it defines your agent’s metadata, asset requirements, and behavior:
DESCRIPTION.md file in the same directory as circuit.toml:
walletType— The wallet type for this agent:"ethereum"or"solana"allowedExecutionModes—"auto"(transactions execute immediately) and/or"manual"(user must approve in UI). First entry is used forcircuit run.runtimeIntervalMinutes— How oftenrun()is calledfilesToInclude/filesToExclude— For monorepo setupsimageUrl— URL for the agent icon displayed in the Circuit UIversion— Semver version (major.minor.patch), auto-bumped on publishstartingAsset— The asset a user must have to start a session;minimumAmountin raw units (wei/lamports)
Agent Code Pattern
TypeScript:Execution Model
- Circuit sends a
runorunwindcommand to your agent - SDK creates an
AgentContextobject - SDK calls your
runfunction with the context - Your code uses SDK methods to analyze positions, execute trades, etc.
- SDK returns results to Circuit
- In manual mode, transactions are submitted for user approval in the Circuit UI
auto— Transactions execute automaticallymanual— Transactions become suggestions for user approval
suggested: bool and suggestionId: int in manual mode.
Important: All suggested transactions are automatically soft-deleted at the beginning of each run execution. Use expiresAt field for shorter expiry.
Execution interval: Set via runtimeIntervalMinutes in circuit.toml. The interval starts after the previous run completes.
Agent Context (AgentContext)
The AgentContext object is passed to both run and unwind functions. It contains:
Session Data:
sessionId(number) — Unique session identifiersessionWalletAddress(string) — Wallet address for this sessioncurrentPositions(array) — Assets allocated at execution startexecutionMode(string) —"auto"or"manual"
currentPositions:
network(string) — e.g.,"ethereum:137","solana"assetAddress(string) — Token contract addresstokenId(string | null) — For NFTs/ERC1155avgUnitCost(string) — Average unit cost in USD (currently hardcoded to 0)currentQty(string) — Current quantity in raw units
log()— Send messages to users and log locallymemory— Session-scoped key-value storage (.set(),.get(),.delete(),.list())swidge— Cross-chain swap and bridge operations (.quote(),.execute())platforms.hyperliquid— Hyperliquid DEX integrationplatforms.polymarket— Polymarket prediction market integrationsignAndSend()/sign_and_send()— Sign and broadcast custom transactionssignMessage()/sign_message()— Sign messages (EVM only)transactions()— Get transaction historygetCurrentPositions()/get_current_positions()— Get live positionsclearSuggestedTransactions()/clear_suggested_transactions()— Clear pending manual mode suggestions
Network Identifiers
Used everywhere in the SDK:- EVM:
"ethereum:{chainId}"— e.g.,"ethereum:1"(Mainnet),"ethereum:137"(Polygon),"ethereum:42161"(Arbitrum),"ethereum:8453"(Base) - Solana:
"solana" - Hyperliquid Perps:
"hypercore:perp" - Hyperliquid Spot:
"hypercore:spot"
- EVM chains:
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"(EIP-7528) - Solana:
"11111111111111111111111111111111"(System Program)
SDK Response Pattern
Every SDK method returns a response object with consistent shape:success before using data:
run/unwind are automatically caught by the SDK — the execution is marked failed and the error is logged. You do NOT need try/catch around SDK methods. Use try/catch only for your own parsing, calculations, or external API calls.
Amounts and Units
- All amounts are strings in smallest units (wei for EVM, lamports for Solana)
- Keep as strings to preserve precision
- Exception: Hyperliquid uses formatted values (e.g., “1.5” for $1.5 USDC)
Logging
agent.log("msg"), agent.log("msg", error=True), agent.log("msg", debug=True)
Best practice: User-facing logs should be clean, concise strings. Use debug=True for internal/object logging. Logs should be interesting to a human user and provide context about why the agent did a specific action. Logs should also provide entertaining or informative bits of information or statistics, such as a protocol’s TVL or current yield or an observed event in the world.
Memory (Session-Scoped Key-Value Storage)
Keys are auto-namespaced by agent and session. Memory persists across execution cycles within the same session, cleared when the session ends. Values must be strings — serialize JSON/numbers before storing.agent.memory.set("key", "value"), agent.memory.get("key"), agent.memory.delete("key"), agent.memory.list()
Suggestions (Manual Mode)
If your agent supports manual mode, transactions become suggestions for user approval. Circuit auto-clears suggestions at the start of eachrun. You can also manually clear:
agent.clear_suggested_transactions()
Positions
agent.currentPositions — Snapshot at execution start. Use for initial decision-making.
getCurrentPositions() / get_current_positions() — Fetch live positions. Note: indexing can lag by chain; may not reflect transactions immediately.
Handling pending transactions: Check hasPendingTxs flag. If true, balances may not be accurate. For time-sensitive logic, track deltas in memory.
Swap and Bridge
Two-step workflow: quote then execute.- Omit
fromToken/toTokenfor native tokens (ETH, SOL) - Same network = swap; different networks = bridge
- Default slippage: 0.5%; use 1-2% for volatile/cross-chain
- Circuit filters >100% price impact automatically — validate against your own thresholds
- Minimum $10-20 recommended to avoid fee issues
- Bulk execution: pass array of quotes to
execute() - Execution status is final:
"success","failure","refund", or"delayed" execute()supportswaitForConfirmation(defaulttrue) — polls EVM transaction receipts and returnssuccess: falseon reverts- In manual mode,
execute()returns a suggestion instead of executing (data.suggested = true)
Custom Transactions / Signing
All transactional methods (signAndSend, swidge.execute, placeOrder, transfer, marketOrder) accept an optional expiresAt parameter (ISO 8601 string) to control suggestion expiry in manual mode.
signAndSend also accepts waitForConfirmation (boolean, EVM only, default true). The SDK polls a public RPC for the transaction receipt after broadcast and returns success: false if the transaction reverted onchain. Set to false to skip receipt polling and return immediately after broadcast.
It is recommended to use viem or web3py to populate calldata and other raw transaction data, rather than doing raw low-level transformations in the script.
Sign and send (EVM):
agent.sign_and_send(), agent.sign_message() with snake_case field names in dicts (to_address, hex_transaction, etc.). The SDK converts to camelCase internally.
Transaction History
network, transactionHash, from/to, amount, token, tokenType, tokenUsdPrice, timestamp. Note: indexing has a delay per chain.
Hyperliquid Integration
Configuration incircuit.toml:
- Only one Hyperliquid agent per wallet (to safely manage margin)
- Your entire wallet balance is available to the agent
- Use
agent.platforms.hyperliquid.balances()andagent.platforms.hyperliquid.positions()instead ofcurrentPositions - Avoid calling balances/positions in loops — Hyperliquid will rate limit
- All values are in formatted amounts (not raw units)
- Must respect Hyperliquid’s tick and lot size rules when placing orders
balances()— Perp account value + spot balancespositions()— Open perpetual positionsorder(orderId)— Get order infodeleteOrder(orderId, symbol)— Cancel orderopenOrders()— All open ordersorders()— Historical ordersorderFills()— Fill historytransfer({ amount, toPerp, expiresAt? })— Transfer between spot and perpliquidations(startTime?)— Liquidation events
Polymarket Integration
Market order:redeemPositions() after market expiry. Position data includes enriched metadata (question, outcome, PNL) via getCurrentPositions(). Both marketOrder and redeemPositions support waitForConfirmation (default true) — the SDK polls for transaction receipts on Polygon and returns success: false if any transaction reverts.
Error Handling Best Practices
- Always check
successbefore usingdata - Log errors with
{ error: true }for UI visibility - Return early on errors
- Don’t wrap SDK calls in try/catch — use
.successchecks - Uncaught exceptions are auto-caught by SDK
- Use try/catch for your own logic, external APIs, parsing
| Error | Cause | Solution |
|---|---|---|
| ”Key not found” | Memory key doesn’t exist | Handle missing keys gracefully |
| ”Quote failed” | Amount too small / no liquidity | Increase amount, adjust slippage |
| ”Transaction failed” | Insufficient balance/gas | Check getCurrentPositions() first |
| ”Transaction reverted onchain” | Tx was mined but reverted | Check contract logic, input params |
| ”Invalid request” | Bad parameters | Validate inputs before SDK calls |
CLI Commands Reference
| Command | Description |
|---|---|
circuit signin | Authenticate (opens browser) |
circuit signout | Sign out |
circuit whoami | Show current user |
circuit new | Create new agent project |
circuit run | Test agent locally |
circuit unwind | Unwind positions and end session |
circuit dev | Watch mode — re-runs agent on file changes |
circuit check | Validate agent project offline (no auth required) |
circuit publish | Publish to production |
circuit wallet list | List wallets |
circuit wallet import | Import wallet for testing |
--path / -p (agent directory), --json / -j (JSON output), --help / -h.
circuit new flags: --language / -l (typescript or python), --name / -n (agent name), --template / -t (bare, swap, hyperliquid, polymarket). All skip interactive prompts.
circuit run flags: --wallet / -w (wallet address), --mode / -m (auto or manual), --amount / -a (token amount in smallest unit), --path / -p (agent directory), --local-sdk-dependencies / -l (skip dep install).
circuit run behavior: Creates a test session, starts local agent server, executes run(), streams logs to terminal. Requires dependencies installed (bun install / uv sync).
circuit unwind flags: --wallet / -w (wallet address), --path / -p (agent directory), --local-sdk-dependencies / -l (skip dep install).
circuit dev flags: Same as circuit run. Watches for file changes and runs run → unwind cycle on each iteration.
circuit publish flags: --path / -p (agent directory), --env KEY=VALUE / -e KEY=VALUE (environment variables, repeatable).
circuit publish behavior: Validates config, uploads files, publishes to Circuit infrastructure. Requires authentication and valid circuit.toml.
Multi-Agent Monorepo Support
You can organize multiple agents in a monorepo with shared utility code:filesToInclude = ["../../utils"] in circuit.toml to include shared directories. For Python, add sys.path.insert(0, ...) at the top of main.py. For TypeScript, configure tsconfig.json path aliases.
Complete Example: Yield Agent
See the Yield Agent example in the docs for a full working agent that:- Checks
currentPositionsfor USDC balance - Approves Aave V3 once (max uint256, tracked via
memory), then deposits USDC usingsignAndSend - Withdraws all USDC from Aave V3 on unwind
Full Documentation Links
For more detail on any topic above, see the full docs at docs.circuit.org:- Get Started (Users): https://docs.circuit.org/agent-users/how-to-use
- Developer Introduction: https://docs.circuit.org/agent-developers/introduction
- Installation: https://docs.circuit.org/agent-developers/getting-started/installation
- Quickstart: https://docs.circuit.org/agent-developers/getting-started/quickstart
- Agent Configuration (circuit.toml): https://docs.circuit.org/agent-developers/getting-started/circuit-toml-reference
- Execution Model: https://docs.circuit.org/agent-developers/concepts/execution-model
- Wallets & Allocation: https://docs.circuit.org/agent-developers/concepts/wallets-and-allocations
- Manual vs Auto Mode: https://docs.circuit.org/agent-developers/concepts/manual-vs-auto-mode
- SDK Quick Reference: https://docs.circuit.org/agent-developers/sdk-reference/quick-reference
- Swap & Bridge: https://docs.circuit.org/agent-developers/sdk-reference/swap-and-bridge
- Hyperliquid SDK: https://docs.circuit.org/agent-developers/sdk-reference/hyperliquid
- Polymarket SDK: https://docs.circuit.org/agent-developers/sdk-reference/polymarket
- Custom Transactions: https://docs.circuit.org/agent-developers/sdk-reference/custom-transactions-signing
- Error Handling: https://docs.circuit.org/agent-developers/sdk-reference/error-handling
- CLI Reference: https://docs.circuit.org/agent-developers/cli-references/authentication
- Troubleshooting: https://docs.circuit.org/agent-developers/troubleshooting
- Examples (Yield, Hyperliquid, Polymarket): https://docs.circuit.org/agent-developers/examples/yield-agent