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

# Best Practices

> Guidelines for getting the most out of Roark simulations

## Customer flows

### Improv vs. Scripted

The single biggest decision in a [customer flow](/documentation/simulation-testing/customer-flows) is the authoring mode, and it maps directly to what you're testing.

**Improv** — You write a free-text brief describing who the customer is, what they want, and how they behave. The simulator improvises a fresh conversation from that brief on every run — different words, same intent:

```
A first-time caller wants to book an appointment for tomorrow around 2pm.
They're friendly but a little unsure of the process and will ask what
information they need to provide.
```

Improv is the default choice for most testing. Because the wording changes each run, it exercises your agent's ability to handle natural language variation for the same intent — the thing that actually breaks in production.

**Scripted** — You author the conversation step by step on a graph canvas, writing the exact customer lines:

```
"Hello, can I make a booking for tomorrow at 2pm?"
```

Scripted mode is for precise control: verifying your agent parses a specific date format, detects a keyword, handles a DTMF sequence, or recovers from a deliberate silence.

<Tip>
  Use **Scripted** when the exact utterance matters — phrasing, keyword detection, slot filling, keypad input. Use **Improv** when you want varied, realistic conversations that test the same intent from a different angle every run.
</Tip>

### Write improv briefs like backstories

The customer setup brief is where the simulated customer comes to life. Behavioral color — emotional state, context, quirks — belongs in this prose, not in the persona (personas carry voice and speech characteristics; the brief carries the situation).

Good briefs give the simulator context that drives nuanced, realistic behavior:

**Bereaved customer**

```
James recently lost his wife and is calling to cancel her phone line on
their shared plan. He is soft-spoken and may become emotional. He doesn't
fully understand the account details and may need things explained gently.
```

**Skeptical professional**

```
Priya is a software engineer who immediately suspects she's talking to an
AI. She will ask pointed questions like "Are you a real person?" and "Can
you transfer me to a human?" She becomes frustrated if the agent can't
directly answer her questions about a billing discrepancy.
```

**Impatient multitasker**

```
Carlos is calling during a short break at work. He has 5 minutes. He'll
give short answers, may mishear things, and will ask the agent to repeat
or speak up. He needs to reschedule a delivery that requires a signature.
```

### Structure scripted flows around paths

Scripted flows are **graph-based** — a DAG of agent and customer steps. Every unique path from start to leaf becomes its own variant automatically: the path engine derives one variant per path, so structuring the graph well is how you get coverage without duplication.

#### Start with a happy path

Begin with a single expected route — the happy path where everything goes as planned:

```mermaid theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
graph LR
    C1["👤 Customer calls in"] --> A1["🤖 Greets and\n asks how to help"]
    A1 --> C2["👤 Asks to book\n an appointment"]
    C2 --> A2["🤖 Asks for\n preferred date"]
    A2 --> C3["👤 Provides\n a date"]
    C3 --> A3["🤖 Confirms\n and books"]
```

#### Add branches for edge cases

Once your happy path works, branch at points where the conversation can diverge. Branches inherit everything above them, and each new path shows up as an edge case in the variant rail:

```mermaid theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
graph TD
    C1["👤 Customer calls in"] --> A1["🤖 Greets and asks how to help"]
    A1 --> C2["👤 Asks to book an appointment"]
    C2 --> A2["🤖 Asks for preferred date"]
    A2 --> C3["👤 Provides a date"]
    A2 --> C3b["👤 Asks what's available"]
    C3 --> A3["🤖 Confirms and books"]
    C3b --> A3b["🤖 Lists available slots"]
    A3b --> C4["👤 Picks a slot"]
    C4 --> A4["🤖 Confirms and books"]
```

Focus your branching where:

* The agent asks the customer a question (customers respond in unexpected ways)
* The agent could go on a tangent or lose track of the conversation
* Tool calls or lookups might fail or return unexpected results

