← Design HQ · HTML on GitHub · PRD — prd-as-on-brand-support.md
On-Brand Support — Discover through Live, then the guest WhatsApp thread.
The full-flow design contract for On-Brand Support, in the locked 8-section shape (design-canon.md § “Assistant-flow mockup structure”, 2026-08-06): Design overview · Scope · Content structure · User journey · Desktop screens · Mobile screens · Components · Future design. Companion to the master build contract: assistant-flows/assistant-lifecycle.html.
19 frames · card → live → monitored · mobile + desktop Brain Check — Connect-only, category-grouped · confirmation copy contract tab order Overview → Personalize → Connect → Try (T1155) pre: Overview → Personalize → Connect → Try · post: Pulse → Overview → Personalize → Connect (R30) amber = action/pending only · emerald = live onlyWidths here sample a fluid continuum — content
scales continuously; structure steps only at sm 640 · md 768 · lg 1024. Kit:
design-canon.md U8.
Every $ figure drawn in these frames ($0.50 per session, wallet balances, MTD totals) is illustrative — prices arrive from props/the DB at runtime, never authored literals (single-source pricing).
Reading order: § Desktop screens first — every desktop frame, full flow, in journey order — then § Mobile screens below it — every mobile/sheet frame, same journey order, laid out side by side as a wrapping grid, grouped per phase (never a tall single-file column of screens). Two sections, never interleaved — a review-document convention only; 375 is still designed and scored FIRST in real work (U8 above still holds).
On-Brand Support answers guest DMs on the
founder's WhatsApp, in the founder's confirmed voice, 24/7 — without the founder typing a word. It
reads the Brain (prices, policies, hours, FAQs, brand voice), answers routine questions in seconds,
and hands anything it can't ground — refunds, complaints, the uncertain — to the founder on Slack,
pausing itself for that conversation until the founder is done. Six phases, one direction: a
founder discovers it in Explore, evaluates what it does, activates it (Personalize → Connect →
Try), a guest's WhatsApp message gets answered or escalated, the founder monitors it in Pulse, and
later reactivates it. This file is the per-assistant exemplar of the master contract
(assistant-flows/assistant-lifecycle.html) and draws the shipped chat golden path.
brain_manifest, D1 confirmation
copy contract) lives there alone. Personalize carries a one-line pointer only; Try reads back a
single readiness line. Neither owns a second checklist.pending_template_approval / template_rejected outcomes never apply
and are deliberately not drawn.#done resume — frames 7/8/9.BYOK_AI_HIDDEN (AUTO-only
launch); the AI Model row is label + “MystFlo AI” badge, Connected, no caret.#done instant
resume left this list — shipped in #2616, 2026-07-22; the 5-min sweep stays as the
safety net.)
TMPL-9P3X (prod row — single source)
├─ catalog copy description · details.tldr · long_description · details.benefits[4]
│ (drawn verbatim on frames 1 / 2 / 2b / 9c — R28: pre = post, byte-identical)
├─ price_per_run $0.50 per session — plain text, never a pill (R27), DB-sourced
├─ handling rules 3 groups, T1209-seeded: Answer on its own · Route to you · Politely decline
│ (route-to-you feeds the deterministic escalation detector — AC-TS-20)
├─ Brain Check 7 required fields, grouped by playbook chapter (PR #3725 / AC-BRAINGATE-09):
│ Your business · Where to find you · What you sell · Questions and policies · Branding · How you run
│ per-row ✓ / ○ / ⚠ · rollup “N of M ready” · confirmation copy contract (D1)
└─ session states AI-answered → escalated (AI paused, Slack thread) → human mode → resumed (#done)
one billable unit per closed session (AC-BILL-01/02/03)
Five founder phases (Discover → Evaluate → Activate → Monitor → Maintain) with the customer's own loop (Trigger → Interact → Outcome) embedded at the point it actually happens — right after Activate, before the founder ever opens Pulse. Interact forks: the AI answers directly from the Brain in the common case, or escalates to the founder via Slack when it can't confidently answer (chat-assistant-standard's 3-tier escalation model). Every frame below sits in one of these six phases.
┌ FOUNDER · DISCOVER ────────────────────────────────────────────────────┐
│ Finds On-Brand Support in Explore — sees price, required apps, │
│ and what it promises, before tapping in. │
└────────────────────────────────────────────────────────────────────────┘
▼
┌ FOUNDER · EVALUATE ────────────────────────────────────────────────────┐
│ Opens the detail sheet — what it does, how it works, key │
│ benefits — decides it's worth setting up. │
└────────────────────────────────────────────────────────────────────────┘
▼
┌ FOUNDER · ACTIVATE ────────────────────────────────────────────────────┐
│ Personalize (handling rules + live preview) → Connect (WhatsApp, │
│ AI, Slack, Brain Check) → Try (honest, no fake test) → │
│ Activating (loader) → live, or the whole thing rolled back. │
└────────────────────────────────────────────────────────────────────────┘
▼
┌ CUSTOMER · TRIGGER → INTERACT ─────────────────────────────────────────┐
│ A guest messages the WhatsApp number, any hour — 11pm included. │
└────────────────────────────────────┬───────────────────────────────────┘
▼
┌───────────────────────┴─────────────────────┐
▼ ▼
AI-ANSWERED (common) ESCALATED
Grounded in the Brain, Refund / complaint /
replies in the founder's can't-ground → Slack
confirmed voice. thread, AI paused.
│ │
└───────────────────────┬─────────────────────┘
▼
┌ CUSTOMER · OUTCOME ────────────────────────────────────────────────────┐
│ Guest helped, in the founder's voice — by AI alone or AI + founder. │
└────────────────────────────────────────────────────────────────────────┘
▼
┌ FOUNDER · MONITOR ─────────────────────────────────────────────────────┐
│ Pulse card + activity feed — sessions, cost, health at a glance, │
│ and anything escalated that still needs a reply. │
└────────────────────────────────────────────────────────────────────────┘
▼
┌ FOUNDER · MAINTAIN ────────────────────────────────────────────────────┐
│ Paused later → reactivate (same setup, same WhatsApp number) or │
│ start fresh — nothing already running is ever lost. │
└────────────────────────────────────────────────────────────────────────┘
prd-as-on-brand-support.md §T1097 — 7-field gate, AC-GATE-01/AC-GATE-02).The frames below are the current build contract — the
dev team matches them pixel for pixel; only current / being-built state lives here. Deferred
ideas live under Part II · Future at the bottom — never a
build target (kit canon U9). Acceptance ids cited in frame notes (AC-* ↗) live in
docs/product/assistants/shared/prd-as-on-brand-support.md §Test Plan — this artifact
cites ACs, never mints them, except where noted NEW (PRD debt) for behavior this
reorg found with no existing criterion, or a freshly-added row (dated) where the gap was simple
enough to file in the same pass.
prd-as-on-brand-support.md.description verbatim from the prod row; required apps WhatsApp Business + MystFlo AI + Slack (escalation channel); fixed-zone card skeleton.ShareSheetModal.+N doorway into Connect (frame 4). Readiness signal only, never a cost signal.On-Brand Support reads your Brain — your prices, policies, hours, FAQs, and brand voice — and answers guest questions in WhatsApp in the voice you confirmed. Routine questions get answered in seconds. Anything it can't ground in your knowledge gets handed to you on Slack.
HowItWorksFlow.tsx chart (assistant-lifecycle.html sec-3 desktop, PR #1184) rather than a bespoke rail..fs-drop + .fs-branch) — never its own 5th node/column.On-Brand Support reads your Brain — your prices, policies, hours, FAQs, and brand voice — and answers guest questions in WhatsApp in the voice you confirmed. Routine questions get answered in seconds. Anything it can't ground in your knowledge gets handed to you on Slack.
prd-as-on-brand-support.md §Test Plan.When it can't answer, it hands the thread to you — you're never out of the loop.
Full Brain readiness — what's confirmed, what still needs you — lives on Connect →.
prd-pl-voice-card.md is NOT retired; its surface (a) needs re-homing (see rollout plan).assistants row yet, so the per-assistant read (template-languages?assistant_id=) cannot run and no template of this assistant exists in any language — the row lists the ACCOUNT's languages as facts with no Approved/Pending word (languages[] where included || purchased, from the plain account read) and says they are sent to Meta at activation (activation submits every purchased sibling alongside the English set). POST-activation (9d / 9d-m): the row reads template-languages?assistant_id=<this assistant> and renders each language's own state word — approved → “approved”, pending → “pending”; available (not bought) is omitted. Never the account aggregate. Final copy for both lines: Chief Writer. Edit → slides the WhatsApp connection detail in as the real page (connects.html #f6b ↗) — the ONE home; this tab never shows a picker, a price, or a per-language state beyond the summary. NEW (PRD debt).onbrand_followup body verbatim (_shared/onbrand-followup-template.ts: “Hi {{1}}, it's {{2}} from {{3}} — circling back on your message. {{4}} Reply here any time and I'll pick it right up.”), rendered with that file's own example values; the earlier placeholder sentence was never a template. Founder-editable is settled by code, not a PRD row: this name is in LOCKED_TEMPLATE_NAMES, is translated per purchased language from the locked English, and a founder-authored variant is never submitted — so the row is read-only in every state. The language a given send uses is decided at send time (resolveTemplateLanguage), never shown here.POST_ACTIVATION_READONLY_TEMPLATE_IDS) the row keeps a LIVE Edit → door to Connects plus one guidance line: “Follow-up languages live on your WhatsApp connection. Add one anytime — your assistant keeps running.” Languages are not assistant config — they live on the connection and are read at send time — so adding one needs no pause, no stop, no re-activation, and nothing here may route through Start fresh. NEW (PRD debt).assistant-lifecycle.html sec-5 exactly: apps + wallet flex-1 on the left, Brain Check fixed 400px on the right — On-Brand Support has a real 7-field Brain Check module, so the master's split applies cleanly with no adaptation needed.Both tiers now drawn per R22. Archetype: assistant-detail-tabs.md.
Runs on your WhatsApp from the moment you activate. Pause anytime.
← the REAL Brain page, live and editable · tap the seam to return
The check re-runs the moment you save on the left — ○ flips to ✓ without leaving Connect.
prd-as-on-brand-support.md §Test Plan.BrainSlideOver with the target section auto-expanded; closing returns to the wizard without losing wizard state.Brain readiness lives on Connect →.
prd-as-on-brand-support.md §Personalization Scope §02 Handling rules, #2605/T1206): a “route to you” topic feeds the deterministic escalation detector, not just a prompt suggestion.prd-pl-voice-card.md and need re-homing there (PRD stays live — the voice engine, Brain sheet, and playbook are untouched). The quiet row drawn above never blocks proceed/activate.prd-as-on-brand-support.md §Test Plan / §T1097 — 7-field gate.ready=true, the wizard allows activation.ready=false, that field routes the founder to its Brain section.business_hours requirement./connects?category=ai.brain_manifest), required first, Optional label on recommended, per-row ✓/○/⚠, amber Add/Review in Brain → on anything missing/degraded. Not-ready state: ! 5 of 7 ready, same module every time it renders.assistant-lifecycle.html frame 14.Runs on your WhatsApp from the moment you activate. Pause anytime.
assistant-lifecycle.html frame 6.You already have one called Autumn retreat support. We numbered this one so you can tell them apart in Pulse — rename it to anything you like.
Keeping the same name is fine, it's just harder to read later.
Runs on your WhatsApp from the moment you activate. Pause anytime.
prd-pl-activation-wizard.md § “Instance Naming — Derive Distinct, Then Nudge” (AC-NAME-01…06). Cross-cutting: this is the shared Try-step naming contract, not a TMPL-9P3X behaviour — drawn here because 9P3X is the exemplar file. AC-NAME-04's sibling-status list was revised at gate R2 (2026-08-08) to include `stopped` + `archived` — verified live against the CF Pages preview (real WhatsApp-connected test account, Start Fresh path): the collision nudge fires correctly against a `stopped` sibling, matching this frame's copy exactly.archetypes/reactivation-flow.md (c) + (e)). The field must arrive already distinct — the copy explains a name the founder can see, it never asks them to fix our default.--fg-55 body text under the field, the sibling's name lifts to --fg-70, and the escape line sits at --fg-30. No amber chip, no warning icon, no red.Name this one section verbatim (.sm + .field); the only new elements are the two caption lines. The “Your word for this instance” helper is replaced by the collision copy while a sibling exists, not stacked on top of it.2, then 3… (never (copy), never a date, never the display_id). The founder's word stays the stem so the pair sorts together in Pulse.About 20 seconds. Stay on this screen.
prd-pl-activation-wizard.md (the shared activate-assistant pipeline this loader collapses to 5 steps) — not this assistant's own PRD; no AC-* id to cite here.activate-assistant pipeline (auth → apps → BYOK-AI gate → payment → terms → workflow → test run → finalize) to 5 grouped steps — wording copied verbatim from the master loader (assistant-lifecycle.html frame 7a, .ld-step): Checking your setup → Confirming billing & terms → Setting up your assistant → Running a live test → Going live.It's answering on your WhatsApp now. Escalations go to #guest-support. Watch it work in Pulse.
It's answering on your WhatsApp now. Escalations go to #guest-support. Watch it work in Pulse.
prd-pl-activation-wizard.md (the shared success-state contract) — not this assistant's own PRD; no AC-* id to cite here.activate-assistant skips the test step for user_initiated (chat) trigger types — is asserted only in this design note, not in a Test Plan row.WhatsApp rejected the message send, so we stopped before activating anything.
Still stuck? Message us — we'll look at the run.
prd-pl-activation-wizard.md (the shared rollback contract, B6) — not this assistant's own PRD; no AC-* id to cite here.wa.me/<MYSTFLO_SUPPORT_NUMBER>, config value, never hardcoded), run reference prefilled — master precedent: assistant-lifecycle.html frame 7(b) note “(b) Failed · B6”. This landing owns the link; the Try-tab nudge (frame 5) keeps its own separate “send yourself the first one” copy untouched.pending_template_approval launch-pending, template_rejected) never apply and are intentionally not drawn here. The loader (6a) and this failed/rollback landing (6b) are the only outcomes beyond the live success state (6).https://wa.me/16318181081 — guests scan or tap to message you, no booking prefill.pulseFeedFormatting.ts.LogsTab.tsx, not drawn as a separate frame.On-Brand Support reads your Brain — your prices, policies, hours, FAQs, and brand voice — and answers guest questions in WhatsApp in the voice you confirmed. Routine questions get answered in seconds. Anything it can't ground in your knowledge gets handed to you on Slack.
long_description; post never draws a second one.ASST-7Q1, template name dropped to the quiet sub-line) and icon run-controls (⏸ ⏹) in place of the price-only pre header; tabs are plain nav (Pulse · Overview · Personalize · Connect), no chevron separators, no done-ticks.Follow-up languages live on your WhatsApp connection. Add one anytime — your assistant keeps running.
Changes take effect on the next run. Nothing already answered is rewritten. Brain readiness lives on Connect →.
POST_ACTIVATION_READONLY_TEMPLATE_IDS) — not greyed with the locked fields. Justification: it edits ACCOUNT state (the WhatsApp connection, read at send time), never the assistant's config, so it neither breaks the lock nor routes through Start fresh. The status on the line is per-assistant (this assistant's own Meta templates), not the account's worst-case list — the two views can disagree by design (see frame 3b note). Chief-architect assigns this AC-CONNECTS-25 in the Connects PRD — that row has NOT landed yet (the PRD tops out at AC-CONNECTS-18), so until it does this stays NEW (PRD debt); cite the id here once the PRD carries it./design 2026-08-24, now cited as AC-MODALTWIN-16 ↗ / AC-MODALTWIN-17 ↗ (in-flight a11y) in the activation-wizard PRD §1/§1a (added same PR as this note). Settled + shipped, note-not-copy (Peyton re-confirmed 2026-08-29: “remove the save changes bar and confirm dialog - we had decided this before earlier… auto-save once user select the toggle”): live on main since PR #4066 (AssistantSettingsTab.tsx saveInstantField + per-key savingKeys ~:404-431, D-2 comment ~:368, “Couldn't save that” toast ~:420). The sentence describing it is a frame ANNOTATION — it is never drawn as founder copy (removed from the drawn paragraph in this redraw). Scope drawn here = TODAY's shipped behavior: toggles instant-save; text fields (Greeting, Handling rules, Routed to you) keep the dirty-state bar + ConfigChangeConfirmModal — a snapshot, not a target state: Peyton ruled platform-wide the same day (“yes, all input fields are auto-save through the platform”), a separate CTO-owned workstream (prerequisite #4077 per-field patching) that supersedes this split when it lands. Do not “fix” auto-saving fields back to the bar afterwards.BillingPreferences.tsx's wallet-alert checkboxes — persist() on change, silent success, toast only on failure). The Switch stays interactive mid-flight (NOT disabled — that pulled it out of tab order) — it dims + reports aria-busy, with an aria-live "Saving…" label; re-entry during a save is guarded in saveBooleanField's savingKeys check, not by disabling the control. Failure toast title is "Couldn't save that" (brand voice — not a raw "Save failed" stub), switch reverts to its prior value, no dirty-state bar appears behind it. No sticky Save/Discard bar, no ConfirmSettingsChange modal — those add a second click that echoes back information the founder already saw when the switch moved, with zero cost or risk to review (binary, instantly reversible). Every OTHER field type on this tab (Greeting, Handling rules, Routed to you — all text) keeps the existing dirty-state bar + confirm-modal flow unchanged; that review step still earns its place for free-text edits and, on generator templates, cost warnings. This is a shared-renderer change (ConfigFieldRenderer's case 'boolean') — every schema-declared boolean field gets this, on any template that mounts AssistantSettingsTab. Known limit, shipped anyway (Peyton-approved 2026-08-25, "ship it first then fix"): the save writes the assistant's whole configuration at once, not a per-field patch. This is reachable in TWO shapes, not one: (a) two DIFFERENT boolean fields on the SAME live template flipped in quick succession — checked against real migrations, not schema-in-isolation: every live template mounting this tab carries at most one boolean today (TMPL-BRST01's six-toggle schema is real but generationSurface:'brain_inline' blocks it from ever mounting this modal via every NEW-activation path checked — the Assistants catalog AND the Brain page's own "Build Your Brand" flow both reuse the same filtered hook; an already-activated legacy instance from before that reclassification is the one thing not ruled out, and isn't checkable without a customer-data read this session isn't authorized to run solo); (b) a boolean flip racing the EXISTING text-field Save+Confirm flow on the SAME tab — reachable TODAY on the one live field via completely ordinary use (flip Slack, then edit+save Handling rules) if one request lands slower than the other. Both shapes, same cause, same fix. Tracked as a high-urgency follow-up (server-side partial-patch on update-config): #4077, which should carry a mechanical one-boolean-per-template guard as an acceptance criterion, not just this prose.notify_escalation_slack, added 2026-08-24 by #4027) IS a real schema-declared boolean and DOES get D-2's instant-save behavior — it's rendered by a dedicated SlackNotifyRow component (not the generic schema loop, to avoid duplicating the row), which now also receives the saving prop for the same in-flight indicator. TMPL-WAITL1 (Waitlist+Launch) does NOT use this component at all — it has its own separate WaitlistSettings screen with its own save flow; its toggles are unaffected by D-2 entirely. This is the live boolean today, singular.prd-as-on-brand-support.md §Test Plan.On-Brand Support reads your Brain — your prices, policies, hours, FAQs, and brand voice — and answers guest questions in WhatsApp in the voice you confirmed. Routine questions get answered in seconds. Anything it can't ground in your knowledge gets handed to you on Slack.
Follow-up languages live on your WhatsApp connection. Add one anytime — your assistant keeps running.
Changes take effect on the next run. Nothing already answered is rewritten. Brain readiness lives on Connect →.
Pick a channel — escalations aren't reaching you yet
Saving…
ConnectionsSection.tsx documented this as a deliberate DOM-parity omission — the post modal never passed tetheredPickers, so no picker rendered here at all (the "Connected ⌄" chevron was dead). Fine while the channel was optional; a dead end once #3205 made it required once Slack connects — confirmed live when the FFB test account's escalation never reached Slack.AssistantDetailModal.post.tsx now builds tetheredPickers the same way ConnectStep.tsx (frame 4) already does — same tetheredPicks.tsx builder, no new component. Pre and post render the identical picker.ConnectionsSection.tsx — the row-level "Optional" badge already carries the signal, and no launch template has more than one optional role (checked all 5 in T408p2's seed migration).tetheredPicks.tsx's shared renderPick() reused the wizard's amber "Pick one to continue" verbatim — true during setup ("continue" is a real next step), false here: the assistant is already live and escalations are silently dropping on the floor right now. State 2 above draws the corrected copy, threaded through a new context: 'wizard' | 'live' param on buildTetheredPickers/renderPick so the wizard's own copy is untouched.SlackChannelPicker is fully controlled by value; a save that only updates local state on success made a pick visually snap back to "Select a channel" for two round-trips (fresh-fetch, then save) on a slow connection — the exact "did my pick even register" failure class TetheredPickReveal (#2368) exists to prevent. State 3 shows the picked value immediately, dimmed, with a quiet "Saving…" line — never the empty placeholder — and only reverts on an actual failure.Rename it first? Winter retreat support ✎
prd-pl-activation-wizard.md (the shared reactivation contract: quick_resume / review_config / start_fresh) — not this assistant's own PRD; no AC-* id to cite here.ModalWrapper presentation="dialog" size="sm"), two real choices, recap answers “what happens to my old setup?” before it's asked. Start-fresh opens the standard wizard prefilled; old instance stays in Past.assistant-lifecycle.html sec-13) draws the generic/offering example; this file is the chat-adapted one.review_config stays invisible plumbing, never a card. Optional rename rides on the Reactivate card.ReactivationConfigReview.tsx:341, auto-resume branch at :134) — drawn here and in the master (assistant-lifecycle.html frame 13), labeled “always Reactivate”, never the internal quick_resume name..kv — chosen for consistency with the pattern already shipped in this exact modal, not a new one. Rename affordance is a single text link across every viewport (matches this frame; the master's sec-13 desktop side-by-side outline button is not built — size="sm" barely changes width by breakpoint, so a second button treatment isn't a real gain here).part-components label — per the canon, flow files keep the component
inventory as notes; every part listed here appears seated in a full screen in sections 5/6, never
only here.assistant-flows/assistant-lifecycle.html is the PRIMARY structural contract — this file is the per-assistant exemplar and must never contradict it. assistant-flows/workshop-booking.html is the canonical structural reference for the 8-section shape (design-canon.md § Assistant-flow mockup structure, 2026-08-06); this file is the token-block exemplar the siblings copy verbatim.prd-as-on-brand-support.md §Test Plan · T1209 handling-defaults migration · HandlingRulesEditor.tsx · AttentionPanel.tsx · ReactivationConfigReview.tsx · chat-assistant-standard.md · ledger ../parity/parity-on-brand-support.md (2026-08-04).prd-as-on-brand-support.md §Test Plan.#done in the Slack thread resumes AI mode within seconds; the literal string “#done” is never forwarded to the guest's WhatsApp.#done hands the thread back to AI instantly — shipped (#2616, 2026-07-22): the Slack reply triggers resume_ai_mode immediately; the 5-min sweep stays as the safety net if #done fails or the owner forgets.No deferred items — everything above is the current build (the shipped On-Brand Support flow). Deferred decisions named in Scope (§2) — the pre-activation chat sandbox, BYOK AI provider picker, escalation-rate card stat — stay listed there, not drawn: never invent Future frames to fill this part (kit canon U9).