product

Rehearsal Room

Model a person (personality type + situation) and 2–3 intervention options — an activity, a phrasing, a choice — and see how each might land, side by side, before it's real. Public + throttled. North star: a decision-testing marketplace.

Hook (general audience): "Got a big conversation you're dreading? Rehearse it first. Real personalities, real choices — see how it might land." The flagship seed scenario is the ur-dreaded conversation, "We need to talk."

Honesty posture (load-bearing)

A rehearsal, not a prediction. An LLM persona is a plausible-fiction generator, not a validated model of a real human. Every reaction is framed as one plausible response; no diagnosis, no "what they will do," no clinical claims (same wellness-not-clinical line as Throughline). This keeps it defensible and is truer to the tech.

How it works

It's the AI-persona engine pointed sideways: instead of "let this persona journal," it's "react in character to each of these approaches." Reuses MBTI_WRITING_STYLES + an OCEAN-style tendency description (apps/backend/src/services/ai-personas.ts) to prompt the reaction via the cost-logged complete() shim (feature_key: 'rehearsal_room.reaction'/dashboard/admin/llm-spend).

v1 surfaces (shipped)

  • /rehearsal-room — the public tool: define a person (archetype + situation), add ≤3 options, Run → side-by-side reactions (reaction · reads-as · watch-for). Saved runs + history (by anon_token in localStorage, or account). Share link.
  • Public, anonymized gallery — runs go in public by default so the homepage becomes a real, searchable feed ("conversations people are rehearsing") of real runs + curated examples. Privacy: before modeling, a prep step (prepareForPublic) swaps real person NAMES for consistent pseudonyms across every field and generates topic tags; modeling runs on the sanitized inputs so reactions are public-safe too. The UI tells the user (heads-up before Run + a "names swapped: Sam → Riley" notice after). Gallery supports ?q= search + ?tag= filter; cards show tags. Opt-out: a "keep this private" toggle (keep_private) skips pseudonymization entirely and stores the run owner-only with real names — is_public=false, no share_slug, no tags, never in the gallery. The share endpoint refuses to publish such a run (it has real names); the user must re-run it publicly to anonymize.
  • Saved people ("remember this person") — a private library so users don't re-describe recurring people. A "Remember this person/character for next time" toggle saves the ORIGINAL (un-pseudonymized) description; a "Your saved people" picker loads them back. Migration 366_rehearsal_personas.sql; owner-only (user_id or anon_token). Personas CRUD: GET/POST /personas, DELETE /personas/:id; the run endpoint also saves when remember:true. Anon→account: POST /claim attaches anon_token-keyed runs + saved people to the account on signup/login; the tool sends the auth token on every call so signed-in users' data is keyed by user_id (proper ownership + cross-device).
  • /rehearsal-room/shared/:slug — read-only shared/gallery run.
  • Public, throttled: per-IP daily cap (rehearsal_rate_limits), input caps (≤3 options, situation ≤1000, option ≤500), gpt-4o-mini only, + a site_settings admin kill-switch (rehearsal_room_throttle, normal|paused).

Data: 364_rehearsal_room.sqlrehearsal_runs (persona/options/results jsonb, user_id or anon_token, share_slug) + rehearsal_rate_limits. 365_rehearsal_room_tags_public.sqltags text[] + GIN/public indexes + is_public default true. RLS-enabled, service-role access only. Backend: routes/rehearsal-room.ts (run / runs / share / gallery / archetypes), services/rehearsal-room.ts, data/rehearsal-gallery.ts. Frontend: app/rehearsal-room/{page,layout}.tsx + shared/[slug], components/rehearsal-room/{RehearsalResults,RehearsalHistory,RehearsalGallery}.tsx, OG app/api/og/rehearsal-room/route.tsx.

Verticals (the same engine, different doorways)

One config-driven engine (components/rehearsal-room/RehearsalTool.tsx + mode on the backend) powers all verticals; each page passes its own copy + seed.

  1. General audience — dreaded conversations. The homepage hook. (shipped)
  2. Work / office/rehearsal-room/work (mode='life'): rehearse a hard conversation with a manager, colleague, or direct report before the meeting. Own copy/seed + OG. (shipped)
  3. Therapists — rehearse an intervention for a client type. Cross-linked from /for-therapists (Throughline). (shipped: cross-link)
  4. Writers — "how would your character act in this scene?" (shipped) /rehearsal-room/writersmode='writer': a character is the persona, a scene is the situation. Own copy/seed + OG card (Bluesky-ready) + a story-universe cross-sell (WritersCrossSell) into HiveJournal / write.cafe / Graphene after a run. Likely the highest-leverage vertical given the founder's Bluesky reach. The villain-shown-mercy gallery example renders in writer framing.

Writers vertical — roadmap (what's left)

Shipped: the writers landing/mode, character-framed modeling, the OG hook, the cross-sell hand-off, and the write.cafe plugin — a collapsible RehearsalCharacterPanel embedded in the entry composer's options drawer (test a character mid-draft, "use my draft as the scene", private-by-default, saved-characters picker) + a "🎭 Rehearse a character" CTA on the /write-cafe home.

Story-universe capture (shipped): the writers cross-sell (WritersCrossSell) captures genre + premise and seeds the hand-off — the HiveJournal / write.cafe cards deep-link the composer prefilled (?prompt=) with a "journal as this character" starter (+ source=write-cafe); the captured world personalizes the copy and is sent on the cross-sell analytics event. Writer-mode runs also skip name pseudonymization (character names are fictional — writers keep them; tags still generated).

Roadmap now clear; future depth (a persistent story bible / multi-character universe) is a larger feature, not a v1 gap.

  • This already makes Rehearsal Room a top-of-funnel acquisition tool for the whole story ecosystem, not just a standalone toy.

Deferred (later)

Reusable saved persona/character library; richer builder (OCEAN sliders); non-therapy/non-writer verticals (managers, parents, negotiation); the public gallery growing from curated → real shares; anon→account claim polish (set user_id where anon_token matches on signup).

REHEARSAL ROOM — Docs | HiveJournal