If you want the *same* path exercised by a different caller, don't duplicate the branch — use **Add variant for path** to run that path again with a different persona or environment.

<Note>
  Structural graph edits (adding or removing steps and edges) pause variant editing until you save — the flow needs to refresh its paths before you can add or remove variants.
</Note>

#### Compose flows instead of duplicating them

Two composition tools keep shared sequences in one place:

* **Flow link** (scripted step) — splices another scripted flow's steps in at that point. Keep a shared IVR tree or authentication sequence in its own flow and link to it; when the menu changes, you update it once.
* **Preceded by** (improv variant) — runs a scripted flow *before* the improv segment. Use it to deterministically navigate an IVR menu, then hand off to an improvised conversation. Improv has no fixed ending, so it can only come last — you can't link a scripted flow after it.

### Templating with variables

Variants carry key/value **variables** that are handed to the customer-side model, and text fields support `{{variableName}}` references:

```
"Hi, my name is {{patientName}} and I need to reschedule
my {{appointmentType}} appointment"
```

Persona-scoped properties use the `{{persona.*}}` prefix and resolve from the variant's persona at runtime:

```
"Hi, my name is {{persona.name}}"
```

This keeps a single flow reusable across many test cases, with only the key details changing between runs. You can also use **Apply a test profile** in the variant's variables editor to fill the entries from a saved profile in one click. See the [Variables guide](/documentation/simulation-testing/variables) for the full lifecycle.

### Generate flows with Ask Roark

You don't have to author flows from scratch. The **New flow** page (`/customer-flows/new`) offers three Ask Roark starting points under "Generate":

1. **From your calls** — pick real production calls and let Ask Roark draft flows from them. This is the fastest route to representative coverage: the drafts reflect how customers actually talk to your agent.
2. **From a transcript** — upload or paste a transcript from any source (another platform, a QA review, a bug report) and generate a flow from it.
3. **Describe what you want** — describe the situation in plain language and Ask Roark drafts the flow for you.

Whichever card you start from, treat the draft as a baseline: review the generated brief or steps, then extend it with edge cases covering paths that didn't occur in the source material but could happen in production. Generated variants carry a **Generated** badge until you review them.

***

## Personas

[Personas](/documentation/simulation-testing/personas) model *who is calling* — the voice and speech profile pinned to each flow variant. A good persona strategy tests your agent across a range of realistic caller profiles.

### Diversify voice and speech

Build a set of personas that vary:

* **Language and accent** — battle-test your transcriber's accuracy across accents (US, British, Indian, Spanish, and more) and languages
* **Speech pace and response timing** — slow, rambling talkers and quick, clipped ones ensure your agent neither interrupts customers nor times out waiting for them
* **Clarity and disfluencies** — vague or rambling callers with natural ums and false starts stress your agent's understanding far more than clean studio speech

<Note>
  Background noise is no longer a persona property — it's the variant's **Environment** chip in the flow editor (Office, Coffee shop, Driving, Airport, and more). Vary it per variant to verify your endpointing holds up in non-ideal audio.
</Note>

### Test difficult customer types

Combine persona fields (base emotion, clarity) with a matching customer setup brief to build challenging callers:

<CardGroup cols={2}>
  <Card title="AI Skeptic" icon="bot">
    Base emotion **Skeptical**, plus a brief where the customer tests the agent with trick questions and asks for a human
  </Card>

  <Card title="Hostile Caller" icon="angry">
    Base emotion **Frustrated**, plus a brief with a rude, escalating customer — verify your agent stays polite and professional
  </Card>

  <Card title="Sensitive Situation" icon="heart">
    A brief describing a customer in a difficult moment (bereavement, financial hardship) — ensure your agent is empathetic and considerate
  </Card>

  <Card title="Rapid Switcher" icon="shuffle">
    Base emotion **Distracted**, clarity **Rambling**, plus a brief where the customer changes topics frequently
  </Card>
</CardGroup>

