Creating an agent
Agents are defined in a folder and synced using the CLI (or SDKs).
Text agent
The structure of the agent folder looks like this:
agents/support/
agent.yaml
instructions.md
guardrail.md
knowledge/returns.md
skills/refund.mdThe CLI makes it easy to create an agent folder
curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
getstream agents init my-agent --template text # or --template voiceagent.yaml sets up the agent's model selection, connectors, tool calling, MCP and so on.
name: support
mode: text
# the model to use, can reference a router or a model
llm: llm-fast
# connectors & MCP
connectors:
- name: github
connection: company # one GitHub account your app owns
tools: [list_issues, get_*]
# if you need code execution
sandbox: daytonaconnection: company is one GitHub account your app owns, so nobody signs in. Create it as in Shared account. See Connectors to let each user connect their own. tools limits which tools it offers; leave it out for all of them. Any other MCP server is a custom connector.
connectors is read by the CLI (beta).
llm can name a route from your LLM router or a provider/model.
instructions.md tells the agent what to do:
You are Acme's support agent. Look up policies in your knowledge base before
answering. If someone asks for a refund, use the refund skill.Try your agent using the CLI:
getstream agents test support --syncguardrail.md aims to prevent your agent from answering questions it shouldn't.
You don't want your support bot answering "why the sky is blue?", or "solve Navier-Stokes".
It runs a decision model in parallel to the LLM response. Keep in mind that these tools never capture 100% of abuse.
See Guardrails for blocking mode, thresholds and webhooks:
---
refusal: I can only help with questions about your Acme account and orders.
---
Answer questions about Acme products, orders, billing, shipping and returns.
Refuse anything else.knowledge/ contains markdown files and URLs which are indexed. knowledge/urls.yaml allows you to index URLs. See Knowledge & skills.
For more advanced use cases you can expand on this with tool calling.
Items can be returned within 30 days of delivery for a full refund to the
original payment method. After 30 days, Acme offers store credit instead.
Opened headphones can only be returned if they are faulty.skills/ make it easy to define a process for an agent.
You could have a "refund" skill, or "package_tracking" or basically anything.
Skills are the most important part of building a useful agent.
See Skills for every option:
---
description: work out whether a customer is owed a refund, and how much
---
Read the return policy and the order details the customer gave. Say whether
they are owed a refund, how much, and to which payment method. Two sentences
at most. If you need something only the customer knows, ask for it.Sync your agent and talk to it:
getstream agents test support --syncAnd for example ask: "What is your return policy?" to see the knowledge base answer, then "I bought headphones 40 days ago, can I get my money back?" to see the agent load the refund skill and follow it.
Voice agent
The approach for voice AI is just as straightforward. You can create a voice agent from the CLI like this
getstream agents init my-agent --template voiceAlternatively you can edit the agent.yaml for the agent you already have. The changes you want to make are:
- Subagent: we use modern openAI style voice. The conversational/fast LLM hands of more complicated questions to the subagent. So you typically want a fast/ not so smart conversational model, and a slower/thinking subagent.
- stt/tts: these can be set to a specific model or a router
- greeting: how you say hi (text or variation mode)
- keyterms: optionally terms that are common to your use case
name: support
mode: voice # joins a call
llm: llm-fast
subagent: llm-thinking
stt: en-low-latency # transcription
tts: en-low-latency # the voice it speaks with
greeting:
text: Northwind Pizza, what can I get you?
mode: variation # don't always say the exact same thing
keyterms: [Acme, store credit]getstream agents test support --syncTo run on a native speech-to-speech model instead, name an sts route. It replaces stt, tts and llm:
name: support
mode: voice
sts: en-low-latency
subagent: llm-thinkingOther channels
The same agent can answer on other channels too:
See Connectors for everything else it can reach. To let it see, see Video.
Agent deep dive
To recap:
| Path | What it holds | Learn more |
|---|---|---|
agent.yaml |
What the agent runs on | agent.yaml |
instructions.md |
The system prompt | |
guardrail.md |
What it will and will not answer | Guardrails |
skills/*.md |
Workflows loaded when they are needed | Knowledge & skills |
knowledge/*.md |
What it may look things up in | Knowledge & skills |
knowledge/urls.yaml |
Pages the backend crawls into the knowledge base | Adding URLs to knowledge |
simulations/*.yaml |
Conversations to test it with | Simulations & evals |
.agent_sync |
Written by the sync: what was last synced, and when |
Only agent.yaml is required
agent.yaml
Every key names a route or setting rather than hard-coding a model:
| Key | What it sets |
|---|---|
name |
The config's name, which sessions are opened by. The CLI requires it; the SDKs fall back to the directory name. |
description |
A note for whoever reads the config. |
mode |
voice or text. A text agent needs no call and uses no speech routes. Defaults to voice. |
llm |
The route or provider/model that holds the conversation. See LLM. |
subagent |
Voice only: the route skills run on. When agent.yaml names none, the router defaults to llm-thinking when the deployment can route it, and the fast model answers everything itself when it cannot. A text agent runs its skills on its llm and is refused one. See Harness & sandbox. |
stt, tts |
Transcription and voice routes for a cascade (transcribe, answer, speak). See STT and TTS. |
sts |
A native speech-to-speech route. Naming one replaces stt, tts and llm. |
voice |
The voice the agent speaks in, including a cloned one. See TTS. |
greeting |
Said on joining without asking the model. Empty waits to be spoken to. |
search |
The web search route the agent may use. |
keyterms |
Words the transcriber should expect: names, products, jargon. |
harness |
Which harness runs the agent. default is the only one. |
sandbox |
daytona lets the agent run code: the subagent on a voice agent, the agent itself on a text agent. See Harness & sandbox. |
connectors |
Connectors, including your own for any MCP server. See Connectors. |
video |
source and max_frames (1 to 8) for an agent that looks at video. See Video. |
tags |
Cost labels, so spend can be attributed to whatever they mean to you. |
app |
Your application's own settings. Never sent to Stream, and the one place an unknown key is allowed. |
Going further
To learn more about each feature:
Screen every turn with guardrail.md, a classifier or your own webhook.
Knowledge files, URLs to crawl, and skills.
Test the agent with simulated conversations and a judge.
Hand-off to the subagent, compaction, and running code in a sandbox.
Your own functions, run in your process.
Linear, Slack, GitHub and more. One shared account, or each user's own.