Skip to content

feat: cycle random quotes in TUI status bar and Web top bar #32

@Flare576

Description

@Flare576

Summary

Surface random quotes from the user's memory in idle UI real estate. Quotes are half the system's persistent memory — they should be visible somewhere other than a dedicated view.

Motivation

After running a full quote backfill migration (see v0.5.1 release), the system has 3,166+ quotes with correct speaker and channel attribution. These are rich, personal, often funny records of real conversations. They deserve passive visibility.

Design

Web — top bar empty space

Current layout:

|SidePanel| Chat with [persona]    [tons of empty space]    () Ready [Pause] [Menu]

Use the empty space for a slow vertical marquee (teleprompter-style scroll, ~20px/s) showing 2 lines of text. Quote text scrolls up continuously, pauses on hover. Small font, subdued color — doesn't compete with the persona name.

TUI — status bar

Current layout:

Ei    [tons of whitespace]    [Input]  Ready

Single line, limited width. Use paginated scrolling:

  1. Word-wrap quote text to actual bar width
  2. Show each "page" for 30 seconds
  3. Advance to next page, then cycle to next quote after a few minutes
  4. Yield to real status info — if queue is active or something needs attention, suppress the quote

Both

  • Cycle to a new random quote every ~3-5 minutes (configurable)
  • Only show when idle
  • Empty state: show nothing (no quotes yet = new user, don't fake it)

Attribution Format

— Sisyphus                        (persona said it, 1:1)
— Flare w/ Sisyphus               (human said it, 1:1)
— Flare w/ Co-Creators            (human said it, room)
— Beta and Lena                   (persona said it, room — channel name IS the room)

Logic (both fields now exist on every Quote as of v0.5.1):

  • speaker === "human"— Flare w/ {quote.channel}
  • speaker !== "human" AND channel !== speaker → persona in a room → — {speaker} in {channel} (or just — {channel})
  • speaker !== "human" AND channel === speaker → 1:1 → — {speaker}
  • channel is undefined (pre-v0.5.1 quotes that missed backfill) → omit attribution entirely, just show the text

Data

Quote shape (as of v0.5.1):

{
  text: string;
  speaker: "human" | string;   // who said it
  channel?: string;            // where it was said (persona name or room name)
  // ...
}

Processor already has searchHumanData() which does semantic search. For random quote cycling, a simple random sample from state.human.quotes filtered by text.length > 20 (avoid noise) is sufficient — no semantic search needed.

Implementation Notes

  • Quote fetch should happen on a timer in the frontend (not the Processor loop)
  • TUI: read bar width from layout at render time for word-wrap
  • Web: CSS overflow: hidden + CSS animation for the marquee — no JS scroll loop needed
  • Consider a max_display_length cap (~300 chars) to avoid very long quotes dominating

Out of Scope

  • Quote pinning / favoriting
  • Filtering by persona or channel
  • Click-to-view-full-quote

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions