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

# Simulation groups

> Run several simulation plans together and send one combined report to email and Slack

A simulation group is a saved set of [simulation plans](/documentation/config-as-code/simulation-plans) that run together. Every time the group runs, each plan starts once and Roark reads the runs as one: a single **group report** covering what went well, the issues found across every run (with call-level evidence) and recommendations, delivered as a PDF to whoever you choose.

Use a group when one release review spans several plans, for example a missions suite, a stress suite and a voice sweep, and the people reading the result want one report rather than three.

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
# yaml-language-server: $schema=https://roark.ai/roark-config.schema.json
kind: simulationGroup
name: weekly-release-review
description: Every plan the pickup agent has to pass before a release
plans:
  - mission-1-pickup-lifecycle      # a kind: simulationPlan in this config
  - Mission 2 address change        # or a plan made in the dashboard, by its exact name
  - conversational-stress
schedule:
  type: weekly
  days: [monday]
  time: '09:00'
  timezone: America/New_York
notify:
  email:
    - qa-lead@example.com
    - vp-operations@example.com     # does not need a Roark account
  slack:
    - channelId: C0123ABCXYZ
      channelName: '#voice-qa'
```

<Note>
  **Applying a group never starts a run.** It declares the group. A group runs when its [`schedule`](#running-on-a-schedule) fires, when someone presses **Run now** on it in the dashboard, or when you start it [from the CLI or API](#running-a-group-on-demand).
</Note>

***

## Fields

| Field | Required | |
| :- | :- | :- |
| `name` | yes | The group's config name, and also its name in the dashboard |
| `description` | no | Free text. Removing it clears it. |
| `plans` | yes | 2 to 20 plan names, in the order they run and appear in the report. Each plan once. |
| `schedule` | no | Run the group on a cadence. The same block as a [plan's schedule](/documentation/config-as-code/simulation-plans#running-on-a-schedule). |
| `notify` | no | Where the report goes. Omitted: email every member of the project, no Slack. |

***

## Which plans run

Each entry in `plans` resolves by name, in this order:

1. A `kind: simulationPlan` in the same bundle, or one config already manages.
2. A plan made in the dashboard with exactly that name. Write it as it appears in Roark, spaces and capitals included.

A name that matches no plan, or more than one, fails that group's apply with the plan named, so a group never quietly runs a different plan than the one you meant.

A plan can belong to several groups. While a group in your config still lists a plan, pruning won't delete that plan: apply keeps it and reports which group needs it. If a plan in a group is deleted from the dashboard, the group's next run fails before starting anything, naming the missing plan. It never runs a partial set.

***

## Running on a schedule

`schedule` takes exactly the same block as a plan's: `hourly`, `interval`, `daily`, `weekly`, `monthly` or `once`, with `timezone`, `enabled`, `endDate` and `maxRuns`. See [Running on a schedule](/documentation/config-as-code/simulation-plans#running-on-a-schedule) for every field.

The ownership rules match too: declaring `schedule` puts the group's schedule under config, removing the block deletes it, and `enabled: false` pauses it without deleting it.

Each fire is attempted once. Plans start one after another and a started run can't be taken back, so a retry could start some plans twice. If a plan can't start, the plans that did start are still grouped and reported on, and the fire is recorded as failed.

<Warning>
  A group run places real, billed calls for **every** plan in it. Check the combined size of your plans before choosing a cadence, or set `maxRuns` while you trial a new group.
</Warning>

<Note>
  A scheduled run can't prompt for a variable, so every variable the group's plans use needs a default. See [Variables](/documentation/simulation-testing/variables).
</Note>

***

## Who gets the report

When every run in the group has finished, Roark writes the group report and announces it. The report PDF goes with every announcement, so a reader who never logs in to Roark still gets the whole report.

### Email

| `notify.email` | Who is emailed |
| :- | :- |
| `true` (default) | Every member of the project |
| `false` | Nobody. The report is still on the group's page in the dashboard. |
| A list of addresses (1 to 50) | Exactly those people, whether or not they have a Roark account |

Each email carries the verdict, a link to the report in Roark, and the full report attached as a PDF. A list is the way to send the report straight to executives or stakeholders outside your Roark project.

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
notify:
  email: [cto@example.com, head-of-cx@example.com]
```

