---
path: /domains/arete/coach
surface: customer
domain: arete
auth: signed-in
source: apps/oshun/web/src/app/domains/arete/coach/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; live BFF
  chat submit + 5xx recovery re-walked 2026-06-27'
---

# AI Coach · Arete · OSHUN

## Purpose

Internal `/domains/arete/*` alternate surface for an AI-coach chat workspace:
chat / starters / history / insights / settings tabs. The chat composer now
calls the live BFF coach composer (`POST /v1/arete/coach/responses`) with the
typed prompt; starters/history/insights/settings still read fixture constants
(`COACH_SESSIONS`, `COACH_CONVERSATION_STARTERS`). Distinct from the polished
`/arete/coaching` (Lilith's bi-weekly letter) — this is conversational and
active, that is editorial and asynchronous.

## Entry points

- **Direct URL / bookmark** — yes (signed-in)
- **No link from `/arete/coaching`** — verify; the polished letter surface does
  not link here in source

## Layout regions

`page.tsx` is a `'use client'` page: SR-only "AI Coach · Arete · OSHUN"
heading + `<AreteAICoach />`. Component at
`apps/oshun/web/src/components/domains/arete/AreteAICoach.tsx`.

- **Container**: `max-width: 900px; padding: 24px`
- **Header**: Brain icon + h2 "AI Coach" + subtitle "Your personal coaching
  companion for growth, reflection, and insight"
- **Tab bar** (5 tabs):
  - `chat` — Chat (MessageCircle icon)
  - `starters` — Starters (Lightbulb icon)
  - `history` — History (Clock icon)
  - `insights` — Insights (Sparkles icon)
  - `settings` — Settings (Settings icon)
- **Content area** (per active tab):
  - `chat` → `<ChatView />` — session header with title and framework /
    personality chips; empty scrollable messages region until the user submits;
    browser message bubbles are tagged by
    `[data-arete-ai-coach-message="user|coach"]`
  - `starters` → `<StartersView />`
  - `history` → `<HistoryView />`
  - `insights` → `<InsightsView />`
  - `settings` → `<SettingsView />`

`ChatView` constants:

- `FRAMEWORK_LABELS`: motivational-interviewing, cbt, act, positive-psychology,
  solution-focused
- `FRAMEWORK_COLORS`: corresponding accent variables
- `PERSONALITY_LABELS`: supportive, challenging, analytical, playful
- `PERSONALITY_ICONS`: Heart / Brain / BarChart3 / Smile

## States

- [ ] **Loading** — N/A: client component with sync fixture import
- [x] **Empty chat (initial)** — chat starts with no message bubbles; the active
      session metadata still renders above the empty message pane
- [ ] **Typing indicator** — `isTyping === true` toggled by `handleSend`;
      animation `ac-typing` defined in `STYLES`
- [x] **User message** — submitted text renders as
      `[data-arete-ai-coach-message="user"]`
- [x] **Coach message (live BFF)** — the real BFF response renders as
      `[data-arete-ai-coach-message="coach"]`
- [x] **Suggested prompts** — when the BFF returns `suggestions`, prompt chips
      render as `[data-arete-ai-coach-suggestion]` and clicking one fills the
      composer
- [ ] **Tab switching** — instant
- [x] **Coach BFF error (recoverable)** — a non-2xx or failed BFF call renders
      "The coach could not be reached right now — your message was not
      processed. Please try again in a moment." as a coach bubble
- [ ] **Offline** — no offline queue or retry state; failed fetch uses the same
      recoverable message as BFF 5xx
- [ ] **Gated** — N/A
- [ ] **Standalone PWA** — no shell chrome around the page

## Interactions

### Tab bar (5 tabs)

- [ ] **Chat / Starters / History / Insights / Settings** (buttons)
  - Function: `setActiveTab(tab.id)`
  - Telemetry: none

### Chat composer

- [ ] **Input** (verify in lower lines of source — composer is referenced via
      `inputValue`, `setInputValue`)
  - Function: typed text becomes `userMsg` on send; immediately appended to
    `messages`
- [ ] **Send** (verify the send button rendering — `handleSend` is the handler)
  - Function: appends a user message, POSTs
    `{ framework: 'reflective', userMessage }` to `/v1/arete/coach/responses`,
    and appends the BFF `content` plus suggestion chips when the response is
    `ok`
  - Failure: non-2xx or failed fetch appends the honest recoverable failure
    bubble and does not render fake suggestion chips
  - Telemetry: none

### Suggested prompt chips

- [ ] **Pill prompt** — clicking calls `handleSuggestedPrompt(prompt)` which
      sets the input value to the prompt text (does not auto-send)

## Data & contracts

- **Reads**: import-time `COACH_SESSIONS`, `COACH_CONVERSATION_STARTERS` from
  `@/lib/arete/arete-extended-simulation` for session metadata, starters,
  history, insights, and settings fixtures
- **Writes**: browser POST to `/v1/arete/coach/responses` for chat replies;
  message state remains local and is not persisted
- **Realtime**: none
- **Caching**: client bundle only
- **Auth/role check**: app-level middleware

## Cross-references

- Domain hub: [`arete.md`](./arete.md)
- Polished counterpart: [`arete-coaching.md`](./arete-coaching.md) — the letter
  surface (different intent: editorial, asynchronous, bi-weekly)
- Cross-domain: Sophia (AI substrate) — `AreteAICoach` calls the Arete BFF coach
  composer; it does not directly import Sophia
- Component source:
  `apps/oshun/web/src/components/domains/arete/AreteAICoach.tsx`
- Simulation data: `apps/oshun/web/src/lib/arete/arete-extended-simulation.ts`
- Types: `apps/oshun/web/src/lib/arete/arete-extended-types.ts`
  (`CoachingFramework`, `CoachPersonality`, `CoachMessage`)

## E2E coverage

- [`apps/oshun/web/e2e/arete-coach-ui.spec.ts`](../../../apps/oshun/web/e2e/arete-coach-ui.spec.ts)
  — direct `/domains/arete/coach` browser coverage: typed prompt POSTs to the
  real `/v1/arete/coach/responses` BFF route as
  `{ framework: 'reflective', userMessage }`, renders the reflective coach
  response and suggestion chips, verifies suggestion click fills the composer,
  and forces a 503 to assert the honest recoverable message with no fake
  suggestions.

## Open questions / known gaps

- [x] Chat response now uses the real Arete BFF coach route instead of the older
      hardcoded simulated reply
- [ ] The direct page always sends `framework: 'reflective'`; the Settings
      framework picker is local UI state and does not influence chat requests
- [ ] No real persistence — messages reset on reload
- [ ] No safety / disclosure copy in the chat interface, despite the framework
      selector (e.g., CBT, ACT) implying clinical-adjacent framing — verify
      whether AI-disclosure / boundary copy needs adding
- [ ] No shared chrome with `/arete` polished surface
- [ ] How does this relate to `Sophia` / `Lilith` infrastructure? The page does
      not import from those domain libs directly
- [ ] No telemetry events fired anywhere in the component