The persona sets the delivery; the variant's customer setup prose sets the situation and behavior. Keeping them separate means one "Frustrated rambler" persona can stress-test every flow in your library.

***

## Plan configuration

A plan composes agent endpoints, attached flows (with a variant selection per attachment), metrics with Pass/Fail checks, and run settings. How you configure it depends on what you're testing.

### Common patterns

<AccordionGroup>
  <Accordion title="Load testing">
    Use the **Load testing** template rather than configuring this by hand. Its **Volume** panel exposes exactly the two knobs you need — **Concurrent calls** and **Total iterations** — plus the flow to test.

    * Pick a flow whose happy path matches your target call duration
    * Set total iterations to your target volume and concurrent calls to how many should hit the agent simultaneously

    This reveals how your agent performs under peak load without over-provisioning your regular test plans.
  </Accordion>

  <Accordion title="Adaptability across personas">
    Test how your agent handles different voices, accents, and speech styles on the same conversation.

    * Attach a **single flow** with the **default variant** selection (your happy path)
    * Attach it multiple times with a different **persona override** per attachment, covering a wide spread of accents, paces, and base emotions

    This isolates persona-driven variation from flow complexity, making it easy to spot which caller profiles cause problems. For language coverage specifically, the **Multilingual** template does the fan-out for you — each attached flow runs once per selected language.
  </Accordion>

  <Accordion title="Instruction following">
    Agents are non-deterministic — verify they don't go off-script or hit loopholes.

    * Build flows with **multiple edge cases**: scripted branches for the paths you can enumerate, improv edge cases for the ones you can't
    * Write **agent expectations** for the behaviors that must hold on every variant, and additional expectations per edge case
    * Focus edge cases on points where the agent might go on a tangent or fail to recover

    The **Flow adherence** template ships with metrics and checks tuned for exactly this.
  </Accordion>

  <Accordion title="Red teaming">
    Use the **Red teaming** template to test resilience against adversarial inputs. It sources flows carrying the **Adversarial** label from your library, or generates 3–10 adversarial edge cases for you at easy, medium, or hard difficulty — covering prompt injection attempts, PII extraction, and social engineering.

    Label your own hand-authored adversarial flows with the Adversarial system label so the template picks them up automatically.
  </Accordion>
</AccordionGroup>

See [Templates](/documentation/simulation-testing/templates) for the full catalogue and what each one preconfigures.

### Keeping simulations under control

| Setting              | Default                | Recommendation                                                                                                                                                  |
| :------------------- | :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Max duration**     | 15 minutes (up to 24h) | Set to \~110% of your average call duration. Prevents runaway calls if the agent goes on a tangent.                                                             |
| **Silence timeout**  | 30 seconds (5–300s)    | Ends calls after sustained silence, catching cases where either side stops responding.                                                                          |
| **End-call phrases** | `goodbye` (max 10)     | Specific phrases that end the simulation immediately when matched. Add phrases that signal a call has gone off track.                                           |
| **End-call reasons** | none (max 10)          | When you can't pin down exact phrases, describe the condition instead — an LLM evaluates each turn and ends the call when the reason is met.                    |
| **Iterations**       | 1 (max 100)            | Runs per test case. Fixed at 1 for outbound runs.                                                                                                               |
| **Concurrency**      | 5                      | Keep at the default or below for regular runs to avoid unnecessary load on your agent and manage costs. Reserve high concurrency for the Load testing template. |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Customer Flows" icon="book-open" href="/documentation/simulation-testing/customer-flows">
    Author improv briefs and scripted graphs
  </Card>

  <Card title="Personas" icon="users" href="/documentation/simulation-testing/personas">
    Create diverse caller profiles
  </Card>

  <Card title="Templates" icon="layout-template" href="/documentation/simulation-testing/templates">
    Start from a goal with preconfigured plans
  </Card>

  <Card title="Run Plans" icon="list-checks" href="/documentation/simulation-testing/run-plans">
    Configure and execute simulation plans
  </Card>
</CardGroup>
