* chore: remove legacy orchestrator, trading and one-off script leftovers The repository still carried the pre-evOo prototype: a Python orchestrator, the old HTML "evoo-platform" cockpit (whose test ran in the root unit suite), an apex-trading package, the hot-reload deploy.sh for it, a permissions manifest, an architecture note with local file links, agent handoff notes, a Steve Jobs persona template and about ninety one-off scripts that probe a developer database with hard-coded local URLs. None of it is used by the product, CI or the real deploy in ops/evo-deploy. Delete those files, drop the evoo-platform test glob from the root vitest config, the Cockpit section from .env.example and the dead biome and gitignore entries, and update the docs that listed the removed tools. scripts/start-tmux.sh no longer starts the removed sentinel and resolves the checkout from its own location instead of a machine-specific path; scripts/seed-ollama.ts requires DATABASE_URL instead of falling back to a local URL with a username. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): drop trading and persona prompts from the conversation shell The web shell still showed leftovers from the trading prototype: composer chips with German trading and "Steve Jobs" prompts, trading suggestion chips under the empty conversation line, a German trading hero for the empty transcript, and a German "data protection" status panel in the sidebar. They suggested actions the product does not have and added persistent chrome. Remove the composer chips and their helper, the empty-state chips and the hero (the empty conversation keeps its existing one-line start hint), the sidebar trading indicator and the data trust panel. The new-bot E2E now asserts the plain empty state; the sidebar spec no longer expects the trading status, and the placeholder Steve Jobs spec with no assertions is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * refactor: remove the trading bot status integration With the sidebar trading indicator gone, the only remaining consumer of the trading bot status was a banner in General settings that reused the same component. evOo is a personal assistant; a status proxy and poller for one external trading service, configured through service-specific TRADING_BOT_URL and VITE_TRADING_BOT_URL variables, does not belong in the core product. Remove the settings banner and its prop plumbing, the web poller, the indicator component, the /api/trading-bot/status proxy, the shared core contract, the env loading and both variables from .env.example, together with their tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore: remove one-off database scripts and a stale review note packages/db carried four hand-run scripts outside the package build that query or seed a developer database with a hard-coded connection string, one of them for a specific account. docs/VOICE-FIRST-REVIEW.md was a one-time verification note for a workflow that no longer exists and named private machines and local paths. Nothing references them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore: replace machine-specific paths and addresses with placeholders ORIGIN.md pinned the intended checkout to an absolute path under a personal home directory, docs/LOCAL-SETUP.md listed folders on one developer's machine, and two tests used what looks like a real tailnet address. Use a home-relative path, drop the machine-specific folder list, and use 100.100.100.100 in the tests; it is still inside 100.64.0.0/10, so both tests check the same thing as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): drop the trading status from the shell contrast test main's contrast test now waits for the sidebar trading status before measuring; this branch removes that status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
9.4 KiB
EvOo Voice — Interaction Model
Gesamterfahrung (encounter)
A conversation with an Oo is a shared encounter, not a thread with a tiny avatar:
| Layer | Role |
|---|---|
| Oo Stage | Primary — large BotAvatar / persona presence, runtime pose, awareness strip |
| Transcript | Secondary protocol — compact caption trail, scrollable record |
| Sound | Calm procedural cues wired to real events (work finished, voice phases, handoffs) |
Text mode (OoStage in Shell) and Voice mode (VoiceStage overlay) share the same metaphor: eyes/presence + space + sound. Brand lock (asymmetric Kulleraugen) is unchanged.
Product model — conversation-centric (Grok-like)
Oos (agents) exist, but the product is organized around conversations (Unterhaltungen), not “pick an agent row = the whole app”:
| Layer | What it is |
|---|---|
| Team | Roster of your Oos — who you can talk to |
| 1:1 Unterhaltung | One Oo, one shared encounter (OoStage) |
| Gruppenunterhaltung | Multiple Oos (+ humans later) in one encounter (OoGroupStage) |
| Projekte | Group conversations organized in Ordner (BotSection folders in sidebar) |
| Mode | Shell route | Stage |
|---|---|---|
| Unterhaltung (1:1) | /app/:botId |
OoStage — one Oo hero |
| Gruppenunterhaltung | /app/g/:groupId?s=live |
OoGroupStage — active-speaker hero + ensemble row; Riffing when peers spark (docs/GROUP-CONVERSATIONS.md) |
| Project sessions | /app/g/:groupId (timeline) |
No stage — session list (ProjectSessionTimeline) |
Clicking an Oo in Team opens a 1:1 conversation, not “the agent product”. Clicking a project opens a group conversation or its session timeline. Gesamterfahrung (stage + sound + transcript record) applies to both conversation types.
Emergent ensemble: Das Ganze ist mehr als die Summe seiner Teile — power from distinct specialists + chemistry in groups, not one mega-agent (docs/PRODUCT.md).
Voice is the immersive primary mode for 1:1 bot conversations. Text chat uses the same stage-first layout; the transcript stays readable but no longer carries identity chrome.
Entry
| Surface | Action |
|---|---|
| Composer Voice pill | Opens Voice Stage when a provider is connected; otherwise opens Voice settings |
| Transcript “Speak this reply” | Reads one message aloud (text-first affordance, unchanged) |
The composer and stage Voice controls use h-control-lg in neutral tokens; when voice is ready an iridescent aurora rim (VoiceAuroraRim) runs along the bottom edge.
Voice Stage
Full-screen dark layer with one glass panel (VoiceStage): the Oo, the live caption, and a control row. An iridescent aurora (VoiceAurora) rises from the panel's bottom edge. Its spectrum is the bot palette (botColors from @rakazo/ui-tokens) rotated so the active Oo's own color sits in the center.
Persona & consciousness layer
Persona is derived at runtime from existing bot fields (name, title, description) — aligned with templates/* archetypes, not a separate marketing field.
| System | Path |
|---|---|
| Archetype detection | apps/web/src/lib/bot-persona.ts |
| i18n status copy | apps/web/src/lib/voice-persona-copy.ts |
| Awareness strip | VoiceAwarenessStrip — subagent, handoff, delegation, peer reply |
| Visual identity | BotAvatar — persona shape + unified EvooMascot soul (eyes/mouth/hands) driven by voice phase |
| Voice delivery | speaker.speak(..., { botId }) → server resolves per-bot voiceId |
Archetypes include: CTO executive, chief operator (Fixer), builder (Dr. Eggbot), curator (Webby), work/life inboxes, home steward, quant, engineer, specialist (narrow fallback — no Wunderwuzzi). See docs/PRODUCT.md and docs/PERSONA-SELECTION.md.
Companion tone: geek-peer (fachsimpeln when wanted) or quiet-doer (execute without condescension) — inferred per user, not one voice for everyone.
Accessibility of ambition: grandma-simple entry (Thermomix to hard math — no power-user gate); expert-grade ceiling per specialty. Same product, different crews; never a mediocre everything-bot.
Phase labels, idle prompts, and thinking lines are character-specific (DE/EN via Lingui). Collaboration narration uses persona-aware phrasing (“casting”, “routing”, “handing off”) instead of generic tool labels.
States
| Phase | Visual | Audio |
|---|---|---|
| Listening | Aurora rises and brightens with mic energy, breathing | Dictation active; silence endpoint sends |
| Thinking | Aurora settles low and drifts side to side | TTS idle; awaiting bot reply |
| Speaking | Full aurora bloom, conductor mascot pose | TTS playback; caption shown live |
Aurora height and opacity follow dictation.energy (0–1) while listening (voiceAuroraBlobs in apps/web/src/lib/voice-aurora.ts). The caption (VoiceLiveText) fades each new word in; words already on screen stay put while an utterance grows and the caption restarts for a new one. Mascot uses EvooMascot poses: idle / thinking / wave.
Controls
The control row holds the persona phase label (live region), Transcript, Interrupt (mic), and Hang up (×).
| Input | Action |
|---|---|
| Space | Interrupt (stop TTS or cancel dictation, resume listening) |
| Esc | Hang up — exit Voice Stage |
| T | Toggle transcript drawer (secondary record) |
Transcript
Collapsible panel shows the last messages from the thread plus the live utterance. Chat scroll behind the stage is dimmed but unchanged; voice does not replace thread history in the database.
Accessibility
prefers-reduced-motion: reducedisables aurora breathing/drift, the panel entrance, and word fade-in; the static aurora remains.- Dialog semantics:
role="dialog",aria-modal, labelled bot name. - Hang up exposes
aria-label="Hang up". - Shortcuts are exposed through
aria-keyshortcutson the matching controls instead of on-screen hint text.
Architecture
Shell (composer Voice)
└─ CallView (orchestration: dictation + speaker + thread send)
└─ VoiceStage (panel, controls, transcript drawer)
├─ VoiceAurora (bottom-edge glow, phase + energy)
└─ VoiceLiveText (word-by-word caption)
Shared singletons: dictation (apps/web/src/lib/dictation.ts), speaker (apps/web/src/lib/tts.ts).
Design tokens
Voice chrome uses text-ui-*, size-icon-*, and h-control-* / size-control-lg — no sub-13px labels on primary controls. See DESIGN.md for the full scale.
Sound language
Procedural Web Audio (oo-sound.ts, oo-vocals.ts, oo-audio-bus.ts) — no sample packs. Full motion/SFX spec: packages/ui-web/MOTION-EVOO-CHARACTER.md.
| Cue | Trigger |
|---|---|
app-start |
Cold open — mint→violet shimmer |
interact |
Primary nav / roster taps |
success-resolve |
Run finished — mint→gold |
need-you |
waiting_input / takeover — with ouh vocal |
work-complete |
Alias of success-resolve |
listening-start / listening-stop |
Voice phase |
speaking-start / speaking-done |
TTS lifecycle |
attention |
Run error in composer |
message-sent |
Composer send |
handoff / group-spark |
Thread collaboration |
Reaction vocals (mh / Mhh nod, ouh, hm on success): state-change only, 8–12 s cooldown, −18…−12 LUFS via shared bus, duck under TTS/PTT.
Toggle: Settings → Voice → Sound feedback. prefers-reduced-motion: reduce → no vocals/SFX loops; character visual state only.
Current slice (this PR)
Stage + sound + onboarding reassurance — shared encounter without requiring the user to sit in front of the screen. Voice Stage is opt-in per session; text mode uses the same Oo Stage metaphor.
Ambient & video presence (future roadmap — do not ship without consent UX)
Ingo capability vision — document only until explicit opt-in flows exist. Not part of the current Gesamterfahrung slice.
| Idea | Product rule |
|---|---|
| Video calls optional | Only when the user wants; a simpler audio-only path stays first-class for users who prefer it |
| "It's just an Oo" | User does not need to sit in front constantly — practical help can be ambient (notifications, background runs, crew handoffs) |
| Ambient presence | An Oo can carry a lot of practical presence without demanding attention — aligned with quiet-doer mode |
| Long-term metaphors (opt-in only) | Could eventually stand in for an alarm system or a home camera — strictly user-opt-in, never default, never surveillance-as-a-feature |
Hard gates (aligned with docs/OO-RELATIONSHIP.md)
- No always-on camera or mic without a dedicated, revocable consent UX — not buried in ToS
- Never creepy — warm competence, not uncanny stalking; earned context only
- Not yes-men — push back on unsafe or over-broad monitoring requests
- No Wunderwuzzi — home/security lanes are specialist Oos with narrow scope, not one omniscient watcher
When video or ambient sensing ships: same encounter grammar (Stage + sound + transcript), plus a visible presence mode indicator the user controls.
Out of scope (later)
- Dedicated
/voiceroute - Hold-to-talk in composer
- WebGL / real audio analyser on TTS output
- Always-on video / ambient camera without explicit consent UX (see roadmap above)