> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roark.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build an agent on Roark

> Declare an agent Roark runs (provider: roark), and the tools it calls, in YAML. Preview with diff, publish with apply

Roark is a voice and chat agent observability and simulation platform, and it can also run your agent. A `kind: agent` with `provider: roark` is an agent Roark runs. You declare its prompt, voice, transcription, and model in your repo, declare the tools it calls as `kind: tool` resources, and `roark config apply` creates the agent and publishes a version of it. Later applies publish a new version only when what you declare differs from what the agent runs.

With `provider` set to another platform (such as `vapi` or `retell`) or omitted, `kind: agent` is a [connected agent](https://docs.roark.ai/documentation/config-as-code/agents.md#provider): it runs on that platform, and Roark observes, simulates, and grades it. Existing configs without `provider` are unchanged.

> [!NOTE]
>
> You need the [CLI](https://docs.roark.ai/documentation/sdks/cli.md) (`npm install -g @roarkanalytics/cli`), an API key with **`config:apply`** in `ROARK_API_BEARER_TOKEN`, and **Build on Roark** enabled on your account. Without Build on Roark, apply fails the agent with `Build on Roark is not enabled for this account`.

## 1. Write the agent and its tools

Put the agent and each tool in its own file under `roark/`:

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
# roark/agents/frontdesk.yaml
kind: agent
name: frontdesk
displayName: Bright Smiles Front Desk
provider: roark
prompt: file://prompts/frontdesk.md
greeting: Thanks for calling Bright Smiles, how can I help?
tts: { provider: ELEVENLABS, voiceId: EXAVITQu4vr4xnSDxMaL }
stt: { provider: DEEPGRAM, model: nova-3 }
llm: { provider: OPENAI, model: gpt-4.1 }
---
# roark/tools/lookup-patient.yaml
kind: tool
name: lookup-patient
agent: frontdesk
description: Find the caller's patient record by phone number
parameters: { phone: string }
handler:
  type: http
  url: https://clinic.example.com/api/patients/lookup
  method: POST
responseFields: [patient.name, patient.nextAppointment]
messages:
  before: Let me pull up your record.
```

* `provider: roark` is who runs the agent: Roark.
* `prompt` is the system prompt the agent runs, inline or from a `file://` path under your config root.
* `greeting`, `tts` (voice), `stt` (transcription), and `llm` (the model) sit directly on the agent. Every one is optional. The `provider` inside `tts`, `stt`, and `llm` is the speech or LLM vendor, not who runs the agent. See [Fields](https://docs.roark.ai/documentation/config-as-code/agents.md#fields) for the vendors each accepts.
* `lookup-patient` is a separate `kind: tool` that names the agent in `agent:` and declares a `handler`, so the agent calls it mid-call. See [Tools for an agent built on Roark](https://docs.roark.ai/documentation/config-as-code/tools.md#tools-for-an-agent-built-on-roark).

### Or let Roark write the prompt

If you don't have a prompt yet, leave out `prompt` and give a `jobDescription` (up to 2000 characters). On the first apply, Roark writes the prompt and greeting from it:

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
# roark/agents/frontdesk.yaml
kind: agent
name: frontdesk
displayName: Bright Smiles Front Desk
provider: roark
jobDescription: Answer calls for Bright Smiles Dental, look up the caller's patient record, and help them with their next appointment.
tts: { provider: ELEVENLABS, voiceId: EXAVITQu4vr4xnSDxMaL }
```

An agent built on Roark needs one of the two: a `prompt`, or a `jobDescription`.

## 2. Preview the changes

```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
roark config diff ./roark
```

`diff` makes no writes. On the first run it lists the agent and its tool as creates:

```text theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
  + agent/frontdesk
  + tool/lookup-patient

2 to create, 0 to update, 0 to delete
```

An unknown `tts`, `stt`, or `llm` vendor fails validation here, before anything is applied.

## 3. Apply

```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
roark config apply ./roark
```

Apply creates the agent, applies its tools, and publishes the agent's first version, which runs your prompt with `lookup-patient` attached. With the API, send the same bundle to `POST /v1/config/apply`.

## First apply and later applies

**On the first apply**, Roark creates the agent and publishes version 1. Fields you leave out, such as a model, use Roark's defaults. If you gave a `jobDescription` and no `prompt`, Roark writes the prompt and greeting now.

**On later applies**, Roark compares what you declare with the live version and publishes a new version only when they differ:

* Re-applying unchanged config is a no-op.

* Every field sets only what it names. A model you leave out keeps what the live version runs, and settings tuned in Roark, such as fallbacks, end-call reasons, or keyterms, stay unless you declare them.

* `jobDescription` is not used again. To change the prompt, declare `prompt`.

* Editing a tool shows up in `diff` as an update to the agent, and apply publishes a version that runs the edited tool:

  ```text theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
    ~ agent/frontdesk
    ~ tool/lookup-patient

  0 to create, 2 to update, 0 to delete
  ```

* Tools added to the agent in Roark stay on it. Config removes a tool from the agent only when the bundle scopes it to another agent, or when a pruning bundle drops it.

## Draft conflicts

If someone has an unpublished draft of the agent open in Roark, apply does not publish over it. The agent fails with:

```text theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
agent "frontdesk" has an unpublished draft in Roark. Publish or discard it there, then apply again.
```

Publish or discard that draft in Roark, then run `roark config apply ./roark` again.

## Other apply errors

Each of these is reported on the agent's change in the apply result, with `status: failed`. A model the vendor does not offer also fails the agent at apply.

| Message | What to do |
| :- | :- |
| `Build on Roark is not enabled for this account` | Build on Roark is not enabled on your account. Nothing is written for the agent |
| `agent "frontdesk" has an unpublished draft in Roark. Publish or discard it there, then apply again.` | See [Draft conflicts](#draft-conflicts) |
| `tool "lookup-patient" did not apply, so the agent was left on the version it runs` | Fix the tool's error, then apply again. The agent keeps running its current version |

## What's not in config yet

These are not part of an agent's config today:

* Sub-agents and handoffs
* Speech-to-speech configs
* Fallback configs
* Call and idle settings
* The chat modality
* Attaching project-wide tools to the agent
* Assigning a Roark phone number to the agent

`roark get-started` scaffolds simulation testing of an existing agent. It does not scaffold an agent built on Roark.

> [!TIP]
>
> In TypeScript, use the same flat fields on `defineAgent`: `defineAgent({ provider: 'roark', prompt, greeting, tts, stt, llm })`. There is no separate helper. See [TypeScript](https://docs.roark.ai/documentation/config-as-code/typescript.md).

> [card] [Agents reference](https://docs.roark.ai/documentation/config-as-code/agents.md#agents-built-on-roark)
>
> `provider`, every agent field, and the vendors each accepts.

> [card] [Tools reference](https://docs.roark.ai/documentation/config-as-code/tools.md)
>
> HTTP and calendar handlers, `responseFields`, and `messages`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.