Static dashboards show you the past. Conversational dashboards (the chat-with-a-chart pattern) make the past interrogable. Live conversational dashboards add the missing piece: an AI watching the stream alongside you, proactively narrating events as they happen and anchoring its narration back onto the chart. The chart accumulates context the moment something interesting occurs. There's no waiting for someone to ask the question, no losing the moment to scroll.
Three pieces composed into one product
This pattern is buildable only because Semiotic ships the three primitives it needs as separate, composable things:
- A streaming runtime. Push API, observation hooks, decay encoding — the chart is designed for data that arrives over time.
- An interrogation hook with proactive announcements. The new
announce() method appends AI-initiated messages to the transcript and adds annotations to the chart without going through a user question. A watcher can call it as freely as a user can call ask(). - Anchored annotations. Every announcement can carry a callout, a threshold, or a band — visual provenance for the AI's claims, attached to the coordinates the claim is about.
Compose them and you get a dashboard where the AI's "I saw that" is structurally identical to the human's "ask about that" — both write to the same transcript, both leave traces on the same chart, both feed the same conversation.
Try it
Synthetic request-latency stream — a value arrives every 400ms. A rolling z-score detector watches the last 30 points; anything beyond ±2.4σ gets announced. Each announcement carries a callout on the chart (with a note explaining the deviation category) and an entry in the transcript. Ask a follow-up like "why?", "what's baseline?", or"is it getting worse?" and you'll get the AI's response in the same transcript. Pause to inspect; reset to start over.
Watching — stream + z-score detector live0 points · 0announcements
Request latency (ms) — synthetic stream
Watcher will announce anomalies here in real-time. You can also ask follow-ups ("why?", "what's baseline?", "trend?").
The demo uses canned responders for the LLM side. In production you'd wireonQuery to a real model and the announcement note field would be the model's actual narrative — generated when the watcher fires, cached on the annotation, displayed on hover.
The watcher pattern
The detector here is intentionally simple: a rolling-window z-score with a debounce. That's the right starting point for most monitoring workflows because it has zero configuration, runs in O(window) per tick, and catches both spikes and dips. Stronger detectors layer on top:
- Median absolute deviation (MAD) instead of stddev for non-Gaussian streams — heavy-tailed metrics (request latency, error counts) often have outliers that pull stddev around. MAD is robust.
- Multi-window comparison. Compare the trailing 30 seconds to the trailing 5 minutes. Flag when they diverge. Catches drift the rolling-window detector misses.
- Domain-aware thresholds. Latency over 1000ms is interesting at any time, even if the rolling mean was 950ms. Add absolute thresholds on top of the statistical ones.
- Capability-layer-driven detection. The same chart that's currently showing latency could be rendered as a Histogram instead — and the histogram-based watcher would flag distribution-shape changes (bimodal becoming unimodal, tail fattening). Pair
suggestStreamChartswith watcher logic specific to each chart family.
Whatever the detector, the pattern is the same: when it fires, call announce()with text and annotations. The interrogation hook handles the rest.
The conversational side
Half of the dashboard is autonomous (watcher → announce). The other half is reactive: the user reads an announcement, has a follow-up question, and asks. That question lands in the same transcript with full context — recent announcements, the statistical summary of the visible window, the user's currently-focused point if any.
The asymmetry is the feature. The watcher narrates broadly ("⚠ spike at t=42, 3.1σ above baseline"); the user drills in ("which downstream call?"). The LLM gets both signals on every turn — it knows what the watcher already said and what the user wants to know now.
When to deploy this
- Production monitoring with on-call rotation. The AI is essentially writing real-time handoff notes. When the next oncall takes over, the transcript plus the chart's anchored notes are a complete record of "what happened during my shift."
- Financial trading desks. A watcher monitors instrument moves; the AI annotates breakouts and breakdowns the moment they happen. Traders ask follow-ups without leaving the chart.
- IoT / industrial telemetry. Sensor streams from a factory floor. The watcher flags pressure drops, vibration anomalies, temperature drift. Each gets a timestamped anchored note that becomes the maintenance log.
- Live experiments / lab readings. Researcher running an experiment; the watcher flags when readings deviate from expected. The AI's anchored notes become a real-time lab notebook.
- Live data exploration sessions. Analyst exploring a new dataset with streaming updates (a query that produces results progressively). The AI narrates what it sees as the data arrives.
Production considerations
The demo cuts corners for clarity. Real deployment needs to handle:
- Use
RealtimeLineChart.The demo uses plain LineChart with state-managed buffer because it's easier to read. In production, swap in Semiotic's RealtimeLineChart — it has an imperative push API that bypasses React re-renders, supports decay encoding, and handles particles. 30+ Hz streams are comfortable. - Debounce the LLM call. The demo's
announce() happens synchronously when the detector fires — the "note" is canned. In production, calling the LLM inside the detector loop will blow your budget. The right pattern: announce immediately with a placeholder note ("detected, analyzing…"), then call the LLM asynchronously, then update the annotation's note when the response lands. - Rate-limit announcements. A cascading-failure incident can fire the detector dozens of times in seconds. The demo debounces by 5 ticks; production needs adaptive backoff (collapse repeat announcements into "10 spikes in 30s").
- Sliding-window annotation lifecycle. When the chart's data window slides, annotations referencing data that's been evicted should either age out or migrate to a separate "recent events" panel. The demo lets them slide off — fine for monitoring, wrong for a forensic timeline.
- Persist the conversation. The transcript is in-memory. If the oncall handoff is the use case, write it to durable storage. Semiotic doesn't ship that path; bring your own.
Failure modes worth thinking about
- The watcher cries wolf. A misconfigured detector floods the transcript with non-events. Users learn to ignore announcements. The fix is upstream — tighter detectors, multi-signal confirmation — not "make the AI better at phrasing the false alarms."
- The watcher misses real events. A z-score detector misses gradual drift. The transcript looks calm while the underlying system is slowly burning down. Pair it with longer-window detectors and absolute thresholds.
- The AI hallucinates causes. The watcher detected the spike; the LLM is guessing what caused it. Make the AI's note explicitly tentative ("likely candidates: …") and surface links to actual evidence (logs, traces) when available. Never let the AI claim certainty it doesn't have.
- Operator desensitization. Anything blinking and announcing constantly gets tuned out. The watcher should be quiet most of the time. Better to flag fewer real events than many maybe-events.
Why this is hard to build outside Semiotic
The pattern requires three things that other chart libraries don't put together:
- A streaming chart runtime that handles incremental data without re-mounting (Semiotic's push API + decay).
- An interrogation surface that accepts proactive AI input, not just user queries (the
announce() method). - An annotation model where AI-generated annotations are first-class (callouts, thresholds, bands all work the same whether the human or the AI added them).
Other libraries can be made to do this with enough custom plumbing — but only because they treat each of the three concerns as out-of-scope. With Semiotic, all three are in-scope, individually testable, and composable. The streaming-first runtime is the load-bearing piece; everything else assembles around it.