Effect Native keeps a closed, versioned catalog. Missing elements are tracked here instead of being added ad hoc. A gap may be accepted only when a real screen needs it and the change can land through every shipping renderer in the same catalog bump.
A component or catalog capability enters the public catalog only when all of the following are true:
- A named real screen demands it, described in public-safe generic language.
- A GitHub issue defines typed bounded props, intents, style contract, and non-goals.
- Implementations and tests land for every shipping renderer in the same change: headless, DOM, and React Native.
- The catalog version is bumped and compatibility tests are updated.
- The renderer conformance suite covers the new component or capability.
There is no plugin/custom-component escape hatch. Rejected gaps stay listed with their reason so pressure is visible without weakening the catalog contract.
The current catalog marker is effect-native/v43, exposed by
CatalogVersion. compatibleCatalogVersions is the decode allow-list, and
CompatibleViewSchema is the schema app authors and renderers should use when
accepting persisted or externally-authored trees.
When the catalog moves from vN to vN+1, the vN+1 compatible decoder must
still accept vN trees by adding a prior-version decoder/normalizer before the
version marker is changed. Unknown component tags remain typed decode failures;
they are not interpreted as extension points. This repository is pre-alpha, so
compatibility stays strict: support is explicit per listed catalog version.
The exhaustive non-audio source map lives in
docs/khala-ui-arwes-visual-parity.md.
KU-9 (#98) ships the full static foundation in v43: twelve owned frame motifs,
generic bounded grouping/compositing scene data, stepped/strip/separator paint
descriptors, inert DOM/React DOM SVG, and explicit React Native geometry or
degradation. Motion/choreography (#92) is shipped in the dedicated
@effect-native/khala-ui package. Final cross-renderer proof ships in #101:
30/30 non-audio parity rows have source-addressed gallery stories, executable
family receipts, renderer dispositions, and a React 19/Electron Scope bridge.
All four bounded Canvas background families ship through
@effect-native/render-canvas in #93 with deterministic seeds, quality/DPR/
memory/active-surface budgets, host-policy suspension, and exact Scope cleanup.
HTML/SVG illumination
ships in #100 with local events, frame coalescing, deterministic SVG IDs,
Scope cleanup, and static coarse-pointer/reduced-motion/native treatments. Text
sequence and decipher effects ship in #99 with a stable semantic layer and a
short-lived inert visual layer. They are grapheme-aware, deterministically
seeded, bounded, interruptible, and perform zero animation work under reduced
motion. Audio is rejected, not a gap.
The conformance suite is the mechanical enforcement for the growth rule. It
mounts, interacts with, styles, and unmounts catalog fixtures through every
shipping renderer. The suite is driven by componentTags, so a new tag fails
until it has a fixture and every renderer declares and proves support for it.
| Element or capability | Demanding screen | Date | Status |
|---|---|---|---|
| Link + typed navigation intent | Marketing landing page needs external links, route links, and in-page anchors | 2026-07-08 | shipped -> #10 |
| Responsive breakpoint variants | Marketing landing page must reflow across phone and desktop widths | 2026-07-08 | shipped -> #11 |
| Schema-backed forms | Marketing intake form and dashboard settings forms | 2026-07-08 | shipped -> #12 |
| Modal + Sheet overlays | Dashboard approvals and confirmation surfaces | 2026-07-08 | shipped -> #13 |
| Virtualized List + SectionList | Dashboard activity feed and grouped settings/history lists | 2026-07-08 | shipped -> #14 |
| Desktop host adapter | Khala Code Desktop needs the DOM renderer mounted inside an Electrobun webview with typed bridge/native services | 2026-07-08 | shipped -> #21 (@effect-native/platform-desktop: runMainDesktop, typed main/renderer bridge, headless Layer harnesses for menu/window/deep-link/single-instance; first consumer is the Phase 4 chat proof host) |
| Electron platform host | OpenAgents Desktop (openagents#8574) boots the DOM renderer inside a hardened Electron main/preload/renderer topology; the Electrobun destination assumed by #20/#21 is historical for that consumer | 2026-07-10 | shipped -> #69 (@effect-native/platform-electron: structural Electron*Like injection (no electron dependency), hardenedWebPreferences schema failing closed on any insecure flip, deny-by-default security-policy application, restrictive-CSP seam, packaged-fuses verifier, Schema-decoded typed IPC with a closed ok/refused envelope + sender-origin validation, frozen minimal preload bridge, renderer client decoding every response, SafeExternalOpener + Electron-backed layers over the reused platform-desktop service contracts, runMainElectronRenderer with foreign-host driver passthrough; 50 conformance/refusal tests) — docs/electron-host.md |
| Canvas scene renderer | Khala fleet board and gym panes need typed graph/timeline scenes over Three.js | 2026-07-08 | shipped -> #22 (@effect-native/render-canvas: closed scene-descriptor catalog effect-native/scene/v1, pure scene reconciler, Scope/Stream frame loop, headless backend, live Three.js backend via makeLiveThreeSceneGraph / makeLiveThreeCanvasBackend — closed mesh/line/points/label/group catalogue, Scope-bridged disposal, optional WebGL draw; depends on three. First catalog consumer GraphFigure #37. Apps may inject a custom ThreeSceneGraph port) |
Foreign Host node |
Monaco editor and terminal surfaces need one reviewed, typed escape hatch | 2026-07-08 | shipped -> #23 (v7: Host component with closed host-kind registry {code-editor, terminal, canvas}, serializable props, onEvent intent; DOM host-driver registry with Scope-bound mount/update/unmount; RN declares unsupported loudly). Contract doc: docs/foreign-host.md |
| Desktop interaction expansion | Composer, palette, transcript, drag/drop, focus, and scroll need typed keyboard/pointer/paste/drop/view-effect intents | 2026-07-08 | shipped -> #24 (v6: typed onKey/focus/pointer/paste/drag-drop intents, pinToEnd view effect, bounded a11y/roving-focus) |
| Protoss-blue dark theme | Khala Code Desktop is dark-only and pins the OpenAgents Khala CSS variable palette | 2026-07-08 | shipped -> #25 (@effect-native/tokens Khala dark theme maps exact OpenAgents Khala CSS-variable hex values onto shared token roles; desktop chat proof mounts it; no light/dark dual theme) |
| Streaming live binding | Transcript and fleet/gym state append/patch from recorded or live streams | 2026-07-08 | shipped -> #26 (runtime makeStreamRegion: keyed append reconciliation, frame-cadence coalescing via groupedWithin, Scope interruption, recorded patch sequence; no catalog bump) |
| App shell / split panes / nav rail | Khala Code Desktop chat shell needs sidebar, thread list, resizable workbench, and active pane switching | 2026-07-08 | shipped -> #27 (v10: SplitPane with typed panes + min/max/size + draggable divider reporting a bounded { paneId, size } onResize intent + dblclick collapse; NavRail sections/items with typed onSelect + active state; Workbench swapping active pane as typed state (keepMounted policy); DOM drag-resizable, RN static-divider fallback, headless records) |
| Popover / dropdown menu / context menu / tooltip | Command menus, settings menus, tooltips, and context menus in Khala Code Desktop | 2026-07-08 | shipped -> #28 (v11: Popover anchored surface (typed placement side/align, presence as typed open, Escape/dismiss intent, focus-first-on-open + focus-return-to-anchor-on-close); DropdownMenu/ContextMenu share a recursive typed MenuItem model (icon/disabled/danger/keybinding/submenu) with roving arrow-key focus + per-item onSelect, ContextMenu pointer-positioned via typed x/y; Tooltip wraps exactly one target with aria-describedby. DOM full a11y/keyboard; RN pressable-menu + accessibilityHint subset (placement declared unsupported); headless records) |
| Command palette / combobox | Khala command palette and slash-command autocomplete | 2026-07-08 | shipped -> #29 (v12: Combobox typeahead with app-supplied options (id/label/subtitle/icon/group/disabled+reason/keybinding), roving aria-activedescendant, typed onQueryChange/onHighlight/onSelect, loading + empty states, grouped rendering — no keyword routing in the component; CommandPalette composes a Combobox in the modal-overlay presence lifecycle (focus trap + return). DOM full combobox/listbox a11y + arrow/Enter keyboard; RN TextInput + pressable grouped options subset; headless records) |
| Tabs | Khala settings, workbench, and panel groups | 2026-07-08 | shipped -> #30 (v13: Tabs typed tab model (id/label/icon/disabled/badge) + typed selectedId state + onSelect intent, horizontal/vertical orientation, WAI-ARIA tablist/tab/tabpanel with roving tabindex + arrow/Home/End keyboard nav; panel association by id (data) with lazy vs keepMounted policy. DOM full a11y/keyboard; RN pressable segmented tab bar + active panel (roving nav declared unsupported); headless records) |
| Icon | Khala nav rail, command buttons, statuses, fleet controls, and menu items | 2026-07-08 | shipped -> #31 (v8: closed IconName set + iconSizes, per-renderer registries — DOM inline SVG/currentColor, RN font glyphs — typed decorative vs meaningful a11y) |
| Rich contenteditable composer | Khala chat composer needs multiline contenteditable text, slash commands, mentions, history, and attachments | 2026-07-08 | shipped -> #32 (v14: Composer over a typed structured document (bounded text runs + atomic mention chips), typed mode (normal/shell), typed attachment state, and named intents onChange/onSubmit/onKeyCommand/onAttachmentDrop with a closed key-command set (submit/newline/history-previous/history-next); autocomplete triggers (slash/mention) are typed data whose candidate list renders via the #29 Combobox. DOM owns the contenteditable surface, plaintext-normalized paste, and IME composition; RN maps to a multiline TextInput on the flattened document (inline chips declared unsupported); headless records) |
| CodeEditor host | Khala editor panel needs Monaco under the reviewed Host contract | 2026-07-08 | shipped -> #33 (typed CodeEditor constructor over the reviewed Host(kind: "code-editor") escape hatch (#23) — bounded serializable props (value/language/readOnly/wordWrap/minimap/token fontScale) + a typed change/selection/save event union; a documented minimal DOM driver makeStubCodeEditorDriver with Scope-owned mount/update/unmount lifecycle (real textarea-backed editor, swap in Monaco with the same contract). No new catalog tag / no version bump — Host already covers it since #23; a full Monaco bundle stays an app-level driver swap. Headless driver-lifecycle + unsupported-driver-marker tests) |
| Terminal host | Khala terminal panel needs a Scope-owned terminal host driver | 2026-07-08 | shipped -> #34 (typed Terminal constructor over the reviewed Host(kind: "terminal") escape hatch (#23) — bounded serializable props (output buffer, cols/rows, autoFit, token fontScale, scrollbackLines, readOnly) + a typed data/resize event union; output is delivered via the serializable output prop the app joins from a byte/string Stream (streaming runtime), input emitted as typed data, geometry as typed resize. Documented minimal DOM driver makeStubTerminalDriver with Scope-owned mount/update/unmount lifecycle + scrollback bound (swap in xterm with the same contract). No new tag / no version bump. Headless driver-lifecycle + bound-output + I/O test) |
| Transcript / Markdown | Khala transcript needs typed pre-parsed markdown, roles, tool cards, status indicators, and auto-pin behavior | 2026-07-08 | shipped -> #35 (v17: Markdown renders a typed, pre-parsed block+inline model (heading/paragraph/list/blockquote × text/code/strong/emphasis/link) to semantic HTML — no parser, no raw HTML; Transcript is a keyed, append-optimized aria-live log of typed message items (closed role/status sets) whose bodies are ordinary catalog views (Markdown, Card tool-cards, CodeBlock once #36 lands), with auto-pin-to-bottom + onPinnedChange. DOM semantic markup + scroll-region pinning; RN nested Text/View mapping + role-tagged bubbles; headless records. Streaming append is O(new) via the #26 stream region) |
| CodeBlock / unified diff | Khala transcript and review surfaces need pre-tokenized code and unified diff rows | 2026-07-08 | shipped -> #36 (v18: CodeBlock renders a typed pre-tokenized line model (closed token-kind set painted with the blue-theme syntax color tokens) with a language label, optional line numbers, and a typed copy intent; DiffView renders a typed pre-parsed unified-diff model (context/add/remove rows, old/new line gutters, hunks) with add/remove theming, unified/split layout, and diff-review affordances — typed per-line comment/verdict intents + source-control action intents, review state as data on the rows. The catalog ships no highlighter/diff parser (app-side, as Khala does). DOM + RN read-only render + review intents; headless records) |
| GraphFigure | Fleet board and gym arbiter graphs need canvas plus DOM/SVG fallback | 2026-07-08 | shipped -> #37 (v19: GraphFigure typed arbiter-graph model (nodes id/label/kind/status/position, edges endpoints/kind/status) with a typed layout policy (precomputed + deterministic named force/tree via shared layoutGraphNodes), typed pan/zoom camera state, and status→theme-token colors; named typed onNodeSelect/onNodeHover/onCameraChange intents. Two render paths under one contract: @effect-native/render-canvas's graphFigureToScene adapter maps the model onto the closed canvas scene descriptor (nodes→mesh+label, edges→line, camera→orthographic), exercised through the headless canvas backend; a DOM/SVG fallback renders the same typed model in a plain webview/gallery; RN a read-only selectable-node subset (edges/pan-zoom declared unsupported). Companion Timeline list of typed run events. headless records) |
| Settings form controls | Khala settings require toggle, select, checkbox, radio, slider, and number controls beyond the base FormSpec | 2026-07-08 | shipped -> #38 (v15: Toggle, Select, Checkbox, RadioGroup, Slider, NumberField each with typed value + typed onChange, disabled/invalid state, and an optional field FieldBinding that drives a #12 FormSpec field exactly like TextField; plus a FieldRow label+control+description+error layout. DOM native controls (switch/select/checkbox/radio/range/number) with aria-invalid; RN native equivalents (Slider drag declared unsupported); headless records) |
| Data display | Khala settings, fleet, usage, and review panes require table, chip/badge, meter/progress, divider, and stat tile | 2026-07-08 | shipped -> #39 (v9: Divider, Badge, Chip, Meter/Progress, StatTile, and non-virtualized Table with typed columns/keyed rows + onRowSelect; closed Tone set; DOM + RN + headless) |
| Toast / status banner / recovery overlay | Khala boot-degraded, update, recovery, and notification states | 2026-07-08 | shipped -> #40 (v16: Toast + ToastRegion (typed notification model id/tone/title/detail/action/autoDismiss, placement, aria-live role status/alert, renderer-scheduled auto-dismiss firing typed onDismiss); StatusBanner persistent inline tone+message+retry/dismiss; RecoveryOverlay full-surface blocking overlay on the modal presence lifecycle with typed recovery status + action intents. DOM full a11y/live-regions + focus trap + auto-dismiss timers; RN native live-region + pressable subset (auto-dismiss timing left to the runtime); headless records) |
| Hotkey registry / focus management | Khala global commands, palette scope, composer scope, recent-thread hints, and focus return | 2026-07-08 | shipped -> #41 (runtime makeKeymap + Keymap Layer: named commands (id/title/group/declarative when enablement/optional chord), chord→command resolution within a focus-scope stack so an overlay scope shadows a global binding, a scope stack that carries focus-return targets restored on pop, setContext enablement, platform-aware formatChord labels (⌘ vs Ctrl), same-chord-same-scope conflict diagnostics, and a rovingTabIndex focus helper. No component tags — no catalog bump. Deterministic headless key-stream test) |
| Icon set expansion + Apps SDK UI icon conventions | OpenAgents Desktop demand audit (harmonization audit §2.4/§5/§6-C5): the monorepo-vendored fork had 15 shell names upstream lacked (rendered via the OpenAI asset module) and the git panel/status/fleet/settings/file-tree/transcript surfaces fake glyphs with unicode text or ship icon-less buttons | 2026-07-14 | shipped -> #85 (v33: closed IconName set 16 → 101 semantic PascalCase names — desktop shell parity (Agent/Folder/Terminal/Settings/…) + arrows, status, git, files, edit actions, transcript actions, search, fleet/connectivity, account/security, payments, common chrome; every DOM glyph drawn in-house on the shared conventions — 1em × 1em, viewBox 0 0 24 24, currentColor, size from core iconSizeValues lowered as --en-icon-size-* (no reference-repo path data); RN text-glyph + SF Symbol registries complete for all 101; per-renderer registry-completeness tests; decorative/meaningful a11y contract unchanged; registry stays closed) |
| Sheet drag-to-dismiss gesture | Gesture demand not yet demonstrated beyond basic sheet presentation | 2026-07-08 | waiting |
| Overlay animation polish | Basic presentation shipped; richer transitions need a demanding screen | 2026-07-08 | waiting |
| DatePicker / DateRangePicker | None yet — no owned desktop/mobile/web screen demands calendar date entry (harmonization audit §5, #86); when a screen does, build on the SelectControl trigger conventions (#79) rather than a bespoke popover | 2026-07-14 | waiting |
| TagInput | None yet — no owned screen demands free-form tag entry (harmonization audit §5, #86) | 2026-07-14 | waiting |
Transition / Animate primitives (full Animate/TransitionGroup) |
None yet — the token side (named easing/duration tokens + data-entering/data-exiting lowering) ships via #76/#77; full animation primitives stay demand-gated (harmonization audit §5, #86; cross-reference the "Overlay animation polish" row above — either row's demanding screen can absorb the other) |
2026-07-14 | waiting |
| Avatar | Apps SDK UI harmonization P2.7 (openagents desktop-UI audit §5): OpenAgents Desktop sidebar accounts, fleet operator rows, and forum identity all hand-roll initials chips today | 2026-07-08 | shipped -> #80 (v34: Avatar with the typed fallback chain image -> bounded 1-3 char initials -> closed-set icon (at least one source required — an empty avatar is unconstructible), control-lattice size, closed tone set with soft/solid variants, typed decorative-vs-meaningful label; AvatarGroup with keyed child avatars, cutout-ring overlap (first on top), and a positive-integer max collapsing the remainder into a +N overflow count. DOM layers the img absolutely over the fallback so a load error reveals it with no renderer state; RN mirrors the layering honestly (a failed RN Image renders nothing). No remote fetching/identicon generation; presence dots stay composition via Badge) |
| SegmentedControl | Apps SDK UI harmonization P2.8 (openagents desktop-UI audit §5/§7, docs/fable 2026-07-14): OpenAgents Desktop settings panels and workbench mode switches hand-roll ad hoc button rows today where a single-choice segmented control belongs — distinct from Tabs (no associated panels) |
2026-07-14 | shipped -> #81 (v36: typed options (id/label/icon?/disabled?, minimum two), value + required onChange, control-lattice size (#76), gutterSize, pill. DOM renders an animated selection thumb reused across renders and positioned via ResizeObserver + getBoundingClientRect against the selected segment's live bounds, transitioning on the named move easing token (#76); WAI-ARIA radiogroup/radio semantics with roving tabindex and arrow/Home/End keyboard nav; component-token tier (#77) data-en-component="segmented-control"/data-en-size/data-en-pill re-point --en-segmented-* local vars. RN renders pressable segments with a static background highlight on the selected segment — no shared sliding thumb; declared as a real fidelity gap versus DOM, not a workaround, since this catalog carries no Reanimated/gesture-handler dependency) |
Media beyond Image (playback: src URLs, HLS, posters) |
None yet — the live-attach case split off and shipped as the media-video host kind below |
2026-07-08 | waiting |
media-video host kind (live MediaStream attach target) |
OpenAgents /sarah avatar surface: WebRTC/<video> attach for the owned renderer and the LiveAvatar fallback currently mounts in a sibling container outside the EN tree (#66) |
2026-07-09 | shipped -> #67 (v26: hostKinds gains media-video; typed MediaVideo constructor with bounded fit/muted/mirrored props + ready/ended/error event union; DOM makeMediaVideoDriver hands the app a Scope-owned <video> via onElement — the stream never crosses the serializable boundary; RN stays a loud unsupported marker until a native video driver is demanded) |
Glass set: IconButton, Toolbar, surface: "glass", Sheet native detents |
OpenAgents GL-1 (openagents#8647, epic #8646): Liquid Glass-era mobile surfaces need the semantic vocabulary in the upstream catalog while the @expo/ui native-island lowering lands monorepo-side |
2026-07-09 | shipped -> #70 (v27: IconButton over the closed icon set with required a11y label; Toolbar floating action strip; style-level surface: "glass" on box-derived styles — DOM translucent bg + backdrop blur, RN honest translucent-surface + hairline-border approximation; optional Sheet.presentationDetents "half"/"full" pass-through; high-fidelity iOS Liquid Glass stays in the @expo/ui lane, not this dependency-free catalog) |
| Transcript message chrome + composer submit lifecycle | OpenAgents Desktop shell (openagents#8574): the first chat surface rendered sender labels as body-concatenated text ("SHELLOpenAgents…", "YOUrofl") and a focused composer never received the app's controlled submit reset, so the input did not clear on submit | 2026-07-10 | shipped -> #72 (v29: TranscriptMessage gains typed senderLabel/timestamp display strings drawn in a meta row separated from the body, with role-differentiated row treatment — user end-aligned bounded bubble, assistant start-aligned prose, system/tool muted (per the Khala Code design source); TextField gains disabled + clearOnSubmit; Composer gains disabled/submitting/clearOnSubmit — submitting keeps typing live for follow-up drafting but suppresses onSubmit while the typed "submit" key command still fires; DOM controlled-value sync fixed so focused fields/editors apply app-driven value resets without clobbering in-progress typing; RN rides the controlled value. No new tags) |
| RN transcript message width discipline | OpenAgents mobile simulator receipts showed long chat bubbles exceeding the viewport because the percentage-constrained message was the direct FlatList-cell child | 2026-07-10 | shipped -> #73 (unchanged v29 contract; RN lowering uses a full-width role-aligned row plus minWidth: 0 / flexShrink: 1 on the 82%-bounded message, with a 4 KiB unbreakable-token regression) |
| Markdown link href: same-origin relative paths | OpenAgents Forum routes (openagents#8635): thread permalinks /forum/t/<id>#post-<id>, profiles, docs, receipts are same-origin links the URI-gated href rejected, forcing an app-side origin-resolution workaround |
2026-07-10 | shipped -> #71 (v28: MarkdownLinkHrefSchema — closed grammar http(s)://… | rooted path /p?q#f (leading // rejected) | #fragment; deliberately tightens schemes to http(s) only — the prior gate ^[a-z][a-z0-9+.-]*: admitted any scheme including javascript:/data:; those and mailto:/custom schemes are now typed failures. Renderers unchanged: DOM emits the href verbatim, RN link-role text. The preferred NavigationDestination-carrying link (issue option 2) stays open as future unification demand) |
RN host-driver registration seam + internal @expo/ui glass lowering + glass-chrome icons |
OpenAgents GL-1 (openagents#8647): the D-MB-02 SwiftUI Liquid Glass island must convert to catalog Host-kind mounting, and the v27 glass set needs a REAL high-fidelity lowering (SwiftUI Liquid Glass) without app code importing @expo/ui |
2026-07-10 | shipped -> #70 ask 2 (render-rn ReactNativeHostDriver + makeReactNativeHostRuntime: Scope-bound mount/render/sweep/dispose mirroring the DOM driver contract, Schema-decoded props failing closed to loud markers, emit → typed Host onEvent intents) + v30 (IconName gains Menu/Compose/Mic/Sparkles; render-rn-INTERNAL @expo/ui/swift-ui lowering for glass IconButton/Button/Toolbar/glass Stack containers on iOS 26+ — SF Symbols, glassEffect circle/capsule/roundedRectangle, typed intents preserved; honest RN material approximation stays everywhere else, incl. iOS < 26 where @expo/ui glass would no-op dishonestly; @expo/ui is an optional render-rn peer dep — app code never imports it). #70 is resolved: its concrete demand shipped; the broader render-swiftui idea is deferred until a new screen supplies bounded per-component evidence. |
| Streaming transcript with partial-utterance updates | OpenAgents /sarah voice transcript (#66) — role-tagged live-append list with in-place partial updates |
2026-07-09 | already shipped -> #35 + #26 (keyed Transcript messages with the closed thinking/streaming/failed/done status set update in place; live append rides makeStreamRegion; no new component needed — demand recorded so the consumer converts off List+Card) |
| GraphFigure provenance vocabulary (badges, chips, entry policy, evidence edges) | OpenAgents /sarah Blueprint map (#68, openagents#8628): domain-neutral fact/need/offering/account semantics, inline provenance/evidence refs, entry treatment for live-arriving nodes, and provenance-backed links distinct from generic statuses |
2026-07-09 | shipped -> #68 (v31: node badge (label + closed tone), typed chips (provenance/evidence/datum + opaque ref) dispatching onChipSelect { nodeId, chipId, ref? }, typed nodeEntry policy (none/fade/pop — DOM marker attribute + guarded Web Animations, never on first paint; RN/canvas declared no-op), evidence_backed edge status -> accent token + heavier stroke across DOM/RN/canvas; v30 trees still decode) |
| Mic state + audio level indicator | OpenAgents /sarah push-to-talk / VAD UI (#66): typed idle/live/denied/muted mic state plus a 0..1 level meter |
2026-07-09 | waiting (proposal: MicIndicator with closed state set + level; Meter/Badge (#39) compose an interim; enters when the demanding screen actually wires PTT/level metering) |
| Handoff / checkout / receipt cards | OpenAgents /sarah sales tool effects (#66): typed cards for human-handoff, checkout link, and payment receipt |
2026-07-09 | waiting (today honestly composed from Card+Text+Button — catalog-blessed composition, not a workaround; a typed card family enters when a second surface demands the same shapes) |
| First-contact AI disclosure banner | OpenAgents /sarah (#66): persistent AI-disclosure notice on first contact |
2026-07-09 | covered -> #40 StatusBanner (persistent inline tone+message is the disclosure shape; no separate component unless regulatory fields — jurisdiction copy slots, ack intent — become real demand) |
| Utility style aliases | Authoring friction not yet demonstrated by a real screen | 2026-07-08 | waiting |
| Monospace / whitespace-preserving text style | effectnative.org's home-page and doc code samples (#19) need indentation-preserving display; worked around today with one Text per source line in a Stack instead of a single multi-line string |
2026-07-08 | waiting -> related to #36 CodeBlock (syntax-highlighted blocks shipped; plain multi-line monospace Text style still open) |
| React Native pixel visual-baseline capture | Testkit visual baselines (#16) ship a typed VisualCapture contract plus a structural-snapshot default and a real DOM-renderer capture (@effect-native/testkit/visual); a native RN pixel-capture harness (e.g. a detox/maestro-style screenshot rig) is undemonstrated |
2026-07-08 | shipped -> #59 (rnVisualCapture structural RN baseline keyed by platform; detox/maestro pixel remains a plug-in VisualCapture implementation) |
| Full Khala Code Desktop shell cutover | Production desktop shell still needs the composed proof of chat + fleet/gym canvas + owner cutover steps | 2026-07-08 | shipped -> #42 (chat + fleet GraphFigure/Timeline + settings strip + oracle; live Electrobun packaging remains operational follow-through); docs/proof-desktop.md |
| Marketing section primitives | openagents.com production landing (WEB-1) needs typed Section/Hero/AnnouncementBadge/CTASection/Footer rather than ad-hoc Stack trees | 2026-07-09 | shipped -> #46 (v20) |
| Marketing NavBar | openagents.com landing header — horizontal top-nav distinct from app-shell NavRail | 2026-07-09 | shipped -> #47 (v20) |
| Accordion / FAQ | Landing FAQ and disclosure lists | 2026-07-09 | shipped -> #48 (v20) |
| PricingTable / PricingColumn | Landing plan comparison | 2026-07-09 | shipped -> #49 (v20) |
| LogoRow + StatsBand | Landing social proof and metric band | 2026-07-09 | shipped -> #50 (v20) |
| Glow + MockupFrame | Landing hero mockup with launch-ui-style glow/tilt treatment | 2026-07-09 | shipped -> #51 (v20) |
| RN renderer parity (close the declared-subset / unsupported matrix) | Khala Code Mobile needs faithful RN mappings for overlays, SplitPane, Combobox, Tabs, Composer mention chips, Slider, GraphFigure, and drag — shipped desktop-first as RN subsets |
2026-07-09 | shipped -> #53 (Modal overlays+placement a11y, SplitPane step resize, Combobox FlatList listbox, CommandPalette Modal, Tabs a11y step, Toast auto-dismiss, GraphFigure camera steps, voice/on-device Host surfaces; continuous gesture-drag residue stays host-optional) |
| Mobile host adapter | Khala Code Mobile needs the RN renderer owned by a mobile host: runMainMobile, app lifecycle, push token, notification-tap + deep-link intents, safe-area/keyboard runtime |
2026-07-09 | shipped -> #54 (@effect-native/platform-mobile: runMainMobile, typed Layers + headless harnesses for AppLifecycle/PushToken/Notifications/DeepLink/SafeArea/Keyboard; peer of platform-desktop #21) |
| Mobile navigation adapter | Khala Code Mobile's drawer + native-stack + modal navigator and khala:// deep links need typed navigation intents |
2026-07-09 | shipped -> #55 (Navigation service + reduceNavigation + deepLinkToNavigationAction in @effect-native/platform-mobile) |
| Mobile gesture / interaction expansion | Khala Code Mobile's swipe-to-quote, pull-to-refresh, long-press, keyboard-avoidance, and safe-area need typed touch intents + runtime concerns (the mobile peer of desktop interaction expansion #24) | 2026-07-09 | shipped -> #56 (v25: interactions.onLongPress/onSwipe/onPullToRefresh; RN long-press + a11y swipe actions; safe-area/keyboard via platform-mobile #54) |
| RN list virtualization parity | Khala Code Mobile's thread list + streaming transcript need FlatList/SectionList-backed List/SectionList/Transcript at production scale |
2026-07-09 | shipped -> #57 (FlatList windowing defaults on List/SectionList; Transcript FlatList + pin/maintainVisibleContentPosition) |
RN foreign-Host drivers |
Khala Code Mobile's voice/STT mic and on-device model surfaces need reviewed Scope-owned RN host drivers under the Host contract (#23) |
2026-07-09 | shipped -> #58 (voice-input + on-device-model host kinds + VoiceInput/OnDeviceModel constructors; RN still loud-marker until app drivers register) |
SwipeableListItem |
Khala Code Mobile's thread rows need swipe-action list rows | 2026-07-09 | shipped -> #60 (v23: leading/trailing actions, onAction, fullSwipeActionId; DOM + RN action reveal subset; gesture-native reveal still #56) |
PullToRefresh / RefreshControl |
Khala Code Mobile's thread list refreshes on pull | 2026-07-09 | shipped -> #61 (v22: bounded refreshing + onRefresh on List/SectionList; RN RefreshControl, DOM refresh affordance) |
Pager / onboarding stepper |
Khala Code Mobile's 3-step onboarding is a linear paged flow (distinct from Tabs selection) |
2026-07-09 | shipped -> #62 (v21: linear steps, activeStepId, progress dots/bar, back/advance/complete intents; DOM + RN) |
| Mobile surface treatments | Khala Code Mobile's arcade visual identity: BackgroundGradient/Wallpaper/Spotlight/Frame/BlurredPopup (signature visuals as catalog citizens, like Glow/Mockup #51) |
2026-07-09 | shipped -> #63 (v24 surfaces; v25 current after gestures) |
| OpenAgents mobile Effect Native conversion proof | Core mobile screens authored once as typed EN data on iOS + Android; shared Desktop/mobile transcript intent and Khala Sync protocol convergence; real active-consumer pixels on both platforms | 2026-07-09 | shipped -> #64 (framework UI/oracles + protocol-honest dual-session proof; active OpenAgents mobile production app has real iOS and Android simulator build/pixel/interaction receipts; live staging remains a product dogfood gate, not a framework conversion gate — see docs/proof-mobile.md) |
| EmptyMessage empty-state block | OpenAgents Desktop history/workspace/fleet panes each hand-roll their empty states today (harmonization audit §5/§7 Phase 2.9, openagents#8712 lineage) — the definition of a composition one-off | 2026-07-14 | shipped -> #82 (v32: optional icon badge over the closed IconName set with its own bounded tone secondary/danger/warning and size sm/md vocabularies, required title, optional muted description, and an optional action slot typed as a Button view specifically — an arbitrary view there is a typed decode failure; centered-column layout on spacing tokens; DOM icon-badge SVG + role-tagged nodes, RN glyph badge + testID-tagged nodes, headless records. Non-goals held: no illustrations/images, no loading state — Spinner/Shimmer shipped -> #83) |
| CopyButton (typed copy-to-clipboard control + injected Clipboard service) | OpenAgents Desktop transcript message actions and diagnostics panel (harmonization audit §5/§7 Phase 2.11): code and message surfaces beyond CodeBlock's built-in copy intent hand-roll copy affordances today | 2026-07-14 | shipped -> #84 (v35: CopyButton — content string, optional label (icon-only IconButton-shaped default vs Button-shaped icon+label), size on the shared control lattice, variant on the existing Button vocabulary (full tone×variant matrix stays a later issue), typed onCopy intent carrying the copied content; copied-state feedback = Check icon swap + copiedLabel tooltip/polite live announcement with typed resetMillis (default 2000ms); clipboard access ONLY through the injected Clipboard service/driver (Context.Service + makeClipboardLayer, renderer option or Layer — never bare navigator.clipboard in the contract). DOM: navigator-backed default driver + renderer-owned uncontrolled feedback timers; RN: injected-driver write or honest declared subset (fires onCopy so the app writes; uncontrolled self-feedback unsupported — controlled copied + renderer-scheduled onCopiedReset is the parity path, Toast precedent); headless records every write (clipboardWrites, simulateCopy). IconName gains Copy) |
| Spinner + LoadingDots + ShimmerText loading indicators | OpenAgents Desktop demand audit (harmonization audit §5/§7 Phase 2.10, openagents docs/fable 2026-07-14 audit): Desktop transcript streaming states and tool-card wait states hand-roll pending affordances today; Indicator (LoadingIndicator/Dots/CircularProgress) was GAP against Apps SDK UI's Indicator family | 2026-07-14 | shipped -> #83 (v38: Spinner indeterminate ring + LoadingDots 3-dot pulse, both sized off the control-lattice icon sub-token (#76) with the closed Tone set; ShimmerText sweeps real pending text (text) or a skeleton placeholder (width) — at least one required, mirroring the Avatar fallback-chain discipline. Determinate circular progress stays a Meter variant (not duplicated). New MotionPreferenceService (mirrors ViewportService) + ViewResolution.reducedMotion resolve prefers-reduced-motion once at the DOM mount boundary (live via the media query's own change event) and bake it into the typed reduceMotion field unless the app overrides it — no component checks a media query itself; DOM gates @keyframes animation behind a resolved data-en-motion="auto"\|"reduced" attribute, reduced renders identical static markup. RN renders all three as an honest static affordance unconditionally (first continuously-animating catalog components; no Animated dependency exists yet in this dependency-free catalog) — a live native loop is an additive, demand-gated follow-up, not a gap in this contract. DOM + RN + headless fixtures, conformance, dedicated component tests) |
| Matrix axes on Badge/Chip/TextField/Select + a new Alert component | Apps SDK UI harmonization P1.6 (openagents desktop-UI audit §5/§7): the remaining PARTIAL rows from the audit's component parity map — Badge/Chip/TextField/Select still lacked the tone×variant×size conventions Button (#78) established, and StatusBanner had no icon+title+body callout shape for inline validation/warning content | 2026-07-14 | shipped -> #79 (v39: Badge/Chip variant (solid/soft/outline) + lattice size; TextField variant (outline/soft), lattice size, gutterSize, invalid, multiline autoResize (Textarea parity); Select SelectControl trigger conventions — variant (soft/outline/ghost), lattice size, pill, dropdownIcon — plus additive multi-select (multiple/values); new Alert component (icon + title + body on the tone×variant matrix) rather than reshaping StatusBanner, whose narrower persistent-banner contract stays completely unchanged. Every new axis is opt-in: each resolver's isLegacy flag gates the new chrome so every pre-#79 tree keeps decoding and rendering identically. Select's React Native rows-list rendering has no trigger to attach dropdownIcon to — a declared fidelity gap, same posture as SegmentedControl's RN thumb-animation gap) |
| Application-chrome token vocabulary (state overlays, dim ladder, overlay surface, motion / elevation / control-lattice groups) | OpenAgents Desktop chrome design pass (openagents#8712): every non-message surface ports the apps-sdk-ui chrome language and needs typed hover/active/selected overlay fills, a textFaint/textDisabled/textInverse dim ladder, surfaceOverlay/scrim overlay surfaces, borderSubtle/borderStrong border steps, accentHover/accentActive solid steps, and shared motion/elevation/control metrics | 2026-07-11 | shipped (@effect-native/tokens: 12 new color roles plus motion/elevation/control groups on ThemeSchema with values in both themes; render-dom lowers them as --en-motion-*/--en-ease-*/--en-elevation-*/--en-control-* custom properties and ships a shared chrome base ruleset — the alpha-overlay state engine (hover/active/selected are translucent overlays of one base color, never new hues), 150ms basic transition, press-scale feedback, one focus ring, nav-item chrome, token-derived thin scrollbars. Theme-level only: no new component tags, no catalog bump) |
Mobile demand docs (#65): GAPS register rows + ROADMAP Phase 4M + docs/porting-map-mobile.md shipped.
| Marker | Issue | What landed |
|---|---|---|
v6 |
#24 | Desktop interaction intents (key/focus/pointer/paste/drag-drop, pinToEnd) |
v7 |
#23 | Foreign Host node + closed host-kind registry |
v8 |
#31 | Icon closed name set |
v9 |
#39 | Data display (Divider, Badge/Chip, Meter, StatTile, Table) |
v10 |
#27 | App shell (SplitPane, NavRail, Workbench) |
v11 |
#28 | Anchored overlays (Popover, DropdownMenu, ContextMenu, Tooltip) |
v12 |
#29 | Combobox + CommandPalette |
v13 |
#30 | Tabs |
v14 |
#32 | Composer |
v15 |
#38 | Settings form controls |
v16 |
#40 | Feedback surfaces (Toast/ToastRegion, StatusBanner, RecoveryOverlay) |
v17 |
#35 | Markdown + Transcript |
v18 |
#36 | CodeBlock + DiffView |
v19 |
#37 | GraphFigure + Timeline (canvas + DOM/SVG) |
v20 |
#46–#51 | Marketing landing catalog (Section, Hero, AnnouncementBadge, CtaSection, Footer, NavBar, Accordion, PricingColumn, PricingTable, LogoRow, StatsBand, Glow, MockupFrame) |
v21 |
#62 | Pager (linear onboarding stepper) |
v22 |
#61 | Pull-to-refresh on List/SectionList (refreshing + onRefresh) |
v23 |
#60 | SwipeableListItem (swipe-action list rows) |
v24 |
#63 | Mobile surfaces (BackgroundGradient, Wallpaper, Spotlight, Frame, BlurredPopup) |
v25 |
#56 | Mobile gesture intents on Interactions (onLongPress/onSwipe/onPullToRefresh) |
v26 |
#67 | media-video host kind (live MediaStream attach target) |
v27 |
#70 | Glass set (GL-1, openagents#8647): IconButton, Toolbar, style surface: "glass" on box-derived styles, Sheet.presentationDetents |
v28 |
#71 | Markdown link href grammar (openagents#8635): same-origin rooted paths + #fragment refs accepted; schemes tightened to http(s) only (javascript:/data:/mailto:/custom schemes are typed failures) |
v29 |
#72 | Chat chrome + submit lifecycle (openagents#8574): TranscriptMessage senderLabel/timestamp meta row + role-treated rows; TextField/Composer disabled/submitting/clearOnSubmit; DOM focused controlled-value sync |
v30 |
#70 | Glass-chrome icons (GL-1 openagents#8647): IconName gains Menu/Compose/Mic/Sparkles; render-rn-internal @expo/ui SwiftUI Liquid Glass lowering for the glass set on iOS 26+ (SF Symbols; honest material fallback elsewhere); RN Scope-bound host-driver registry (#70 ask 2) ships alongside (non-catalog runtime seam) |
v31 |
#68 | GraphFigure provenance vocabulary (Sarah Blueprint map, openagents#8628): domain-neutral node badge (label + tone), typed chips (provenance/evidence/datum + opaque ref) with the onChipSelect payload intent, typed nodeEntry policy (none/fade/pop — DOM applies, RN/canvas declared no-op), and the evidence_backed edge status mapped to the accent token across DOM/RN/canvas |
v32 |
#82 | EmptyMessage (desktop harmonization P2.9, openagents docs/fable 2026-07-14 audit §5/§7): typed centered empty-state block — optional icon badge over the closed IconName set with bounded tone (secondary/danger/warning) and size (sm/md), required title, optional muted description, and an action slot typed as a Button view specifically; DOM + RN + headless |
v33 |
#85 | Icon expansion (desktop harmonization P2.12, openagents docs/fable 2026-07-14 audit §2.4/§5/§6-C5): closed IconName set 16 → 101 semantic PascalCase names (desktop shell parity + arrows/status/git/files/edit/transcript/search/fleet/account/payments/chrome); Apps SDK UI conventions — 1em × 1em box, viewBox 0 0 24 24, currentColor, size from core iconSizeValues lowered as --en-icon-size-*; own-drawn DOM glyphs, complete RN text-glyph + SF Symbol registries, per-renderer completeness tests |
v34 |
#80 | Avatar + AvatarGroup (harmonization P2.7): typed image -> initials -> icon fallback chain, control-lattice sizes, Tone soft/solid variants, cutout-overlap groups with max/overflow count; v33 trees still decode |
v35 |
#84 | CopyButton (harmonization audit Phase 2.11, Desktop transcript message actions + diagnostics panel): typed copy-to-clipboard control over the injected Clipboard service (Layer/renderer-option seam; navigator-backed DOM default; headless records writes), IconButton-shaped icon-only default vs labelled Button shape, control-lattice size, Button variant vocabulary, typed onCopy/onCopiedReset intents, copied-state Check swap + copiedLabel announcement with typed resetMillis; IconName gains Copy |
v36 |
#81 | SegmentedControl (harmonization P2.8): single-choice INPUT control distinct from Tabs (no panel association) — typed options (id/label/icon?/disabled?), value + onChange, control-lattice size, gutterSize, pill; DOM animated sliding thumb measured via ResizeObserver against the selected segment's live bounds using the #76 named move easing token, WAI-ARIA radiogroup/radio semantics with roving tabindex + arrow/Home/End keyboard nav; RN pressable segments with a static (non-animated) selection highlight (declared fidelity gap vs. DOM's shared thumb); v35 trees still decode |
v37 |
#78 | Button full tone x variant x size matrix (harmonization P1.5): tone (6 matrix tones, default accent), variant (solid/soft/outline/ghost, default solid), size (control lattice, default md), pill, loading, block, selected; DOM lowers tone/variant/size to data-en-* attributes re-pointing --en-button-* vars from the --en-matrix-*/control-lattice vars (#75/#76/#77), RN resolves the same matrix cell directly; pre-v37 variant: "primary"|"secondary"|"ghost" trees still decode and normalize onto their exact tone+variant equivalents via resolveButtonAppearance ("primary" -> accent/solid, "secondary" -> secondary/solid, "ghost" -> accent/ghost, unchanged) |
v38 |
#83 | Spinner + LoadingDots + ShimmerText (harmonization P2.10): indeterminate loading indicators for Desktop transcript streaming states and tool-card wait states — control-lattice-sized Spinner/LoadingDots on the closed Tone set, ShimmerText sweeping real pending text or a skeleton placeholder width; determinate progress stays a Meter variant; typed reduceMotion resolved by the new MotionPreferenceService/ViewResolution.reducedMotion (DOM detects prefers-reduced-motion once at mount, RN renders an honest static affordance unconditionally); v37 trees still decode |
v39 (current) |
#79 | Matrix axes on the remaining PARTIAL components (harmonization P1.6): Badge/Chip gain variant (solid/soft/outline) + lattice size via resolveBadgeAppearance; TextField gains variant (outline/soft), lattice size, gutterSize, invalid, and (plain/non-secure only) autoResize (DOM grows a multiline field to its scrollHeight; RN already grows with no fixed height, a declared no-op) via resolveTextFieldAppearance; Select gains SelectControl trigger conventions — variant (soft/outline/ghost, no solid), lattice size, pill, dropdownIcon — via resolveSelectAppearance, plus additive multi-select (multiple/values); a new Alert component (icon + title + body on the full tone x variant matrix, via resolveAlertAppearance) joins the catalog rather than reshaping StatusBanner in place (see the AlertView doc comment and docs/guide/07-catalog-reference.md's ### Alert section for the decision). Back-compat: every resolver's isLegacy flag (true only when the caller sets none of the new axis fields) gates all new chrome, so pre-v39 trees keep decoding and rendering byte-for-byte identically; v38 and v37 trees still decode. React Native's rows-list Select has no trigger to attach dropdownIcon to — a declared fidelity gap alongside SegmentedControl's RN thumb-animation gap. Per-component style-key allowlists were deliberately NOT tightened in this bump: Badge/Chip/TextField/Select's existing style.backgroundColor/borderColor/borderWidth keys remain valid because the pre-v39 (isLegacy) rendering path still depends on them for manual box styling, and removing them would itself be a breaking API change — the same call the v37 Button bump made (buttonStyleKeys was left unchanged) |
Non-catalog Phase 4 runtime ships (no version bump): desktop adapter (#21), canvas renderer package (#22), streaming region (#26), Keymap/focus (#41), Protoss-blue theme tokens (#25), Electron platform host (#69).
Non-catalog Phase 4M runtime ships (no version bump): mobile adapter (#54), navigation adapter (#55), list virtualization parity (#57), host kinds voice/on-device (#58), RN visual capture (#59).