Execution Model
How an agent call lands, gets proved, and resumes — across blocks.
In one paragraph
- Stage 1 (queue):
call_agentinterprets the agent’s ABG until it hits a model or tool call, then suspends. - Stage 2 (prove): an off-chain prover picks up the job and submits a verified result via
submit_inference_result. - Stage 3 (resume): an inherent-driven
on_initializehook scans verified results and resumes the agent’s ABG with the original caller’s origin. - Capability surface:
pallet_shipvalidates every emitted intent against the ABG’s declared capability set. Calls outside that set are rejected.
The three stages
Each stage is a distinct extrinsic with a distinct caller. The chain only verifies what each stage’s extrinsic carries — never raw prover output, never tool results from anyone but the registered enclave.
Stage 1 — Queue (call_agent)
A signed transaction lands in a block. pallet_agents creates an entry in PendingAgentJobs, records the original user origin, and begins interpreting the agent’s ABG. The interpreter advances through synchronous nodes (conditions, sequence, parallel) until it hits a ModelCall or ToolCall.
At that point AIVM queues an inference job and emits InferenceQueued. The agent suspends. The block closes; the user’s transaction is done.
Stage 2 — Prove (submit_inference_result)
An off-chain prover, subscribing to InferenceQueued, picks up the job. It runs the inference, generates a TensorCommitment proof (full prover) or signs the output (lite prover), and submits the result. AIVM verifies the proof via the native KZG host function and marks the job InferenceVerified.
No agent state transitions occur in this stage. The prover’s role is bounded: supply the inference result and the verification material. Nothing else.
Stage 3 — Resume (inherent, block-author-driven)
On every block, an on_initialize hook scans InferenceVerified entries (bounded by a per-block weight budget). For each, the agent loop resumes with the verified result, executing under the original user origin recorded in Stage 1.
The agent continues interpreting the ABG until it either hits another async boundary (back to Stage 1/2) or reaches a terminal node that emits SHIP intents. Intents execute under the same original origin.
Why three stages, not one
The split exists because each stage has a different trust relationship with the chain.
- The user can submit
call_agentbut cannot run inference. They’re only authorized to start the work. - The prover can run inference and submit proofs but cannot mutate agent state. They’re only authorized to supply verified results.
- The runtime (via the inherent hook) is the only thing that mutates agent state, and only after KZG verification has passed. State changes are always driven by deterministic on-chain logic, never by prover-controlled extrinsics.
Result: prover compromise can’t change agent state
What kicks off Stage 1
Agents don’t run on every block — they sit dormant until something wakes them. There are three trigger categories:
Events
On-chain events the agent subscribes to: token transfers, calls from other agents, contract state changes.
Time
Scheduled wake-ups at a specific block height or interval. Cron-shaped.
External users
Anyone calls call_agent with an entrypoint and input.
The original-origin invariant
When call_agent lands in Stage 1, the chain records the caller’s origin. Every later step in that agent’s execution — Stage 2’s prover submission, Stage 3’s ABG resume, the eventual SHIP intents emitted at terminal nodes — runs under that same origin.
That preserves two things:
- Fee accounting. The agent pays for inference and tools out of its own seus balance (reverse-gas), but user-side fees on the originating
call_agentare billed to the original caller. - Authorization. SHIP intents that touch other accounts (transfers, contract calls) execute as the original caller, not as the agent. The agent can act on the caller’s behalf only to the extent the caller pre- authorized via the entrypoint.
Capability surface enforcement
An agent’s ABG declares the set of models, tools, sub-agents, and intent types it’s allowed to reference. This capability surface is part of the ABG itself, stored on-chain at registration time.
At every async boundary, AIVM and pallet_tools check that the requested model or tool is in the surface. At every terminal node, pallet_ship validates that emitted intents are inside it. Anything outside the surface is rejected at the runtime layer — the agent cannot exceed its declared capabilities even if the underlying model output suggests doing so.
Per-run limits
Each agent run is bounded so a misbehaving model can’t consume unbounded block weight or storage. The headline numbers:
| Limit | Value |
|---|---|
| Max ABG nodes | 256 per agent |
| Max steps per run | 64 |
| Sync steps per tick | 16 |
| Max messages per run | 10 |
| Max sub-agent call depth | 2 |
| Inference retries per node | 2 |
| Tool retries per node | 2 |
| Job expiry | 600 blocks (~1 hour) |
Full reference at Network Parameters.