How it works

The words the rest of the docs use.

The three parts

PartWhat it is
EngineRuns the agent loop. It calls the model, runs tools, saves every step, and streams events. It is the cloud, or the subs binary.
WorkerYour code. It is an HTTP endpoint that answers a decision request. It is optional.
ClientAnything that sends messages and reads events. Slack, a browser, your backend, or the CLI.

Agents

You declare an agent in substructure.toml.

[agent.oncall]
llm = "openrouter"
model = "anthropic/claude-sonnet-4-5"
system = "You are the on-call assistant."

The section says what the agent is: its model, its prompt, its tools, and the other agents it can call. See Agents.

The worker key selects who decides. Set it and the engine sends every decision for that agent to your code. Leave it off and the engine decides. One project can hold both kinds.

Sessions and turns

A session is one conversation. It holds the messages, the tool calls, the state, and the config. The engine saves all of it.

A turn starts when a client sends input. It ends when the agent stops responding. A session runs one turn at a time.

Decisions

The engine asks what happens next at every step of a turn. That question is a decision request.

{
    "trigger": { "type": "tool.execute", "name": "get_time" },  // why the engine is asking
    "proposed": { },   // what the engine plans to do
    "state": { },      // your agent state
    "agent": { },      // the current config
    "messages": [ ]    // the conversation so far
}

The answer is a decision response.

{
    "actions": [ ],    // what to do next
    "messages": [ ],   // messages to record
    "state": { },      // omit to keep the current state
    "agent": { }       // omit to keep the current config
}

For most triggers the engine already has a plan, and proposed holds it. Return proposed unchanged to accept it. That is a complete agent.

An agent with no worker runs the same loop. The engine proposes, then accepts its own proposal.

See Workers to write the code, and Protocol for every field.

Triggers

The trigger says why the engine is asking.

TriggerMeaning
session.startA session was created.
client.messagesA client sent or edited messages.
client.actionA client called a named action.
tool.executeThe model called one of your tools. Run it.
tool.finishedA tool call ended.
llm.executeYour worker makes this model call.
llm.finishedA model call ended.
sub_agent.finishedA child session completed.
interrupt.resumedSomeone resumed a paused branch.

Actions

The actions in a decision tell the engine what to do.

ActionMeaning
llm.callMake a model call.
tool.callStart a tool call.
tool.result / tool.errorEnd a tool call.
llm.result / llm.errorEnd a model call the worker made.
sub_agent.spawnStart a child session.
message.sendWrite a message into a session.
interruptPause the branch until someone resumes it.
doneEnd the turn.

Where things run

CallDefaultAlternative
DecisionsThe engineYour worker. Set worker on the agent.
ToolsYour workerThe browser. See Client-side tools.
Model callsThe engineYour worker. Set type = "worker" on the LLM block. See LLMs.

Durability

The engine saves every trigger, decision, and call before it acts. If the engine or your worker stops, the run continues from the last saved step. See Durability.

Next