Agents

An agent is a model, a prompt, and a set of tools. You declare one with an [agent.<id>] section.

substructure.toml
[llm.openrouter]
type = "openrouter"

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

The id is how everything else names the agent. Slack routes to it. A client submits to it. A parent agent calls it.

What you can declare

KeyMeaning
llmWhich [llm.<id>] block the model call runs on.
modelThe model to call.
systemThe system prompt.
descriptionWhat this agent does, for a parent that calls it.
mcpConnections whose tools the model can call. See Connectors.
sub_agentsOther agents this one can call. See Sub-agents.
toolsTools the browser runs. See Client-side tools.
workerWhere decisions go. See Workers.
retryTimeouts and attempts. See Retries.
signing_secret_envThe variable holding the signing secret, for an engine you run.

Every key of the wire AgentConfig works here under the same name. See Config for the full reference.

Several agents

A second agent is a second section. Each one names its own model.

substructure.toml
[llm.claude]
type = "anthropic"

[llm.cheap]
type = "openai"

[agent.assistant]
llm = "claude"
model = "claude-sonnet-4-5"
system = "Delegate research to the researcher, then answer."
sub_agents = ["researcher"]

[agent.researcher]
description = "Finds and reads sources."
llm = "cheap"
model = "gpt-5-mini"
system = "Answer with citations. Be brief."

The model sees researcher as a tool. The child runs in its own session with its own transcript and cost.

Who decides

worker selects who answers this agent's decisions.

workerResult
SetThe engine POSTs every decision to that URL.
Not setThe engine decides by accepting its own proposal.

Routing is per agent. An engine-hosted parent can call a worker-hosted child.

substructure.toml
[agent.triage]
llm = "claude"
model = "claude-haiku-4-5"
worker = "https://triage.internal/agent"

Agents whose worker writes the config

A section has two jobs. It declares that the agent exists, and it can set the config. An agent whose worker builds its own config needs only the first.

substructure.toml
[agent.reggu]
worker = "http://localhost:4000/substructure/agent"

That section sets nothing, so session.start carries no proposal and the worker declares the whole agent. Two rules follow.

  • An agent that sets nothing needs a worker.
  • An agent that sets anything needs llm and model.

A partial config is a parse error.

Tools

Tools come from three places.

SourceRuns onDeclared in
A connectorThe enginemcp on the agent
Your codeYour workerThe config the worker returns
The browserThe clienttools on the agent, with handler = "client"

Only browser tools go in the file. The tools your worker runs are worker code.

Next