---
path: /lilith-studio/tara
surface: customer
domain: lilith
auth: signed-in + role:v1_editorial_producer (default)
source: apps/oshun/web/src/app/lilith-studio/tara/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'
---

# Lilith Studio · Tara (read-only mirror)

## Purpose

A single read-only pane on what Tara is currently serving end-users: today's
recommended sit, the course sittings, and the daily ritual. It mirrors live
content for the author's reference — edit/publish actions live behind the studio
shell, not here. Server-rendered by fetching `/v1/tara/today`,
`/v1/tara/sittings`, and `/v1/tara/ritual` in parallel.

## Entry points

- **Lilith Studio hub** (`/lilith-studio`) — verify a Tara surface link
- **`/lilith-studio/scenes`** — verify cross-link
- **Footer buttons here**: "← Studio hub" (→ `/lilith-studio`), "Scenes" (→
  `/lilith-studio/scenes`), "New scene" (→ `/lilith-studio/scene/new`)
- **Direct URL / bookmark** — yes (signed-in + editorial scope)

## Layout regions

`/lilith-studio/layout.tsx` mounts `<ShellLayout active="studio">` and the
editorial gate. **This page additionally mounts its own `LWebShell` with
`LCustomerNav active="explore"`** (see Open questions — likely a double-shell).
Max width 1080, centered.

- **Header**: studio `ShellLayout` header + this page's `LCustomerNav` (Explore)
- **Masthead** (`LMasthead`): left "Lilith Studio · Tara", right "read-only
  mirror", kicker "What end-users see now", title "_Tara_, currently live."
- **Two-column grid** (`1.4fr / 1fr`):
  - **Left column**:
    - **Today** (`LEyebrow`): accent-bordered card with mono line "Recommended
      sit · <pathLabel> · session <i>/<total> · <N> min", serif title, italic
      "taught by <teacher>". Empty → dashed "No recommended sit on the wire for
      today."
    - **Sittings (course)** (`LEyebrow`): `<ol>` of sitting rows
      (`40px 1fr auto` grid) — mono `index`, serif `title`, and a state·duration
      chip whose color keys off `state` (here=accent, done=green `#1f4f3a`, else
      muted). Empty → dashed "No sittings configured for the active path."
  - **Right column**:
    - **Daily ritual** (`LEyebrow`): rule-bordered card with mono "<ritualId> ·
      <daypart> · <N> min", serif title, accent "Pattern · <pattern>". Empty →
      dashed "No daily ritual configured."
- **Action row** (flex, wraps): ghost "← Studio hub", ghost "Scenes", primary
  "New scene"

## States

- [ ] **Loading** — async server component awaits three `bffGet` calls in
      parallel; no client skeleton. Verify `loading.tsx`
- [ ] **Fully populated** — today's sit + sittings list + ritual all present
- [ ] **No sit today** — `today.recommendedSit` falsy → "No recommended sit on
      the wire for today."
- [ ] **No sittings** — `sittings.sittings` empty → "No sittings configured for
      the active path."
- [ ] **No ritual** — `ritual` falsy → "No daily ritual configured."
- [ ] **All empty** — every BFF call returns null (network/non-2xx via `bffGet`)
      → all three dashed empty rows
- [ ] **Sitting state variants** — `here` (accent), `done` (green), `next` /
      `queued` (muted)
- [ ] **Error (recoverable)** — `bffGet` swallows errors to `null`, so failures
      render as the empty states — no distinct error UI
- [ ] **Offline** — 5s abort → null → empty rows; SW-cached HTML may show last
      render
- [ ] **Gated (access denied)** — non-editorial scope → layout renders
      `LilithStudioAccessDenied`
- [ ] **Standalone PWA** — `data-responsive-page`; verify the `1.4fr/1fr` grid
      collapses at narrow widths (no explicit responsive rule in code)

## Interactions

This page is a **read-only mirror** — the only interactive elements are the
three footer navigation buttons. The today/sittings/ritual cards are
non-interactive display.

- [ ] **Today card** (`<div>`) — non-interactive
- [ ] **Sitting row** (`<li>`) — non-interactive; verify whether a row should
      link to its sit (none coded)
- [ ] **Ritual card** (`<div>`) — non-interactive
- [ ] **"← Studio hub"** (`LBtn kind="ghost"`, `href="/lilith-studio"`)
- [ ] **"Scenes"** (`LBtn kind="ghost"`, `href="/lilith-studio/scenes"`)
  - Function: → [`lilith-studio-scenes.md`](./lilith-studio-scenes.md)
- [ ] **"New scene"** (`LBtn kind="primary"`, `href="/lilith-studio/scene/new"`)
  - Function: → [`lilith-studio-scene-new.md`](./lilith-studio-scene-new.md)
  - Keyboard: Enter activates; in tab order
  - Mobile (≤ 640 px): action row `flexWrap: 'wrap'` lets buttons stack

## Data & contracts

- **Reads** (parallel, `bffGet`):
  - `GET /v1/tara/today` →
    `{ generatedAt, recommendedSit?: { id, title, teacher, durationSeconds, pathLabel, sessionIndex, pathTotal } }`
  - `GET /v1/tara/sittings` →
    `{ generatedAt, sittings: { id, index, title, durationSeconds, state: 'done'|'here'|'next'|'queued' }[] }`
  - `GET /v1/tara/ritual` →
    `{ generatedAt?, ritualId, title, pattern, durationSeconds, recommendedDaypart: 'morning'|'midday'|'evening' }`
- **Writes**: none (read-only mirror)
- **Realtime**: none
- **Caching**: `bffGet` default `revalidate = 60` s; session cookie forwarded
- **Auth/role check**: `/lilith-studio/layout.tsx` editorial gate (admin:\* or
  studio:editorial scope) → else `LilithStudioAccessDenied`

## Cross-references

- Studio hub: [`lilith-studio.md`](./lilith-studio.md)
- Scenes editor: [`lilith-studio-scenes.md`](./lilith-studio-scenes.md)
- New scene: [`lilith-studio-scene-new.md`](./lilith-studio-scene-new.md)
- The end-user Tara hub this mirrors: [`../03-tara/tara.md`](../03-tara/tara.md)
- Journey:
  [`../../journeys/lilith-studio-tara-scene-publish.md`](../../journeys/lilith-studio-tara-scene-publish.md)
- Component source: `apps/oshun/web/src/app/lilith-studio/tara/page.tsx` (inline
  page; `EmptyRow` local component)
- Feature spec: [`V1/features.md`](../../../V1/features.md#lilith-persona-policy)
- Architecture: [`V1/ARCHITECTURE.md`](../../../V1/ARCHITECTURE.md#lilith)

## Open questions / known gaps

- [ ] **Double shell**: the layout mounts `ShellLayout` and this page mounts
      `LWebShell` too. Confirm whether the page should drop its `LWebShell` (the
      layout's refactor note says pages "return their inner authoring component
      directly")
- [ ] Nav `active="explore"` vs layout `active="studio"` — two competing
      active-tab signals
- [ ] The mirror is read-only by design but offers no link from a sitting row to
      its underlying sit/source — confirm authors don't need a drill-in here
- [ ] `bffGet` null on failure collapses error and empty into one state — no way
      to tell "no content configured" from "BFF unreachable"
- [ ] Confirm the three `/v1/tara/*` BFF endpoints are the same the end-user
      `/tara` hub consumes (so the mirror is truly faithful)