An empty list (`email: []`) is rejected rather than read as "nobody" or "everyone". Write `false` or `true`.

### Slack

`notify.slack` takes up to 10 channels, in the same `{ channelId, channelName }` shape an [alert](/documentation/config-as-code/alerts) uses. Each channel gets a summary message (the verdict, runs passed, calls, issue count and the top three issues, with a **Read the report** button), and the report PDF is posted in that message's thread.

```yaml theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
notify:
  email: false
  slack:
    - channelId: C0123ABCXYZ
      channelName: '#exec-updates'
    - channelId: C0456DEFUVW
      channelName: '#voice-qa'
```

<Steps>
  <Step title="Connect Slack to the project">
    Slack is connected once, in the dashboard, under **Settings → Project → Notifications**. Connecting is an approval in Slack itself, so it can't be done from config. A group that names a Slack channel fails to apply until the project has a Slack connection.
  </Step>

  <Step title="Find each channel's id">
    In Slack, open the channel, click its name, and copy the **Channel ID** at the bottom of the **About** tab (it looks like `C0123ABCXYZ`). The id is what identifies the channel; `channelName` is only the label you'll see in Roark.
  </Step>

  <Step title="Invite Roark to private channels">
    Roark joins public channels on its own. For a private channel, add the Roark app to it first: open the channel's details, then **Integrations → Add apps**.
  </Step>
</Steps>

<Note>
  Posting the PDF needs Slack's file upload permission, which older Slack connections don't have. On those, the summary message still arrives but without the PDF. Reconnect Slack under **Settings → Project → Notifications** to grant it.
</Note>

### When settings change

Each run copies the group's notification settings when it starts. Changing `notify` and re-applying affects the next run, never a report that's already being written.

Like every other field, deleting the `notify` block (or one of its lines) reverts it to the default: email every project member, no Slack.

***

## Running a group on demand

Applying never starts a run, so a one-off run is its own step. From the CLI, using the group's id (from `roark simulation group list`):

```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
roark config apply ./roark
roark simulation group run <group-id>
```

The command returns the **run group**: the runs it started and, under `latestReport`, the report's progress. The report waits for every run to finish. Poll it until `latestReport.status` is `READY` (or `FAILED`):

```bash theme={"theme":{"light":"everforest-light","dark":"everforest-dark"}}
roark simulation run-group get <run-group-id>
```

The same operations are in the API (`POST /v1/simulation/group/{groupId}/run`, then `GET /v1/simulation/run-group/{runGroupId}`) and in the [Node.js](/documentation/sdks/node-sdk) and [Python](/documentation/sdks/python-sdk) SDKs. A run started this way announces its report through `notify` exactly as a scheduled run does.

***

## In the dashboard

Saved groups are listed under **Simulations → Runs → Groups**, above the history of group runs. Each row shows the group's schedule and where its report goes, and has **Run now**. Each group run opens a page with the combined report and a PDF download.

A group created by config shows **Managed by config**. You can still run it from the dashboard, but its plans and its **Report delivery** settings are read-only there: change them in your config and re-apply.

A group made in the dashboard with the same name as a `kind: simulationGroup` is adopted on the first apply rather than duplicated, as long as exactly one unmanaged group has that name.

***

## Removing a group

Deleting a group from your config (with prune on, the default) deletes the group and its schedule. The group runs and reports it already produced stay, so past reports remain readable.

***

## Apply order

A group lists plans by name, so one apply resolves it after the plans and before the alerts:

```
metric → persona → httpRequestDefinition → agent → tool → flow → collector → simulationPlan → simulationGroup → alert
```

Deletes run in reverse, so a pruned group is removed before any plan it listed.

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


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