glanceResult([...]). This page is exhaustive; the
renderer silently drops anything off-schema, so treat every cap as hard.
Global rules
- 1–3 blocks per card; at most one chart (
bars,line,splitBar) — extras are dropped, not truncated. - Every string is trimmed and must be non-empty; every number must be finite.
toneis always"neutral" | "good" | "bad"— a meaning, not a color. The renderer owns hues.- Glance cards render on the notch’s dark glass; there is no light variant on this surface.
- One failing block never sinks the card (per-block error boundaries), and one invalid block never invalidates its siblings — it’s dropped and counted.
header
appIcon renders a real app logo (e.g. "notion") — but only when the
visible title starts with that app’s name; otherwise the slot is dropped so
one brand can’t wear another’s icon.
stats
Wraps to a second line before truncating.
bars chart
Every bar carries its value label; the series switches to compact form
(
16K, 1.2M) when exact numbers would collide.
line chart
The latest value is always called out.
splitBar chart
Segment colors are assigned by index (blue → teal → purple → neutral) —
never by the author, and never green/red, so composition can’t be confused
with good/bad. Sliver segments are floored at ~2% so they stay visible.
progress
list
badge and trailing are mutually exclusive at render time — a badge wins.
A subtitle that repeats the badge text is dropped automatically.
keyValue
clock live
Ticks every second. An unknown timezone falls back to local time and
relabels itself “Local” rather than showing a wrong city.
countdown live
Exactly one of
until / seconds is required. Prefer until — an absolute
target survives remounts. The 30-day cap applies to seconds only; a
far-future until renders honestly (168d 04:30). Turns green at zero.
badges
divider
{ "type": "divider" } — no props.
row
Lays children side by side. Rules: rows never nest,
widget can’t be a child,
and at most one chart per row (it consumes the card’s chart budget).
Children size themselves two ways:
widget
The sandboxed escape hatch — see Custom widgets.
Not available to the model — only integration tool results can carry one.
Cannot sit inside a
row.
Glyphs
The 34-name allowlist for everyicon prop:
Parse & degradation semantics
- The wire format is
{ "blocks": [...] }under the_voiceos_glancekey of your tool’s JSON result; VoiceOS strips it before the model reads the result. - Invalid blocks are dropped individually; a card with zero valid blocks is dropped whole.
- After validation, the first 3 blocks survive and the first chart consumes the chart budget; the rest are dropped.
- Extraction caps the whole glance payload at 32,000 chars — raised to 96,000 when a widget block is present.

