# say

The `say` step type speaks a message aloud using text-to-speech (TTS) — an audible cue, like [`alert`](/steps/type/alert), for when a long-running custom command or workflow finishes or needs attention, but with a spoken message instead of just a bell. It detects an available speech engine per OS and degrades gracefully (printing the message) when none is available or when running in CI.

```yaml
steps:
  - name: notify
    type: say
    content: Deployment to {{ .steps.env.value }} is complete
    voice: [Samantha, Zira, en-us]   # cross-platform stack; first installed wins
    rate: normal                      # slow | normal | fast
    print: fallback                   # fallback (default) | always | never
```

`say` works across platforms by detecting an available speech engine: the built-in `say` command on macOS, `spd-say` or `espeak`/`espeak-ng` on Linux, and PowerShell's `System.Speech` on Windows. When no engine is available — or when running in CI or another headless environment — it follows the `print` policy (by default, printing the message as a Markdown blockquote so the information is never lost).

## Fields

- **`content`** — The message to speak. Supports templates.
- **`voice`** — An ordered list of candidate voices. Like a CSS `font-family` stack, the first voice actually installed on the host is used; if none match, the engine's default voice is used. Voice names are platform-specific (macOS uses human names like `Samantha`; Windows uses names like `Zira`/`David`; espeak uses language codes like `en-us`), so a portable stack mixes them — e.g. `[Samantha, Zira, en-us]` resolves to Samantha on macOS, Zira on Windows, and `en-us` on Linux.
- **`rate`** — Speech rate: `slow`, `normal` (default), or `fast`. Mapped to each engine's native scale.
- **`print`** — How the message is shown in addition to (or instead of) speaking:
  - `fallback` (default) — speak when possible; otherwise print the message as a Markdown blockquote.
  - `always` — always print the blockquote _and_ also speak when possible.
  - `never` — speak when possible; otherwise stay silent (no printed output).

Use `say` at the end of long-running workflows for an audible cue when you've switched to another window. In CI it skips speech and follows the `print` policy (default `fallback` prints the message).
