> ## 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.

# Config as Code

> Define your Roark agents, personas, flows, and collectors as YAML in git and deploy them with one apply

## Overview

Config as Code lets you define your Roark resources - agents, personas, simulation flows, and metric collectors - as YAML files in your own git repository, then deploy them with a single apply. Your config repo is the source of truth: Roark reconciles the live project to match what you submitted, creating what's new, updating what changed, and removing what you deleted.

<Note>
  Config as Code manages **resource definitions**. It does not run simulations or place calls; you trigger those as usual once the resources exist.
</Note>

You write only a human-readable `name` for each resource. Roark derives a stable identity (`configKey = <kind>/<name>`) and resolves cross-references by name, so there are no UUIDs in your files and no state file to keep in sync.

***

## How it works

You submit the full desired set of resources to a single endpoint. Roark:

1. **Parses and validates** every resource against the schema.
2. **Diffs** the submitted set against the resources this project already manages via config.
3. **Reconciles**: creates new resources, updates changed ones, and (unless you opt out) deletes config-managed resources you removed from the submission.

There are two endpoints:

| Endpoint                | What it does                                                      |
| :---------------------- | :---------------------------------------------------------------- |
| `POST /v1/config/plan`  | **Dry run.** Returns the changes that *would* be made. No writes. |
| `POST /v1/config/apply` | **Applies** the changes and returns what happened.                |

Always run `plan` first to preview the diff, then `apply`.

***

## Prerequisites

* A Roark API key with the **`config:apply`** permission. Generate one from [API Keys](/documentation/getting-started/api-keys) and confirm it carries `config:apply`.
* A git repository to hold your config files (any layout; Roark reads the files you submit).

<Note>
  The API key is scoped to a single project. Everything you apply lands in that project.
</Note>

***

## Repository layout

One file per resource, discriminated by `kind`. A conventional layout:

```
roark/
  agents/frontdesk.yaml
  personas/frustrated-caller.yaml
  flows/frustrated-rebooking.yaml     # improv flow
  flows/booking-scripted.yaml         # scripted-graph flow
  collectors/consent-on-frontdesk.yaml
  prompts/escalates-to-manager.md     # referenced by file://
```

Add this header to any resource file for editor autocomplete and validation:

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
# yaml-language-server: $schema=https://schema.roark.ai/roark-config.schema.json
```

***

## Resource kinds

### Agent

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
kind: agent
name: frontdesk
description: Bright Smiles front desk booking agent
customId: bright-smiles-frontdesk
endpoints:
  - name: outbound-primary
    value: '+15551234567'
    direction: INCOMING_AND_OUTGOING
```

### Persona

The simulated caller. Self-contained (references nothing).

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
kind: persona
name: frustrated-caller
displayName: Dana Whitfield
language: EN
accent: US
gender: FEMALE
baseEmotion: FRUSTRATED
backstoryPrompt: file://prompts/frustrated-caller.md
```

### Flow (improv)

An improvised simulation with a happy path and edge-case variants. References agents, a persona, and an environment by name.

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
kind: flow
type: improv
name: frustrated-rebooking
agents: [frontdesk]
happyPath:
  persona: frustrated-caller
  environment: default
  prompt: You call to rebook the cleaning that was cancelled on you.
edgeCases:
  - name: escalates-to-manager
    prompt: file://prompts/escalates-to-manager.md
    expectations:
      - Agent offers to escalate rather than arguing
```

### Flow (scripted)

A step-by-step conversation graph (branches, merges, DTMF, voicemail, scenario links). Each apply replaces the whole graph.

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
kind: flow
type: scripted
name: booking-scripted
agents: [frontdesk]
branchingMode: ADAPTIVE
graph:
  - ref: greeting
    type: AGENT_TURN
    content: Thanks for calling, how can I help?
    steps:
      - ref: request
        type: CUSTOMER_TURN
        content: I'd like to book a cleaning.
