Sub-agents — the Level-1 surface over the agent runtime (SPEC §7D).
One axiom: an Agent is a Tool — (system prompt × a filtered toolkit view ×
the §8 client loop), invocable as a uniform Toolnexus.Tool. One new noun:
agent/2. Everything compiles to the six runtime verbs.
explore = Toolnexus.Agents.agent("explore", does: "read-only research", uses: %{tools: [lookup]})
coder =
Toolnexus.Agents.agent("coder",
does: "implements changes",
soul_file: "AGENTS.md",
team: [explore]
)
r = Toolnexus.Agents.run(coder, [transport: transport, llm: %{model: "gpt-4o-mini"}], "fix the failing test")
r.textas_tool/2 is the bridge the other way: it turns an agent into a %Toolnexus.Tool{}
for the classic API's extra tools. If the agent suspends durably (§10), the tool
result carries metadata.pending, and a §10 retry with ctx.answer resumes it —
agent suspension and tool suspension are the same machinery.
Summary
Functions
The one new noun. Spec fields (§7D Level-1 surface)
The bridge: an Agent IS a Tool — drop it into the classic API's extra tools.
Collect this agent + its whole team graph into a runtime registry — the transitive closure of the entry agent's team graph; unreachable agents are not present (§7D team scoping).
Level 1: one-shot — build a runtime, run the agent to completion, tear down.
Functions
@spec agent(String.t(), keyword() | map()) :: Toolnexus.Agents.AgentDef.t()
The one new noun. Spec fields (§7D Level-1 surface):
:does— required routing description (advertised to delegating parents):uses— toolkit view,%{tools: [%Toolnexus.Tool{}]}:soul— inline system prompt, or:soul_file— path to read it from:team— list ofagent/2values this agent may delegate to viatask(children never inherit delegation — recursion is opt-in per definition):budget—%{max_turns, max_tokens, max_tool_calls, max_wall_ms, max_children, max_concurrent, max_depth}:model— default"inherit"(the runtime'sllm.model):wait_for— §10 interpreter authority ((Request -> Answer)):on_spawn/:on_close— lifecycle callbacks:hooks/:on_metric— the §8 seams for THIS agent's turns; each replaces the runtime-wide value (never merged). A §7F compactor rides:hooks.
@spec as_tool(Toolnexus.Agents.AgentDef.t(), keyword() | map()) :: Toolnexus.Tool.t()
The bridge: an Agent IS a Tool — drop it into the classic API's extra tools.
A durable suspension surfaces as a §10 pending tool result; the client's
retry-with-ctx.answer re-runs the agent with that Answer as its interpreter.
@spec registry(Toolnexus.Agents.AgentDef.t(), map()) :: map()
Collect this agent + its whole team graph into a runtime registry — the transitive closure of the entry agent's team graph; unreachable agents are not present (§7D team scoping).
@spec run(Toolnexus.Agents.AgentDef.t(), keyword() | map(), String.t()) :: map()
Level 1: one-shot — build a runtime, run the agent to completion, tear down.
rt_opts are Toolnexus.Agents.Runtime options (:transport, :llm, ...).
Returns %{text, is_error, status, pending, turns, total_tokens}. When the run
suspends durably (status: "pending"), the live runtime rides along under
:runtime so the host can Runtime.resume/2 and must shut it down itself;
otherwise the runtime is already torn down.