Tutorial
Build your first agent
We'll start with a three-line agent and grow it into a tool-using,
composable one — a few lines at a time. Every snippet is a real
.agent file; paste any of them into the
playground to watch it compile.
Your first agent
An agent needs three things: a name, a
model, and a prompt. That's a complete,
runnable agent.
agent: greeter
model: claude-opus-4-7
prompt: |
Greet the user warmly in one sentence.
toac build greeter.agent emits a typed
greeter.ts exporting a runnable greeter.
Typed inputs
Declare parameters under inputs, then reference them in
the prompt with {inputs.<name>}. The count in
inputs[1] must match the rows.
agent: greeter
model: claude-opus-4-7
inputs[1]{name,type}:
name,string
prompt: |
Greet {inputs.name} warmly in one sentence.
The generated agent takes a typed
{ name: string } — pass the wrong shape and it's a
compile error.
Structured output
Add outputs and the agent returns a typed, validated
object instead of free text. Arrays use [].
agent: extractor
model: claude-opus-4-7
inputs[1]{name,type}:
text,string
prompt: |
Extract the key facts from: {inputs.text}
outputs[2]{name,type}:
title,string
facts,string[]
toac emits a zod schema and a "respond" tool, so the
result is parsed and typed as { title: string; facts: string[] }.
Tools
Name tools under tools; implement them in a co-located
<agent>.tools.ts. The runtime runs the tool-use
loop for you.
agent: researcher
model: claude-opus-4-7
inputs[1]{name,type}:
topic,string
tools[2]: web_search,fetch_page
prompt: |
Research {inputs.topic}. Use web_search, then fetch_page to read sources.
outputs[1]{name,type}:
summary,string
// researcher.tools.ts
import { defineTool } from "toad-runtime";
import { z } from "zod";
export const web_search = defineTool({
description: "Search the web for a query",
input: z.object({ query: z.string() }),
run: async ({ query }) => `results for ${query}`,
});
Loops & conditionals
The prompt is a small, type-checked template:
{#each} over array inputs and {#if} on
booleans.
agent: report
model: claude-opus-4-7
inputs[2]{name,type}:
findings,string[]
detailed,boolean
prompt: |
Write a report from these findings:
{#each inputs.findings as f, i}
{i}. {f}
{/each}
{#if inputs.detailed}
Add a thorough analysis section.
{:else}
Keep it to one paragraph.
{/if}
Loops compile to .map().join(""); conditionals to
nested ternaries — all validated against the typed inputs.
Composition
Declare another agent under uses and
toac wires it in as a tool — one agent calls another.
agent: planner
model: claude-opus-4-7
uses[1]: researcher
prompt: |
Plan an article. Use the researcher tool to gather sources first.
The sub-agent's typed inputs become the tool's input schema automatically. That's the whole framework: small files that compose.
Where next
You've covered the whole language. Try the playground, browse the examples, or read the full reference.