Architecture
Sessions
A session is a running instance of an agent on a specific wallet. Starting an agent creates a session that ties together your run/unwind functions, a wallet, an execution mode (auto or manual), and the user’s asset allocations.
Sessions persist across execution cycles — your run function is called repeatedly at intervals, not just once.
Session Lifecycle
User starts agent
|
v
+--------+
| Created | -- Session initialized, assets allocated
+----+---+
|
v
+---------+
| Running | -- run() called on each interval
+----+---+
|
+---- User pauses --> Paused (session open, no run cycles)
| |
| +---- User resumes --> Running
|
+---- User stops --> Stopped (session ends)
|
+---- User unwinds --> unwind() called --> Stopped
Execution Flow
Each time your agent executes:
- Circuit sends a
run or unwind command to your agent
- The SDK creates a fresh
AgentContext with session data
- Your
run function is called with the AgentContext
- Your code executes using SDK methods
- Results are returned to Circuit
- In manual mode, any transactions become suggestions for user approval in the UI
The Run Loop
Circuit calls your run function on a recurring interval defined by runtimeIntervalMinutes in circuit.toml:
runtimeIntervalMinutes = 15
The interval starts after the previous run completes — not from the start of execution. Each cycle is independent: your function receives a fresh AgentContext each time. To persist state between cycles, use Memory.
Run Function
async function run(agent: AgentContext): Promise<void> {
// 1. Read currentPositions to understand holdings
// 2. Apply strategy logic
// 3. Execute trades, swaps, or other operations
}
Unwind Function
Called when a user wants to exit. It receives the positions to close, which may be a subset of total holdings.
async function unwind(agent: AgentContext, positions: CurrentPosition[]): Promise<void> {
for (const pos of positions) {
// Reverse each position (e.g., swap back to starting asset)
}
}
After unwind completes, the session ends.
Modes
Configured via allowedExecutionModes in circuit.toml:
auto — Transactions execute immediately
manual — Transactions become suggestions for user approval
Your code is identical in both modes. Circuit routes the request based on the session’s mode. In manual mode, the response includes suggested and suggestionId fields.
All pending suggestions are automatically soft-deleted at the beginning of each run execution. Pass an expiresAt timestamp (ISO 8601) when submitting a transaction if you need a shorter expiry window.
For full details on modes, see Manual vs Auto Mode.
Pausing and Resuming
Users can pause a running agent from the Circuit dashboard. While paused:
- The session stays open and asset allocations remain in place
- No
run cycles are executed — the agent is effectively idle
- Memory and session state are preserved
When the user resumes, execution picks up on the next scheduled interval as if the agent had never stopped. No data is lost.
Pausing is useful when a user wants to temporarily halt an agent during volatile market conditions or while reviewing activity, without fully unwinding positions.
Key Points
- Multiple agents per wallet — a wallet can run different agents simultaneously. However, the same agent cannot run twice on the same wallet.
- Hyperliquid restriction — only one Hyperliquid agent per wallet (to safely manage shared margin). Other (non-Hyperliquid) agents can still run on that wallet.
- Session memory persists across
run cycles within a session, but is cleared when the session ends.
currentPositions reflects balances at the start of each run execution — not live balances.
- Uncaught exceptions in
run or unwind are caught by the SDK automatically. The execution is marked as failed and the error is logged.
See Also