```

### Collector

Decides which metrics get collected on which conversations (the config form of a [collector](/documentation/metrics/metric-collectors)).

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
kind: collector
name: consent-on-frontdesk
modality: call
status: ACTIVE
metrics:
  - consent_collection_consent_obtained
  - interruption_appropriateness_appropriate
filters:
  - conditions:
      - type: AGENT
        key: frontdesk
        operator: EQUALS
```

* **Metrics** are referenced by their stable slug, not a UUID, and must be visible to the project and support the collector's `modality`.
* **Filters** are condition groups: groups OR together, conditions within a group AND. An `AGENT` condition's `key` is a config-managed agent name (resolved on apply); every other type uses its `key`/`value` verbatim.

<Note>
  For the full field reference of every kind, see the [Config DSL reference](https://schema.roark.ai/roark-config.schema.json) schema.
</Note>

***

## Deploying

Bundle your resources into a single JSON body and submit it. The body is `{ "resources": [...], "prune": true }`, where each entry is one resource in the same shape as its YAML.

<Steps>
  <Step title="Preview the changes">
    ```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
    curl -X POST https://api.roark.ai/v1/config/plan \
      -H "Authorization: Bearer $ROARK_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @bundle.json
    ```

    The response lists each planned change with an `op` of `create`, `update`, or `delete`, plus a summary:

    ```json theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
    {
      "data": {
        "changes": [
          { "configKey": "collector/consent-on-frontdesk", "kind": "collector", "name": "consent-on-frontdesk", "op": "create" }
        ],
        "summary": { "create": 1, "update": 0, "delete": 0, "noop": 0 }
      }
    }
    ```
  </Step>

  <Step title="Apply">
    Once the plan looks right, run the same body against `apply`:

    ```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
    curl -X POST https://api.roark.ai/v1/config/apply \
      -H "Authorization: Bearer $ROARK_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @bundle.json
    ```

    Each change comes back with a `status` (`applied` or `failed`) and, on success, the resource `id`.
  </Step>
</Steps>

<Note>
  These endpoints are available in the [Node.js](/documentation/sdks/node-sdk) and [Python](/documentation/sdks/python-sdk) SDKs as `config.plan` and `config.apply`, taking the same bundle.
</Note>

***

## Apply semantics

* **Identity is by name.** Re-submitting an unchanged resource updates it in place; it never creates a duplicate. Renaming a resource is a delete of the old name plus a create of the new one.
* **Cross-references resolve by name** within the same submission (a flow's `agents:`/`persona:`, a collector's `AGENT` filter). The referenced resource must be in the bundle or already config-managed in the project.
* **Prune deletes what you removed.** By default, config-managed resources absent from the submission are deleted so the project matches your repo exactly. To layer additive changes without deleting, send `"prune": false`.
* **Prompts are code.** Any prompt field takes an inline string or `file://relative/path.md`, resolved relative to your config root and inlined before you submit.
* **Idempotent.** Applying the same bundle twice converges to the same state.

<Warning>
  With `prune` enabled (the default), a resource you delete from your repo is deleted from Roark on the next apply. Submit the **full** desired set every time, or use `"prune": false` for additive-only applies.
</Warning>

***

## Config-managed resources in the UI

A resource created by config is **read-only in the dashboard** and carries a "managed by config" badge. To change it, edit your config and re-apply.

If you need to hand a resource back to manual UI editing, **detach** it (from the resource's menu in the dashboard). Detaching clears its config ownership:

* A later apply that still lists it will re-adopt it.
* A later apply that omits it will simply leave it alone (it is no longer config-managed, so prune won't touch it).

***

## Recommended workflow

1. Keep your `roark/` config in a git repo, reviewed via pull requests.
2. In CI, run `plan` on every PR and post the diff for review.
3. On merge to your main branch, run `apply`.

This gives you versioned, reviewable, reproducible Roark resources with a full audit trail in git.
