The deliberate scope, milestone plan, and trade-offs behind explAIn. The authoritative version lives in docs/roadmap.md and docs/architecture.md.
Roadmap
v0.1 — “Two humans, an advisor each, one Moderator”
Goal: validate the core advisor + mediator loop end-to-end, with one persona, one provider, on the web. In scope:
- Email magic-link auth.
- 1:1 conversations with an invite-link join flow.
- Real-time send/receive via Supabase Realtime.
- Per-user advisor (DeepSeek, streaming, accept/edit/discard UI).
- Moderator persona only (annotation pills below each message).
- The transparency “show your work” panel (original draft / advisor suggestion / sent text / mediator annotation).
- Per-call
llm_callsledger (data only, no UI). - A soft daily token ceiling per user (dogfood guardrail).
- Expo web build deployed to Vercel.
v0.2 — “Pick a persona”
Add the remaining four personas with their distinct behaviors (Arbiter, Judge, Chronicler, DM), the persona-switching propose/accept/reject UI, plus OpenAI and Google adapters and a per-conversation model picker.
v0.3 — “Native”
iOS and Android builds via EAS, push notifications (Expo Notifications + Supabase webhook), and mobile-specific UX polish.
v0.4 — “Hosted tier”
Stripe subscriptions, quota enforcement from llm_calls aggregates, a user-facing usage dashboard, and an invite-only beta gate.
v1 — “Public”
Open the BYO-key open-source variant (extract packages/llm into a public repo with a self-hosted setup guide), a marketing site, and public launch.
Out of scope (deliberately)
- Group chats (more than 2 humans). The product hinges on a 1:1 mediation contract; the active-participant cap allows a small structured group, but mass group chat is not the goal.
- Voice and video. Text first.
- Message edit/delete in v0.1. A re-edit would force the mediator to re-run, and the right semantics are not yet obvious.
- Model fine-tuning.
Notable trade-offs
- Observers vs muted participants. explAIn chose a hard
active/observerrole split over “everyone active, some muted,” because the LLM-visibility boundary is the load-bearing asymmetry. An observer is never fed into the mediator’s context; a muted-but-active participant would be. See Product Vision. mediator_action='external'for non-mediated rows. Structural and cross-chat-quote rows that bypass the mediator are tagged'external'(or'passthrough'forkind='system') so audit queries keep real mediator decisions distinct from structural insertions.- Cascade on cross-chat tags.
cross_chat_tagsrows cascade-delete with their parents; the durable record is the message ledger (the system notice and theexternal_quoterow), so losing the ephemeral coordination row is acceptable for v0.1/v0.2. - Notification banner before web push. A
pending_notificationstable plus an in-app banner ships first; real push (v0.3) will INSERT the same rows for backgrounded clients, so banner and push share one data plane and the v0.2 window avoids service-worker / VAPID infrastructure. - Sentry + soft auth fallback. When
useSession()is used outside its provider in production, it logs to Sentry and returns an unauthenticated sentinel (routing to login) rather than crashing; dev still throws.
Open questions parked for later
- DM cadence: time-based vs message-count vs LLM-decides (different infrastructure each).
- Judge rule format: free-text charter vs preset templates vs LLM-judged natural language; v0.2 starts free-text.
- Advisor opt-out per conversation: affects
advisor_suggestionnullability; currently nullable, revisit on usage data. - Message edit/delete semantics: does the mediator re-run? Default is “no edits” until dogfood demand appears.
- Brand / wordmark: ship the stylized
explAIncapitalization in product UI or only on the wordmark.
Related
- Product Vision — the thesis and transparency contract
- Architecture — the system that implements these decisions
- Source of truth:
docs/design.md