# App YAML

> Top-level structure of an app YAML.

Canonical HTML page: https://conclude.io/doc/reference/yaml/
Last updated: 2026-11-02

---

Top-level structure of an app YAML.

## Skeleton

```yaml
name: ticket            # required, lowercase identifier
label: Support ticket   # required, display name
description: |          # optional, long-form description
  Ticket app for ...
icon: support           # optional, icon name (defaults to "support")

settings:               # optional, operational config
  ...
roles:                  # optional, who can do what
  ...
texts:                  # optional, UI text overrides
  ...

attributes:             # required, ≥1 attribute, must include "title"
  - name: title
    type: string
    label: Subject
    mandatory: true

triggers:               # optional
  - onCreate: [...]
    onComment: [...]
    onEdit: [...]
    onConclude: [...]

scripts:                # optional, named Starlark functions
  - name: route
    source: |
      def onTrigger(activity, conclude, trigger):
          ...

emailConnector: {...}   # optional
webConnector: {...}     # optional
jira: {...}             # optional
zendesk: {...}          # optional
lookup: {...}           # optional

create: {...}           # optional, controls activity creation UX
connect: {...}          # optional, connected-app mode
review: {...}           # optional, review workflow
```

## Top-level fields

| YAML key | Type | Required | Purpose |
|---|---|---|---|
| `name` | string | ✓ | Unique identifier; lowercased on save |
| `label` | string | ✓ | Display name |
| `type` | `channel` \| `global` | — | App scope; defaults to `channel` |
| `description` | string | — | Long description, shown in editor |
| `context` | string | — | Extra contextual metadata (used by agents as system-prompt prefix) |
| `icon` | string | — | Icon name; defaults to `support` |
| `settings` | object | — | See [settings](#settings) |
| `roles` | object | — | See [Macros and roles](https://conclude.io/doc/reference/macros-and-roles/) |
| `texts` | object | — | See [texts](#texts) |
| `create` | object | — | See [create](#create) |
| `connect` | object | — | Connected-app linkage |
| `review` | object | — | See [review](#review) |
| `attributes` | list | ✓ | See [Attributes](https://conclude.io/doc/reference/attributes/) |
| `triggers` | list | — | See [Triggers](https://conclude.io/doc/reference/triggers/) |
| `scripts` | list | — | See [Scripting (Starlark)](https://conclude.io/doc/reference/scripting/) |
| `emailConnector` | object | — | See [Connectors](https://conclude.io/doc/reference/connectors/) |
| `webConnector` | object | — | See [Connectors](https://conclude.io/doc/reference/connectors/) |
| `jira`, `zendesk` | object | — | See [Connectors](https://conclude.io/doc/reference/connectors/) |
| `lookup` | object | — | See [Connectors](https://conclude.io/doc/reference/connectors/) |

## Validation rules

Conclude rejects an app that breaks one of these rules:

- `name` and `label` must be non-empty
- `attributes` must be non-empty
- Attribute `name` must be unique
- An attribute named `title` is mandatory and must have `type: string`
- If an attribute named `conclusion` exists, it must have `type: text`

## Settings

`settings:` holds the app's operational configuration:

| YAML key | Type | Purpose |
|---|---|---|
| `subject` | string | Singular noun for an activity ("ticket", "incident"); used in default UI text |
| `mode` | string | Space-separated flags: `channel` (give each activity its own channel), `silent` (suppress chat notifications) |
| `channelName` | string | Template for per-activity channel names (supports macros). Example: `_${__channel}_${jira.id}` |
| `notifications` | string | `default` or a comma list (e.g. `deadline,severity`) — which lifecycle events post to chat |
| `alert` | string | Role expression for channels/users to notify on every activity event |
| `errorLog` | string | Channel for system error messages from this app |
| `rateLimit` | string | `N/min` format; default 10/min for inbound connector traffic |
| `disableDeadline` | bool | Hides the built-in `deadline` attribute |

Examples:

```yaml
settings:
  subject: incident
  mode: channel               # each incident gets its own channel
  channelName: inc-${title}
  alert: ${__channel} ${initiator}
  notifications: deadline,severity
  rateLimit: 30/min
```

## Texts

`texts:` overrides UI text. Set only the keys
you want to change; everything else falls back to defaults that read
naturally for the `settings.subject` you set.

Keys (all string, optional):
`launchButton`, `ownerLabel`, `unassignedLabel`, `unassignedAvatar`,
`initiatorSummary`, `closedBySummary`,
`createCaption`, `editCaption`, `concludeCaption`,
`createIntro`, `editIntro`, `concludeIntro`,
`createButton`, `editButton`, `concludeButton`,
`externalUser`, `externalAvatar`.

Example:

```yaml
texts:
  createCaption: Report a new bug
  createButton: File bug
  concludeCaption: Close this bug
```

## Create

`create:` controls how a user opens a new
activity from chat.

| YAML key | Type | Purpose |
|---|---|---|
| `reaction` | string | Emoji shortcut(s) that open the create form, comma-separated. Default: 🎫 |
| `userInput` | bool | If true, show the form before creating; otherwise create immediately |
| `threadHistory` | `partial` \| `full` | How much of a thread a reaction copies into the activity. Default: `partial` |

```yaml
create:
  reaction: ":bug:,:beetle:"
  userInput: true
  threadHistory: full
```

`threadHistory: partial` starts at the reacted message and skips everything before
it in the thread. `full` copies the whole thread, starting at the parent message,
no matter which reply carries the reaction. Either mode copies at most 100
messages. An unknown value is rejected when the app is saved.

Either way the copy keeps posts by other apps' bots, matching what gets recorded
when the messages arrive live. Everything posted through Conclude is skipped:
banners and cards, agent posts, and messages Conclude relayed on behalf of a user
in a bridged or connected channel.

## Review

`review:` gates activities behind a review step.

| YAML key | Type | Purpose |
|---|---|---|
| `members` | string | Role expression for reviewers |
| `alert` | string | Channel/users alerted when a pending review arrives |
| `ignore` | string | Skip review for matching initiators (e.g. `internal`) |
| `include` | string | Force review for matching initiators (e.g. `external`) |
| `createChannel` | bool | Create a dedicated review channel per pending activity |

## Connect

`connect:` is for cross-org connected apps. Most apps don't set this.

