agent.yaml plus the prompts, tool files and knowledge
folders it points at. It answers three questions: who answers the call, what
each agent may do, and what each of those things actually is.
One rule explains the whole file:
An agent owns its own handoffs, transfers, flows and tasks. Each one is written in full inside the agent that uses it first. Any other agent names it with a bare name.On this page:
- Quickstart - the smallest package with two agents
- The five things an agent can do - and which give the caller back
- Every key an agent takes - four required, five lists
- Build one in three steps - the worked version
- How a value gets from one step to the next -
variables:,save:,context: - What the compiler holds for you - the errors you cannot write past
Quickstart
Two agents.front_desk answers, and can hand the caller to
complaint_specialist:
agent.yaml
front_desk writes the handoff block, so the definition sits beside the agent
that uses it. Another agent that wants the same handoff writes its bare name,
- to_complaints. A bare name nobody defines is refused, and so are two blocks
with one name.
The same goes for tasks, flows and transfers.
The five things an agent can do
An agent is a person on the phone. It can do five kinds of things, and each kind has its own list:
If you remember one thing, remember the third column. Tools, tasks and flows
come back. Handoffs and transfers do not.
Every key an agent takes
An agent has four required keys and five optional lists. There are no others.string
required
What the agent is called. Other agents and
entry_agent: use this name.file path
required
The Markdown file holding this agent’s prompt, relative to the package root.
model name
required
Which reasoning model this agent uses. Names one entry under
models.think.model name
required
Which voice this agent speaks in. Names one entry under
models.speak.model name
Which transcriber this agent hears with, for an agent that speaks another language.
Names one entry under
models.listen. Omit it to use the package’s.list of names
Tools this agent may call. Each name is a file under
tools/<name>.yaml.list of tasks or names
Tasks this agent may run. Write the task in full to define it here, or write
a bare name to run a task another agent already defined.
list of flows or names
Flows this agent may run. Write the flow in full to define it here, or write
a bare name to run a flow another agent defined.
list of handoffs or names
Agents this one can hand the caller to. Write the handoff in full to define
it here, or write a bare name to use one another agent defined.
list of transfers or names
People this agent can put the caller through to. Write the transfer in full to
define it here, or write a bare name to use one another agent defined.
Build one in three steps
Say you want two agents, and each one can run a task. Step 1. Say who answers.agent.yaml
messages. Saved values reach the receiving model only through
placeholders in its prompt. A transfer’s to: names the environment variable
that holds the phone number, never the number.
agent.yaml
front_desk top to bottom. You already know everything it can do, and
which kind of thing each one is. That glance is the point of the five lists.
Step 3. Add the tools. Every file under tools/ is a tool, so there is no
list to keep. Declare MANAGER_PHONE_NUMBER in secrets:. The top-level
tools: list is only for a tool that needs behaviour around it on every agent,
such as a line said as it starts:
agent.yaml
verify_customer twice. It is defined once,
inside front_desk, and complaint_specialist just names it. Sharing is
naming the same thing.
How a value gets from one step to the next
Three keys do this, and they each do one thing. Each has its own page.top-level list
Says where a value comes from and which step confirms it. The value itself,
its type and its default are a field on
State in state.py, the box.
Nothing fills it by itself.Variableson a task
Fills a variable when the task finishes.
- customer_phone: result.phone
means “put the task’s phone answer into customer_phone”.Taskson a task or a handoff
Chooses how much of the conversation so far the next step can read. It moves
the transcript, not your saved values.Context scope
{{state.customer_phone}}.
Ordering work without a gate
In the example above,verify_customer fills customer_phone with save:,
and manage_booking’s own when: says it runs only once the caller is
identified. That is how “verify before booking” works: the order lives in the
prompt, not in a gate, so the caller hears nothing about it.
Put that clause on the work that needs the value, not on the route to it. And
never hold up the way to a person: somebody asking for a manager should not be
interviewed first.
Tasks attach handoffs, and nothing else
A task hastools: and handoffs: and no other list. There is no tasks:,
no flows: and no transfers: key on a task, so a task cannot run
another task or flow, or reach a person directly. That is not a rule
you have to remember. The key does not exist, so the file cannot be written.
What the compiler holds for you
- A bare name in an agent’s list must be defined by some agent. A typo is a build error, not a silent gap.
- A name listed under the wrong kind is refused, and the message names the list it belongs on.
- All five kinds share one namespace, because every name becomes a callable function at runtime. Two things cannot share a name, and two agents defining the same name is refused the same way.
- A handoff, transfer, flow or tool that no agent reaches is also a build error. There is no dead config to forget about.
- A task can list
tools:andhandoffs:only, enforced by the shape of the file.
Order, and what it does not mean
Nothing an agent lists runs in list order. The model picks what to use from thewhen: text. Two things in a package do run in a fixed order: the steps: of
a flow, and the entries of prefetch:. Pre-fetch
entries resolve top to bottom, and an entry that reads a value only a later
entry saves stops the build.
Order is not free everywhere, though: the order of names in a list is the
order the tools are declared to the model in the generated code, so
reordering a list produces a different file. Treat that as presentation, not
as control flow.
The order to write the file in
unmute init writes the shape without
prefetch:, since the scaffold declares none. examples/salon-concierge shows
where it lands once a package uses it: right after variables:.
channels: and capacity: are not in this file. They sit at the top of
targets.yaml.
Every one of those keys, with its type, whether it is required, and what values
it accepts, is in the
agent.yaml key table.
Where to go next
Your first task
Add one task to the agent you just made, one key at a time.
Tasks
Nested tasks and typed results.
Handoffs
When to split into two agents.
Flows
Tasks in a fixed order, sharing what they learn.
Human transfers
Cold and warm transfer to a person.