Documentation
Build agents with TOAD
A .agent file is a small, indentation-based document (2
spaces, never tabs) — a strict superset of
TOON. You describe what the agent is; toac emits the
how.
How it works
flowchart TD A["your.agent"]:::file --> S1["1 · lower<br/>prompt: | blocks become valid TOON"] S1 --> S2["2 · decode<br/>parsed by the real @toon-format/toon decoder"] S2 --> S3["3 · validate<br/>keys, types, tools, inputs.x refs → a typed agent model"] S3 --> S4["4 · emit"] S4 --> B["your.ts<br/>readable, typed TypeScript on toad-runtime, over Claude"]:::file classDef file fill:#0c1411,stroke:#4ade80,color:#b8f3cf,stroke-width:1.5px;
Real logic (what a tool actually does) lives in plain TypeScript, in a
co-located <agent>.tools.ts.
The .agent format
| Key | Req | Form | Meaning |
|---|---|---|---|
agent |
yes | identifier | the agent's name (also the export + filename) |
model |
yes | string | a Claude model id, e.g. claude-opus-4-7 |
description |
no | string | one line on what it does |
inputs |
no | inputs[N]{name,type}: + N rows |
typed call parameters |
tools |
no | tools[N]: a,b |
tool names, implemented in <agent>.tools.ts |
prompt |
yes | prompt: | + block |
the instruction prompt |
outputs |
no | outputs[N]{name,type}: + N rows |
typed structured result |
system |
no | system: | + block |
system prompt (defaults to the description) |
uses |
no | uses[N]: a,b |
sub-agents wired in as tools via asTool() |
maxTurns / retries |
no | number | tool-use turn cap / model-call retries |
A header's count must match its rows: inputs[2]{...} has
exactly two rows; tools[2]: a,b lists exactly two names.
Types
string, number, boolean, or a
quoted object type like "{title:string;score:number}".
Append [] for an array (string[], or
"{...}[]"). Read object fields with
{inputs.x.field} or, in a loop, {item.field}.
Interpolation
Inside prompt, {inputs.<name>} inserts a
declared input and {env.<NAME>} inserts an
environment variable (process.env.<NAME>, empty string
if unset). {{ and }} are literal braces. Every
reference is validated against the agent's typed inputs, with located
file:line:col diagnostics.
Loops
Iterate an array input with
{#each inputs.<name> as <item>} …
{/each}. Add a 0-based index with
{#each … as <item>, <i>}, an empty-list fallback
with {:else}, and destructure object elements with
{#each rows as {a, b}}.
prompt: |
Summarize these notes:
{#each inputs.notes as note, i}
{i}. {note}
{:else}
No notes provided.
{/each}
Conditionals
Include a section based on a boolean input with
{#if inputs.<flag>} …
{:else if inputs.<other>} … {:else} …
{/if} (a leading ! negates).
prompt: |
{#if inputs.detailed}
Write a thorough analysis.
{:else}
Keep it brief.
{/if}
A complete example
A kitchen-sink agent using loops, conditionals, object fields, and destructuring — all type-checked:
Try it live in the playground.
The runtime (toad-runtime)
The generated agent runs a tool-use loop over the Anthropic API with:
outputs become a typed, validated
result.
uses: or
asTool().
retries, maxTurns, and
onToolCall / onToolResult /
onError hooks.
agent.stream(inputs) yields text deltas.
The tool-use loop, end to end:
flowchart TD
I["inputs (typed)"]:::file --> M["call Claude<br/>system + prompt"]
M --> Q{"wants a tool?"}
Q -->|yes| T["run the tool<br/>your .tools.ts"]
T --> M
Q -->|no| O["validate against outputs<br/>→ typed result"]:::file
classDef file fill:#0c1411,stroke:#4ade80,color:#b8f3cf,stroke-width:1.5px;
Composition
An agent can be used as a tool by another — call asTool()
and list it in the parent's tools, or skip the wiring and
declare it with uses; toac imports it and
calls asTool() for you.
# planner.agent
agent: planner
model: claude-opus-4-7
uses[1]: researcher
prompt: |
Plan an article. Use the researcher tool to gather sources first.
flowchart TD P["planner agent"]:::file -->|"uses: researcher"| R["researcher.asTool()<br/>typed inputSchema"] R --> L["researcher runs its<br/>own tool-use loop"] L --> O["typed result<br/>returned to planner"] O --> P classDef file fill:#0c1411,stroke:#4ade80,color:#b8f3cf,stroke-width:1.5px;
Write agents with AI
TOAD's syntax is small and explicit on purpose — so an LLM can author it. Copy this prompt into Claude, describe your agent, and paste the result into the playground.
Full reference also lives in docs/authoring.md.