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.
1 · 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.
2 · 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.
3 · 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[] }.
4 · 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}`,
});5 · 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.
6 · 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 format reference.
