"Never move the reader against their intent." Six words, then fifteen principles that cascade from it. Rule one: move only when the reader asked to move—if someone is reading, don't pull them somewhere else; auto-scroll should never be the default. Rule two: follow only while they're following—if they're at the live edge, keep the stream in view; if they scroll away, leave them there. Rule three: every interaction is intent—scrolling is not the only signal; selecting text, using the keyboard, opening a link, searching should all stop the interface from moving.
This is not product documentation. This is a UX heuristic precise enough to become an engineering contract. When shadcn/ui released chat primitives, the first artifact was not a component library but a specification: fifteen behaviors that define what makes a streaming chat interface feel right, encoded into a headless React primitive called MessageScroller that owns the behavior while you bring the data.
The full fifteen-point spec continues with geometric precision. Start a new turn near the top of the viewport—this gives the new turn room to be read from the beginning. Then stream in the answer; the streaming answer can grow into the available space. Keep part of the previous conversation in context—enough of the previous turn should remain visible so the reader knows where they are. Let new content arrive offscreen; the conversation can keep streaming without changing what the reader is looking at. Show what's happening out of view; make it clear when a response is still streaming or when new messages have arrived. Make it easy to return to the latest reply; a "Jump to latest" action should bring the reader back and resume following. Let people jump anywhere in the conversation—long threads need message links, search, unread markers, and direct navigation. Reopen where the reader left off; a saved conversation should open at the last meaningful turn, usually the last user message, not the absolute bottom. Keep the reader's place when layout changes—images load, markdown expands, code blocks render, older messages appear above, none of that should make the reader lose their place. Handle interruptions without stealing position—stopping, retrying, regenerating, branching, or errors should not unexpectedly move the conversation. Stay responsive in long threads; streaming text, markdown, code, images, and long history should still feel responsive. Be accessible without the noise—keep the transcript navigable, preserve keyboard focus, and announce important events at a comfortable pace.
This is a UX heuristic precise enough to become an engineering contract—fifteen behaviors that define what makes a streaming chat interface feel right.
MessageScroller handles the parts that are easy to get wrong: anchored turns, streamed replies, saved thread restore, prepended history, jump-to-message, scroll controls, visibility tracking. It is unstyled and headless. It owns the behavior; you bring the data, transport, persistence, or model state. This is the codification layer made visible—a battle-tested pattern extracted from thousands of streaming chat implementations, compressed into a primitive that encodes judgment so you don't have to re-litigate "should auto-scroll be default" every sprint.
The infrastructure implication is the part that matters for teams shipping at scale. Design-system teams now maintain two contracts, with two audiences, optimized for radically different consumption patterns. The human contract is Figma files, Storybook instances, and prose documentation—visual artifacts designed for browsing, for inspiration, for judgment calls that require taste. The agent contract is flat YAML, semantic tokens, and markdown rationale—structured data designed for parsing, for deterministic lookup, for zero-ambiguity resolution.
The quality gates for each are fundamentally different. A Figma file is versioned by publish date; a DESIGN.md is versioned like source code, with commit hashes and semantic versions. A Storybook is validated by visual regression tests and designer review; a DESIGN.md is validated by whether the agent can consume it without inventing off-system values. A style guide PDF can drift from implementation for months before anyone notices; a DESIGN.md that falls out of sync breaks the build within a single session, because the agent cannot find the token it was told must exist.
This is the infrastructure layer arriving. Not the debate about whether designers should code—that question assumes the designer is the only consumer of the design system. Not the hand-wringing about AI reshaping taste or workflow—that presumes the output is still aimed solely at human judgment. This is the moment when design systems bifurcate into two parallel artifacts, each with its own format, its own versioning discipline, its own definition of "correct."
MessageScroller encodes fifteen streaming-chat behaviors into a headless primitive because those behaviors are now infrastructure, not product features—every team building a streaming interface needs them, and every team was getting at least three of the fifteen wrong.
The governance models diverge from here. A human-facing design system tolerates ambiguity; two designers can interpret "use primary sparingly" differently and both produce acceptable work. An agent-facing design system cannot tolerate ambiguity; "use primary sparingly" has no programmatic meaning, but "primary actions only; never more than one per screen" does. A human design system can evolve through conversation and critique; an agent design system evolves through explicit token additions and committed rationale, because the agent has no access to the Slack thread where the design team debated whether accent should be amber or orange.
The versioning splits as well. Figma is append-only in practice—old frames stay in the file, deprecated components linger in libraries, and "version 2.0" usually means "we made a new page." DESIGN.md versioning is append-never—deprecated tokens are removed, not hidden, because leaving them in the file means the agent might use them. When a token changes meaning, the file is updated and every agent session from that point forward reads the new contract. There is no grace period where both old and new values coexist. The agent does not read release notes.
The workflow instruction—"if a needed value is missing, add a named token to DESIGN.md and explain why"—is the mechanism that keeps the two contracts from drifting. The agent becomes a participant in design-system maintenance, not just a consumer. Every time it adds a token, it is proposing an extension to the system. Every time it writes a rationale, it is documenting a decision that future sessions will inherit. The design-system team's job shifts from "publish the canonical artifact" to "review and merge agent-proposed additions," which is a fundamentally different editorial posture.
This is not a distant-future scenario. Per AI Skill Market Blog, the DESIGN.md format is in production and teams are wiring it into repositories. The shadcn/ui chat primitives shipped as unstyled components for both Radix and Base UI, with examples live on the site. The fifteen-point UX spec is not aspirational—it is the contract that MessageScroller already implements. The workflow rule about never hardcoding one-off values is not a best practice—it is the instruction teams are embedding in CLAUDE.md files as standing context.
The infrastructure question is no longer whether design systems need a machine-parseable format. The infrastructure question is how design-system teams govern two parallel artifacts—one optimized for human browsing and judgment, one optimized for agent parsing and deterministic output—when the quality gates, versioning models, and update cadences for each are structurally incompatible. The answer that shipped is: you treat them as separate build artifacts with separate pipelines, and you accept that "correct" now has two definitions that will never fully converge.