Coach conversations¶
A coach conversation is a scripted chat the Coach plays in the Coach tab. It's an ordered list of chat items — messages, reply choices, and cards that launch sessions, sounds, or actions. This is the most structured content type, so this page is the longest.
Follow The authoring model for parent/translations, status, slugs, and validation.

Parent fields¶
| Field | What it means |
|---|---|
| Slug | Stable id, e.g. welcome, morning_default. |
| Opening module | Optional coach module spliced in at the start (e.g. a greeting). |
| Closing module | Optional coach module spliced in at the end (e.g. an optional check-in prompt). |
Translation fields¶
| Field | What it means |
|---|---|
| Items | The ordered chat script — a list of items, each with a type. This is the bulk of the work; the item types are below. |
| Push copy | A short notification line associated with the conversation. (Currently not used at send time — push bodies live in the Coach Schedule — but the field is still authored.) |
The item types¶
Each item in Items has a type that decides what it renders as. Items you
don't recognise are ignored by the app, but the save-time check
(coach-content-validate) will reject malformed known items.
Messages¶
received_bubble— a message from the Coach. Fields:text(and an optionalleading_spacefor extra spacing above).sent_bubble— a message shown as if from the user. Field:text.
Letting the user choose: reply chips + branching¶
reply_chip_row— a row of tappable reply chips. Needs anidand a list ofchips, each with alabeland either a navigationtargetor anaction(see actions below). A chip can carry atag(a short keyword stored when the user taps it) andis_last_step.tag_match— conditional branching. It has asource(theidof an earlierreply_chip_row) andbranches— a map from the chip'stagto a sub-list of items. The Coach plays the branch matching what the user picked. Thesourcemust reference a reply_chip_row that appears earlier in the same list — the save check enforces this so a branch can't dangle.
Cards that launch content¶
These are the cards that connect a conversation to the rest of the app.
session_card — launch a Library session¶
Always needs session_id (the session's template kind, e.g. audioGuided).
Then one of two forms:
- Reference form (preferred) — supply
session_slugand omit the title. The app pulls the title, image, and duration from the session itself, so the card always matches the live session. Author this whenever the card points at a real session. - Literal form — supply an authored
title(and optionallyduration). Use this only when there's no backing session row to resolve from.
The save check verifies the session_slug resolves to a real session. A card
with neither a title nor a slug is rejected.
sound_card — launch a sound or album¶
Needs ref_kind and ref:
- Album:
ref_kind: album,ref= the album slug (e.g.ocean). Renders as the album with an "N sounds" count. - Track:
ref_kind: track,ref= the track's id. Renders as the single track with its duration.
The save check verifies the album slug / track exists and is published. (There's
no "literal" sound card — for a plain promo, use a teaser_card with a
navigate:/sounds/... link instead.)
teaser_card — a promo / call-to-action¶
A visual card with a title, subtitle, and an icon, plus exactly one of:
- a navigation
target(a route), or - an
action(see actions below).
Icons (pick from this set): self_improvement, air, headphones,
lightbulb_outline, nightlight_round, psychology, insights_outlined.
The first check-in card is a teaser_card with action: check-in:open. That
action opens the check-in sheet in place, and the card automatically shows a
"Done" badge and stops responding to taps once the user has completed a
check-in (by any route). Use icon: insights_outlined (the Progress icon) for it.
Structural items¶
day_divider— a labelled divider (e.g. "Day 1").week_strip— the week indicator strip.collapsed_days_link— a "show earlier days" link with atarget.
Actions and navigation targets (closed sets)¶
Where an item takes an action, the allowed values are:
complete— marks the step/conversation complete.noop— does nothing (placeholder).check-in:open— opens the check-in sheet (the first-check-in CTA).navigate:<route>— navigates to a route (see below).
Where an item takes a navigation route (target, or inside
navigate:<route>), it must be one of the known routes — the save check
rejects anything else, so a typo can't ship a dead link:
- Tab roots:
/coach,/library,/sounds,/progress,/profile - Progress detail:
/progress/detail/{sleep,feeling,awareness,activity} - Profile sub-pages:
/profile/{notifications,appearance,account,privacy,about} - A session:
/sessions/<template-kind> - A sound album:
/sounds/album/<album-slug>(album must exist) - A single track:
/sounds/track/<track-id> - A Library category:
/library/<category>
What blocks a save¶
- A
session_cardwhosesession_slugdoesn't resolve to a real session. - A
sound_cardwhose album slug / track doesn't exist or isn't published. - A
teaser_card/chip with anavigate:route outside the known set. - A
teaser_cardwith both (or neither)targetandaction. - A
tag_matchwhosesourcedoesn't match an earlierreply_chip_rowid. - Any malformed item (missing required fields for its type).
Where it shows up¶
The Coach tab plays the conversation top to bottom: messages appear, reply chips wait for a tap, branches resolve from the user's earlier choices, and cards render as tappable tiles that launch the session/sound or run the action. The opening/closing modules are spliced in around the items, and the schedule decides which conversation plays when.
See also¶
- Field-by-field reference: received_bubble, session_card, reply_chip_row, tag_match in the content-block reference
- Flow rules: Composition & sequence rules