SYSTEM Cited by 3 sources
Yelp CHAOS¶
Definition¶
CHAOS is Yelp's internal server-driven UI (SDUI) framework. The server authors a CHAOS Configuration (a bundle of views, layouts, components, and actions) per request; the client (iOS, Android, web) reads the configuration and renders a UI that the server fully determined. CHAOS was first introduced publicly in Yelp's 2024-03 post and the backend was unpacked in "Exploring CHAOS: Building a Backend for Server-Driven UI" (2025-07-08).
Surface area¶
- GraphQL API — a single CHAOS Subgraph in Yelp's
Apollo Federation supergraph.
Clients issue a
chaosConfiguration(name, context)query. - CHAOS REST API — the contract each CHAOS backend service implements; the subgraph routes to the backend for the requested view. Multiple teams run their own CHAOS backend, all conforming to this contract.
- Python Strawberry subgraph — the GraphQL-facing layer.
Build pipeline¶
Four layers, all named in the post:
ChaosConfigBuilder— request entry point; holds registered ViewBuilder classes and returns the final configuration.ViewBuilder— one class per logical view (view_id()== e.g.consumer.welcome). Selects the layout and declares optional subsequent views for
view flows.
3. LayoutBuilder — e.g. SingleColumnLayoutBuilder
(one main section) or mobile layouts with
toolbar/footer sections. Holds an ordered list of
FeatureProviders per section; order == render order.
4. FeatureProvider — one per product feature; produces
the components and actions that implement the feature.
Follows the six-stage
lifecycle —
registers → is_qualified_to_load → load_data →
resolve → is_qualified_to_present → result_presenter.
The build runs FeatureProviders in two parallel loops: loop 1 fires all async upstream requests, loop 2 waits on results and composes components. ("The latest CHAOS backend framework introduces the next generation of builders using Python asyncio, which simplifies the interface" — a future post will cover this.)
Element model¶
Components and actions are JSON strings inside a stable GraphQL schema (json-string-parameters-for-schema-stability):
ChaosJsonComponent{ identifier, componentType, parameters }— e.g.componentType: "chaos.button.v1"withparameters: "{\"text\": \"Find local businesses\", ...}".ChaosJsonAction{ identifier, actionType, parameters }— e.g.actionType: "chaos.open-subsequent-view.v1"withparameters: "{\"viewId\": \"consumer.view_two\"}".
Backend Python dataclasses (TextV1, ButtonV1,
IllustrationV1, OpenUrlV1, OpenSubsequentView,
ViewPlaceholderV1, …) type-check the element content before
serialisation.
Client capability matching¶
A FeatureProvider.registers returns a list of Register
entries, each carrying a Condition(platform=[...],
library=[...]) and a presenter_handler. First matching
condition wins; if no register matches the requesting client,
the feature is omitted from the response. This is how
Yelp keeps old app versions working while new components ship
— see
register-based-client-capability-matching.
Error isolation¶
Every FeatureProvider is wrapped in an error decorator
(error-isolation-per-feature-wrapper). An
exception in one feature drops that feature only; the rest
of the view still renders. Developers can flag a provider as
IS_ESSENTIAL_PROVIDER = True to opt out — if the feature is
"essential," its failure fails the whole view.
Failure logs include feature name, owner, exception details, and request context — used for threshold-based alerting and owner-team notification.
Advanced primitives¶
- View Flows —
ViewBuilder.subsequent_views()returns additional ViewBuilder classes whose output is packed into the same response'sviewsarray. Navigation happens locally viachaos.open-subsequent-view.v1actions — no network round-trip. Canonical example: Yelp for Business customer-support FAQ menu. See preloaded-view-flow-for-predictable-navigation. - View Placeholders —
ViewPlaceholderV1embeds a nested CHAOS view that the client fetches asynchronously after rendering the parent. Configurable loading / error / empty / header / footer component IDs and anestimatedContentHeightfor layout stability. Production example: Yelp for Business home screen embeds the Reminders feature (served by a different CHAOS backend) as a placeholder. See view-placeholder-async-embed.
Component vocabulary: Cookbook + Konbini¶
CHAOS serves UI components from Yelp's cross-platform design
system Cookbook. The
Konbini library family auto-
generates four platform-specific libraries (Kotlin, Swift,
Python, TypeScript) from a single JSON interface
definition per Cookbook component. Every CHAOS backend at
Yelp instantiates the same generated Python classes (e.g.
CookbookButton(text=..., style=..., on_click=..., size=...,
background_color=...)); those instances serialise to a JSON
wire format that Konbini-generated client libraries
deserialise into identically-shaped interface models. A
hand-written per-platform render extension
(CookbookButtonInterface.Render on Android Compose, etc.)
binds the deserialised model to the platform-native Cookbook
widget family. See
single-json-spec-to-multi-platform-codegen.
Konbini is also where CHAOS solves backward compatibility at component-version granularity (below the feature-level Register- based matching that operates at Register granularity):
- Each client bundles a
spec file listing the
component versions it supports (e.g.
android@23.0:{"cookbook.Button": "1.0", "cookbook.ButtonStyle": "0.1"}). - Every CHAOS request carries a Konbini context
(
spec_name@spec_version). - Backend picks the highest compatible component version per
spec; falls back to a
migrate()function to downgrade to the previous major when needed. - Major bumps
(e.g. Button
0.8 → 1.0whentext: Stringchanges totext: FormattedText) are the only trigger for a migrate function; additive changes are minor bumps requiring no backport.
See patterns/protocol-algorithm-negotiation and migrate-function-for-component-downgrade.
Hybrid usage: powering the Yelp Assistant chat¶
CHAOS is not always used to render a whole screen. In Yelp Assistant (2026-09-29 post) it runs in hybrid mode: the top bar and text-input bar are native, and only the scrolling chat content is server-driven. The team went hybrid because early CHAOS "doesn't provide affordances to send requests to the backend and support for text input fields did not exist at the time" — SDUI where it's strong (a dynamic list of heterogeneous messages), native where it's weak (text entry, network calls). This is the wiki's canonical hybrid-native-sdui instance.
Yelp Assistant exercises several CHAOS extension points:
- View/data separation — the client fetches the CHAOS view configuration once at launch as a template, then hydrates it turn-by-turn with data, rather than re-fetching the view each turn. "as the conversation progresses, the data hydrates the view."
- Datasets + MessageEvent — CHAOS datasets are the
client-side conversation store; "each entry in the dataset
represents a
MessageEvent," and CHAOS observes the datasets to keep the UI current. A small typed vocabulary (user_message,typing_indicator,bot_message,link_message,quick_replies) drives which component template renders each entry; ephemeral events (typing_indicator,quick_replies) are removed once no longer needed. - Custom CHAOS actions —
quick_replyis a Yelp-Assistant-specific CHAOS action (still a CHAOS action, but scoped to the chat screen) that routes a tapped quick-reply bubble back through the message-sending logic;open_url(built into CHAOS) navigates alink_message. - Client actions — the inverse of a CHAOS action: "executed
by the client on the backend's instruction." The first,
DisableChat, is sent in the bot's final response to remove the (native) input bar and end the session — a backend-driven handle on a native-owned surface. "The mechanism is flexible to support new actions as we require them." - Optimistic updates — on Send the client optimistically inserts the user message + a typing indicator into the dataset before the backend replies; the client owns removing the typing indicator on response or failure.
Known tradeoffs¶
- GraphQL schema stability bought at the cost of losing per-element schema validation in GraphQL introspection (payloads are opaque strings). Backend dataclasses and client-side renderers must agree out-of-band.
- Register-based capability gating is first-match and order- sensitive; correctness depends on most-specific-first ordering.
- Two-loop build pattern is a pre-asyncio design; an asyncio- native redesign is in flight.
- No disclosed operational numbers (latency, RPS, cache hit rates) — the post is an architecture walkthrough, not a retrospective.
Seen in¶
- sources/2025-07-08-yelp-exploring-chaos-building-a-backend-for-server-driven-ui — the backend deep-dive canonicalised by the wiki. The 2024-03 CHAOS introduction post has not been ingested.
- sources/2026-04-22-yelp-how-yelp-keeps-server-driven-ui-consistent-across-four-platforms
— follow-up unpacking Konbini + Cookbook, the
cross-platform codegen layer beneath CHAOS. Discloses the
{name, raw_value}design-token wire format, the spec-version negotiation for backward-compat, and themigrate()function pattern for component-version downgrade. - sources/2026-09-29-yelp-the-making-of-the-yelp-assistant-ui
— CHAOS in hybrid mode powering the Yelp Assistant chat:
native shell + server-driven content, view/data separation,
datasets + MessageEvent vocabulary, custom
quick_replyCHAOS action,DisableChatclient action, optimistic-update chat loop.
Related¶
- systems/apollo-federation — the GraphQL substrate
- systems/strawberry-graphql — Python subgraph library
- systems/yelp-konbini — the codegen bridge from Cookbook component interfaces to per-platform serialisation libs
- systems/yelp-cookbook — Yelp's cross-platform design system; CHAOS serves its components via Konbini
- systems/yelp-assistant — hybrid native + CHAOS chat app
- concepts/server-driven-ui — the architecture CHAOS implements
- concepts/optimistic-update — the Yelp Assistant chat loop's client-side UX
- register-based-client-capability-matching
- json-string-parameters-for-schema-stability
- client-spec-version
- component-version-migrate-function
- federated-graphql-subgraph-per-domain
- feature-provider-lifecycle
- two-loop-parallel-async-build
- error-isolation-per-feature-wrapper
- preloaded-view-flow-for-predictable-navigation
- view-placeholder-async-embed
- single-json-spec-to-multi-platform-codegen
- patterns/protocol-algorithm-negotiation
- migrate-function-for-component-downgrade
- companies/yelp