# Creating an agent

Agents are defined in a folder and synced using the [CLI](https://getstream.io/cli/docs/install/) (or SDKs).

## Text agent

The structure of the agent folder looks like this:

```text
agents/support/
  agent.yaml
  instructions.md
  guardrail.md
  knowledge/returns.md
  skills/refund.md
```

The CLI makes it easy to create an agent folder

```sh
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 voice
```

`agent.yaml` sets up the agent's model selection, connectors, tool calling, MCP and so on.

```yaml title="agents/support/agent.yaml"
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: daytona
```

`connection: company` is one GitHub account your app owns, so nobody signs in. Create it as in [Shared account](https://getstream.io/agents/docs/ios/connectors/shared-account/). See [Connectors](https://getstream.io/agents/docs/ios/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](https://getstream.io/agents/docs/ios/connectors/mcp/).

`connectors` is read by the CLI (beta).

`llm` can name a route from your [LLM router](https://getstream.io/agents/docs/ios/llm/) or a `provider/model`.

`instructions.md` tells the agent what to do:

```markdown title="agents/support/instructions.md"
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:

```sh
getstream agents test support --sync
```

`guardrail.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](https://getstream.io/agents/docs/ios/guardrails/) for blocking mode, thresholds and webhooks:

```markdown title="agents/support/guardrail.md"
---
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](https://getstream.io/agents/docs/ios/knowledge-and-skills/).
For more advanced use cases you can expand on this with [tool calling](https://getstream.io/agents/docs/ios/tool-calling-and-dispatch/).

```markdown title="agents/support/knowledge/returns.md"
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](https://getstream.io/agents/docs/ios/knowledge-and-skills/#skills) for every option:

```markdown title="agents/support/skills/refund.md"
---
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:

```sh
getstream agents test support --sync
```

And 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

```sh
getstream agents init my-agent --template voice
```

Alternatively 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

```yaml title="agents/support/agent.yaml"
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]
```

```sh
getstream agents test support --sync
```

To run on a native speech-to-speech model instead, name an `sts` route. It replaces `stt`, `tts` and `llm`:

```yaml title="agents/support/agent.yaml"
name: support
mode: voice
sts: en-low-latency
subagent: llm-thinking
```

## Other channels

The same agent can answer on other channels too:

- [Phone](https://getstream.io/agents/docs/ios/telephony/purchase-number/): give it a number, or bring your own SIP trunk
- [WhatsApp](https://getstream.io/agents/docs/ios/connectors/whatsapp/)
- [iMessage](https://getstream.io/agents/docs/ios/connectors/imessage/)
- [SMS](https://getstream.io/agents/docs/ios/connectors/sms/)
- [Slack](https://getstream.io/agents/docs/ios/connectors/slack/)

See [Connectors](https://getstream.io/agents/docs/ios/connectors/) for everything else it can reach. To let it see, see [Video](https://getstream.io/agents/docs/ios/video/).

## Agent deep dive

To recap:

| Path                  | What it holds                                       | Learn more                                                                                         |
| --------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `agent.yaml`          | What the agent runs on                              | [agent.yaml](#agentyaml)                                                                           |
| `instructions.md`     | The system prompt                                   |                                                                                                    |
| `guardrail.md`        | What it will and will not answer                    | [Guardrails](https://getstream.io/agents/docs/ios/guardrails/)                                                  |
| `skills/*.md`         | Workflows loaded when they are needed               | [Knowledge & skills](https://getstream.io/agents/docs/ios/knowledge-and-skills/)                                |
| `knowledge/*.md`      | What it may look things up in                       | [Knowledge & skills](https://getstream.io/agents/docs/ios/knowledge-and-skills/)                                |
| `knowledge/urls.yaml` | Pages the backend crawls into the knowledge base    | [Adding URLs to knowledge](https://getstream.io/agents/docs/ios/knowledge-and-skills/#adding-urls-to-knowledge) |
| `simulations/*.yaml`  | Conversations to test it with                       | [Simulations & evals](https://getstream.io/agents/docs/ios/simulations-and-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](https://getstream.io/agents/docs/ios/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](https://getstream.io/agents/docs/ios/harness-and-sandbox/). |
| `stt`, `tts`  | Transcription and voice routes for a cascade (transcribe, answer, speak). See [STT](https://getstream.io/agents/docs/ios/stt/) and [TTS](https://getstream.io/agents/docs/ios/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](https://getstream.io/agents/docs/ios/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](https://getstream.io/agents/docs/ios/harness-and-sandbox/).                                                                                                                                                                   |
| `connectors`  | Connectors, including your own for any MCP server. See [Connectors](https://getstream.io/agents/docs/ios/connectors/).                                                                                                                                                                                                                                    |
| `video`       | `source` and `max_frames` (1 to 8) for an agent that looks at video. See [Video](https://getstream.io/agents/docs/ios/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:

- [Guardrails](https://getstream.io/agents/docs/ios/guardrails/): Screen every turn with guardrail.md, a classifier or your own webhook.
- [Knowledge & skills](https://getstream.io/agents/docs/ios/knowledge-and-skills/): Knowledge files, URLs to crawl, and skills.
- [Simulations & evals](https://getstream.io/agents/docs/ios/simulations-and-evals/): Test the agent with simulated conversations and a judge.
- [Harness & sandbox](https://getstream.io/agents/docs/ios/harness-and-sandbox/): Hand-off to the subagent, compaction, and running code in a sandbox.
- [Tool calling & dispatch](https://getstream.io/agents/docs/ios/tool-calling-and-dispatch/): Your own functions, run in your process.
- [Connectors](https://getstream.io/agents/docs/ios/connectors/): Linear, Slack, GitHub and more. One shared account, or each user's own.

---

For the most recent version of this documentation, visit [https://getstream.io/agents/docs/ios/creating-an-agent/](https://getstream.io/agents/docs/ios/creating-an-agent/).