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

# Writing alert templates

> Customize the content and wording of your Coalesce Quality alerts

Alert templates let you control the exact content and wording of the alerts
Coalesce Quality sends so an alert reads the way your team expects.

## Plain text templates

Plain text is the default mode which lets you define a plain text **title** and **body**.
Leave a field empty to use the default for that alert. Use this mode when you want a fixed,
unchanging message, like sending static content to stakeholders.

## Dynamic templates

<Note>
  **Alpha feature.** Customizing alert content with Dynamic templates as
  described here — are currently in Alpha. Contact the
  Coalesce team to have them enabled for your workspace.
</Note>

Dynamic templates use block-based template layout that is interpreted by a Jinja engine.
They allow you more control over the alert content with variables and sections.

### The block model

A template is an **ordered list of blocks**. Each block is a small,
self-contained fragment written in [Jinja](https://jinja.palletsprojects.com/),
and each block renders on its own — a block cannot reference or inherit from
another block. There is no shared base template: `{% extends %}` and
`{% include %}` are **not** supported and will fail to render.

Each alert ships with a **default template** made up of the shared catalog
blocks below. When you save a custom template it **replaces the default
entirely** — so to keep a section you must keep its block, and to remove a
section you simply omit its block.

### Layout sections

A rendered alert is laid out in two sections, and every block belongs to one of
them:

| Section          | When it renders                                                      |
| ---------------- | -------------------------------------------------------------------- |
| **Summary**      | Once per alert — the top-level message.                              |
| **Issue detail** | Repeated for each issue in the alert — the issue card or attachment. |

Catalog blocks have fixed placements per channel, so they land in the right
section automatically. A **custom block** renders in whichever section you
assign it to.

### Catalog blocks

Catalog blocks land in a fixed layout section — you don't place them yourself. The
sections below are the defaults for Ungrouped Issue alerts; Grouped Issue alerts
may repeat a block across both sections.

| Block            | Section      | What it shows                                                                         |
| ---------------- | ------------ | ------------------------------------------------------------------------------------- |
| `headline`       | Summary      | The asset that triggered the alert, linked to the issue, plus its heads and folders.  |
| `products`       | Summary      | Affected and downstream data products.                                                |
| `ownership`      | Summary      | Owners of the asset and downstream owners, tagging them where a handle is configured. |
| `error_message`  | Issue detail | The issue message.                                                                    |
| `asset_metadata` | Issue detail | The most recent code change and schema change on the asset (within the last 30 days). |
| `incident_mgmt`  | Issue detail | Drives the Incident Management tooling. Renders in Slack only.                        |

### Custom blocks

You are not limited to the catalog. Add your own named block with whatever Jinja
content you like; it renders in list order within the layout section you assign
it to.

### Variables and filters

**Variables** carry the alert's data; **filters** (tagged `filter` below) format
a value. Apply a filter with a pipe: `{{ asset.name | bold }}`. Every variable is
optional — a value that isn't available for a given alert renders as empty rather
than erroring, and a filter applied to an empty value renders as empty text.

The following are available on **every** alert:

| Name                    | Description                                                                                                                |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `workspace`             | Workspace identifier.                                                                                                      |
| `alert.id`              | Alert identifier.                                                                                                          |
| `issue.url`             | Link to the issue (or failing run) in Coalesce Quality.                                                                    |
| `issue.message`         | Issue or run message.                                                                                                      |
| `asset.name`            | Asset name (truncated).                                                                                                    |
| `asset.path`            | Fully-qualified asset path.                                                                                                |
| `asset.type_name`       | Human-readable asset type, e.g. `Table`.                                                                                   |
| `asset.url`             | Link to the asset.                                                                                                         |
| `asset.folders`         | List of folder names the asset lives in.                                                                                   |
| `asset.heads`           | List of head assets, each with `name`, `path`, `type_name`, `url`.                                                         |
| `owners`                | Asset owners, each with `id`, `title`, `path`, `mention`.                                                                  |
| `downstream_owners`     | Downstream owners, same fields as `owners`.                                                                                |
| `commit`                | Most recent code change (within 30 days): `short_message`, `author_name`, `mailto`, `url`, `ago`. Empty if none.           |
| `schema_change`         | Most recent schema change (within 30 days): `url`, `ago`. Empty if none.                                                   |
| `bold` `filter`         | Bold text.                                                                                                                 |
| `italic` `filter`       | Italic text.                                                                                                               |
| `link(url)` `filter`    | Render the value as a hyperlink to `url`; an empty `url` degrades to the bare label.                                       |
| `code` `filter`         | Inline / block code. Pass a language, e.g. `code("sql")`.                                                                  |
| `date(layout)` `filter` | Format a timestamp. Accepts a `strftime` string (e.g. `"%Y-%m-%d"`) or a Go layout; defaults to `2006-01-02 15:04:05 UTC`. |
| `join` `filter`         | Join a list into a string (standard Jinja filter).                                                                         |

Filters are **channel-aware**: the same template renders native Slack markup,
HTML email, or MS Teams markup depending on where the alert is sent — you don't
(and can't) branch on the channel yourself. The `mention` field on `owners` and
`downstream_owners` is already formatted for the channel, so print it directly.

#### Ungrouped Issue alerts

Alerts that fire once per issue expose these in addition to the common set:

| Name                       | Description                                                      |
| -------------------------- | ---------------------------------------------------------------- |
| `alert.action`             | `created`, `updated`, `status_updated`, or `closed`.             |
| `alert.action_verb`        | Human-readable action, e.g. `created`, `status updated`.         |
| `issue.id`                 | Issue identifier.                                                |
| `issue.group_id`           | Identifier of the issue group.                                   |
| `issue.title`              | Issue title (truncated).                                         |
| `issue.name`               | Issue name.                                                      |
| `issue.muted`              | Whether the issue is muted.                                      |
| `asset.schema`             | Asset schema, derived from the path.                             |
| `products`                 | Affected data products, each with `id`, `title`, `label`, `url`. |
| `downstream_products`      | Downstream affected data products, same fields as `products`.    |
| `incident_mgmt.set_status` | Whether the Set Status action is available.                      |

#### Grouped Issue alerts

Alerts that group issues by failing entity expose these in addition to the common
set:

| Name                  | Description                                                               |
| --------------------- | ------------------------------------------------------------------------- |
| `failure.message`     | Failure message.                                                          |
| `failure.started_at`  | When the failing run started (a timestamp — pair with the `date` filter). |
| `failure.status_verb` | Human-readable run status, e.g. `failed`.                                 |
| `failure.duration`    | How long the failing run took, pre-formatted (e.g. `3s`).                 |

### Worked examples

#### A stripped-back analyst Slack alert

To give analysts a lean alert, keep the headline, affected products, ownership,
and error message, and drop the asset metadata and incident-management sections.
Because a custom template replaces the default, you achieve this by keeping only
the blocks you want:

| Block           | Section      | Content                                                                                                                                             |
| --------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `headline`      | Summary      | `{{ asset.type_name }} {{ asset.name \| link(issue.url) \| bold }}`                                                                                 |
| `products`      | Summary      | `{% if products %}Affected Products: {% for p in products %}{{ p.label \| link(p.url) }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}` |
| `ownership`     | Summary      | `{% if owners %}Owned by: {% for o in owners %}{{ o.title }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}`                             |
| `error_message` | Issue detail | `{{ issue.message }}`                                                                                                                               |

Omitting `asset_metadata` and `incident_mgmt` removes those sections — and
because `incident_mgmt` is gone, the Slack **Set Status** button is dropped too.

#### A headline that leads with the schema

To surface the schema in the headline, override the `headline` block on a
**per-issue alert**:

```jinja theme={null}
{{ asset.schema }}/{{ asset.name }} {{ alert.action_verb }}
```

For an issue that was just created on `analytics.orders`, this renders as
`analytics/orders created`. (Use this on per-issue alerts — `asset.schema` is not
available on grouped alerts.)

### When a template breaks

Templates are validated as you edit: the **live preview** in the editor renders
your template against a sample alert and shows any parse or render error inline,
so you can fix it before saving.

If a saved template ever fails to render when a real alert fires — for example a
typo introduced later, or a variable used in a way that errors — Coalesce Quality
falls back to the **default template** for that alert and sends it. **Delivery is
never blocked and no partial message is sent.**
