<!-- Once this directory changes, update this README.md -->

# Features/Chat

Renderer-side view layer for chat.
Streaming updates arrive as AI SDK `UIMessageChunk` frames through a chat-owned transport abstraction. Ordinary web runtime uses server SSE directly. Electron Desktop runtime uses `window.cradle.chatStream`, where Electron main owns the long-lived upstream server SSE connection and renderer windows consume IPC fanout. Initial hydration and reload/recovery read trusted `UIMessage` snapshots through React Query and project locally into Zustand. Terminal snapshot rows are also mirrored into a Cradle-owned IndexedDB cache so remounting a previously opened session can restore stable transcript content before the canonical server snapshot request returns; streaming rows never enter that cache.
Passive windows hydrate the current message snapshot first, then subscribe through `chat-stream-transport.ts` for active-run AI SDK chunks instead of polling snapshots while a message is streaming. Web runtime uses the multiplex `/sync` WebSocket when enabled and otherwise calls `GET /chat/sessions/{sessionId}/stream`; Electron Desktop subscribes to the main-process broker so multiple windows share one upstream stream. The WebSocket client owns ping/pong deadlines, socket generations, reconnect backoff, and exactly-once subscription registration. Run chunks resume only from the last accepted `{ runId, cursor }`; if that cursor was evicted while the run remains active, the server sends a transient `data-cradle-stream-snapshot` followed by later live chunks on the same subscription. `ChatStreamingHandler` restores the Cradle-owned AI SDK stream state from that snapshot, including active text/reasoning part ids, so subsequent deltas continue the current assistant instead of failing into an empty history shell.
Codex active goals can create server-owned system continuation runs after a previous run fails or idles without user cancellation. Chat Runtime event-tail invalidation refreshes `/runtime-status` and message snapshots when run or interaction facts change, and `use-chat-session.ts` refreshes message snapshots when runtime status exposes an active run message id that is not yet hydrated. Once the new streaming assistant row appears in the snapshot, the existing passive session-stream join path consumes the new run; no visible internal user message is added to chat history.
Text/reasoning/file parts hydrate as `UIMessage.parts`. Chat-owned structured context parts such as `$`-selected Skills are also stored in `UIMessage.parts` under the `data-cradle-*` namespace, rendered inline with the user prompt, and projected only by providers that understand them. Tool calls also stay in `UIMessage.parts`; chat render plans derive transient `messageId + partIndex` refs for subscriptions, but no browser-owned mirror stores tool payload by `toolCallId`.
The store preserves raw AI SDK `UIMessage.parts` as the message-history source of truth. Tool UI reads fields such as `approval`, `input`, `providerExecuted`, output state, and provider-specific payload directly from the current tool part so native AI SDK approval continuation and Cradle Tool UI standardization evolve on the same message boundary.
Native AI SDK tool approvals render inline from tool parts with `state: "approval-requested"`. Approve/deny actions update the tool part to `approval-responded`, use AI SDK `lastAssistantMessageIsCompleteWithApprovalResponses`, and continue by sending the complete `messages` history through the existing chat response endpoint. Runtime-owned approval requests use the same inline buttons but submit to Chat Runtime's pending tool-approval endpoint so the active provider request can resume. Codex app-server approvals are identified by standardized `approval.*` tool payloads; Claude Agent `canUseTool` approvals are identified by the Claude Code builtin tool envelope. Neither path uses the deleted independent approval stream.
Claude Agent `TodoWrite` state is synthesized by the server adapter into persisted tool output `pluginState.todos`. Chat store selectors reverse-scan raw `UIMessage.parts` for the latest plugin state and render it in Right Aside runtime surfaces; inline `TodoWrite` blocks may still project directly from tool args while the call is running. The TODO shared vocabulary is `todo` / `processing` / `completed`, with processing text read from `activeForm`. Codex app-server plan/file/MCP/web tool items render through the same classified tool block surface. Chat Runtime access and interaction controls are Cradle-owned `runtimeSettings`: the Composer control persists session defaults through `/runtime-settings`, sends loaded defaults with new turns and queue items, and lets active providers apply live updates through their runtime side-channel.
Provider-owned UI slot state is consumed by the surface declared by the provider. Composer-adjacent persistent rendering is reserved for slots with `composerState`, such as Codex goal, Codex plan-ready actions, and Codex background terminal controls; ChatGPT account usage is a slash-triggered composer rail opened by `/usage` and closed by the user, while its unavailable state remains visible as a disabled slash command row when no provider state exists. Snapshot-style runtime metadata such as status, model, reasoning, MCP, alerts, skills, plugin, and config must not render as chips above the input or as synthetic message-bubble content. Message-stream events that need transcript placement should arrive as stream evidence or persisted message/tool parts instead of polled UI slot state. Codex compact state separates context-compaction lifecycle from thread token-usage meter state, so the `/compact` row can show running/completed lifecycle and current usage as an icon-ring state plus inline copy like `(used 52%)` without Cradle owning compaction semantics. Picker-style state such as model, reasoning, and config stays in existing model-picker, runtime-panel, or diagnostics surfaces, not by fake `/model` or `/reasoning` slash commands. Right Aside Runtime renders Cradle-owned workflow summaries such as Plan/TODO progress, run status, tools, and chat attention; Dev-only runtime environment diagnostics render from a top-right resource-style popover.
`/btw` is provider-owned quick-question UI exposed through a runtime `quick-question` slot with `slashCommand` and `composerState` surfaces. The slash picker renders it from runtime capabilities, and submitting `/btw <question>` opens the composer-adjacent quick-question slot rail only when that provider slot exists. It uses the shared Chat Runtime SSE request boundary and UIMessageChunk parser used by normal chat streams, while keeping its stateless local projection and lifecycle. It is not registered as a Cradle-owned fallback command, does not persist a chat message, and does not open a Dialog or Browser Panel.
`/side` is a Cradle-owned chat command, not a provider command. The composer exposes it alongside other Cradle commands, `use-chat-session.ts` intercepts `/side [message]`, calls `POST /chat/sessions/{sessionId}/side-chat`, opens a Browser Panel `side-conversation` tab in the current BrowserPanel owner scope, and optionally submits the inline message/files/context through `POST /chat/side-conversations/{sideConversationId}/response`. Side messages use the renderer-only live chat store under keys such as `side:{id}` and do not create Cradle Chat Session rows.
Subagent detail tabs render provider-native threads through Chat Runtime provider-thread APIs. Codex and Claude Agent subagents hydrate with `provider-threads/:threadId/turns` and subscribe to `provider-threads/:threadId/stream`, then reuse `ChatStreamingHandler`, the renderer-only live chat store, and the transcript `MessageBubbleView` with a synthetic provider-thread view id. This keeps subagent detail on the same AI SDK message/chunk architecture as Chat Session without creating Cradle child sessions, polling UI slot state, scraping the parent tool output, or mixing provider-thread transcripts into the main session store. Parent chat tool rows render only the provider-owned tool lifecycle, status, summary, and a Browser Panel handoff; full subagent transcripts are not nested into parent message parts.
When a session is already streaming, the composer chooses between two distinct follow-up transports. `queue` submits a durable Chat Session continuation through `/chat/sessions/{sessionId}/queue`; those rows are shown in the queue controls and can be cancelled or reordered while pending. `steer` submits live same-turn guidance through `/chat/sessions/{sessionId}/steer`; accepted steer messages are inserted into the visible transcript from the route response and are not queue items. The default mode comes from Chat settings, and `Shift+Meta/Ctrl+Enter` flips between `queue` and `steer` for one send.
AI SDK wire validation is intentionally limited to the SSE boundary through `uiMessageChunkSchema`. Once a frame has been accepted as an AI SDK chunk or a snapshot has been loaded from Cradle's own database, chat feature code treats the object as trusted and uses direct TypeScript narrowing instead of feature-owned Zod schemas.

## Files

- **chat-tool-entities.ts**: Trusted tool-part helpers for reading AI SDK tool names, approval metadata, and builtin tool payload identity from `UIMessage.parts` without materializing a parallel tool entity store
- **chat-capabilities.ts**: Feature-owned GET boundary for `/chat/draft-runtime-capabilities`, `/chat/sessions/{sessionId}/capabilities`, `/chat/sessions/{sessionId}/ui-slot-states`, and background-terminal list/terminate actions, used only for runtime-native capability data and provider-owned slot state such as Codex compact, plan, tool activity, MCP, diff, terminal, approval, alert, filesystem, skills, plugin, search, crew, usage with account rate-limit windows, and config summaries. The response is a Cradle-owned trusted API payload.
- **provider-thread-command.ts**: Chat Runtime provider-thread HTTP boundary for provider-native subagent/thread detail panels, including metadata read, turn hydration with projected `UIMessage` records, and AI SDK chunk stream subscription.
- **chat-context.ts**: Chat-owned attention snapshot store and renderer context provider factory; publishes active chat attention state such as viewport range, scroll position bucket, near-bottom/manual-scroll state, and composer focus without exposing Chat DOM structure to system-agent, while app composition owns provider installation.
- **chat-context.test.ts**: Unit coverage for Chat attention snapshot publication into typed Jarvis context envelopes
- **bang-command.ts**: Chat-owned parser for Composer `!cmd` submissions; accepts only single-line commands with no space after `!`, leaving empty, spaced, or multi-line input as ordinary chat text. When a local workspace path is available, typing `!` opens Composer bang PTY mode instead of keeping a bang text prefix.
- **composer/bang-pty.ts**: Helpers for Composer bang PTY door detection, namespaced pty ids, and discard-confirm transcript heuristics.
- **composer/views/composer-bang-pty-view.tsx**: Props-only dark PTY chrome with discard / write-back actions.
- **composer/containers/composer-bang-pty-container.tsx**: Mounts Cradle `ShellView`, owns discard confirm, and persists scrubbed transcripts through `/bang-transcript`.
- **composer/stories/composer-bang-pty-view.stories.tsx**: Server-free gallery for idle, with-output, and busy write-back bang PTY chrome.
- **composer/stories/composer-view.stories.tsx**: Includes a `BangPty` state that mounts the bang PTY surface inside ComposerView.
- **fixtures/screenshots/composer-bang-pty.png**: Preview capture of the bang PTY chrome with discard / write-back actions.
- **bang-command-metadata.ts**: Trusted metadata reader for Cradle-owned `metadata.cradle.bangResult` snapshots persisted by Chat Runtime.
- **chat-slash-commands.ts**: Web-owned slash command descriptor and merge helpers; converts runtime-native commands and command-like runtime UI slots into composer actions, annotates matching runtime slot command rows with provider-owned state labels, filters picker/metadata slots out of the slash panel, executes provider-declared slot `commandAction` metadata for submit/UI actions, hides `requiresSession` slots from pre-session draft composers, registers Cradle UI commands such as `/appshot` and `/side`, and keeps Cradle UI commands separate from provider capabilities
- **transcript/views/message-bubble-view.tsx**: Direct props-only message bubble renderer for fully materialized `UIMessage` fixtures, exports, and host-provided callbacks. It has no store, session, route, Electron, or runtime dependency.
- **transcript/containers/message-bubble-by-id.tsx**: Store-backed message bubble entry that derives `messageId + partIndex` subscriptions and delegates individual parts to bounded adapters.
- **optimistic-chat-turn.ts**: Chat-owned optimistic first-turn boundary used by launch surfaces; appends the user prompt and pending assistant bubble immediately, starts the shared chat stream transport, and leaves canonical snapshot reconciliation to the normal chat session refresh path.
- **chat-response-command.ts**: Feature-owned HTTP command boundary for `/chat/sessions/{sessionId}/response`, `/chat/sessions/{sessionId}/quick-question`, `/chat/sessions/{sessionId}/bang-command`, live side conversation create/response/delete routes, `/chat/sessions/{sessionId}/stream`, `/chat/sessions/{sessionId}/cancel`, `/chat/sessions/{sessionId}/queue`, and `/chat/sessions/{sessionId}/steer`; long-lived response/stream calls are now consumed through `chat-stream-transport.ts` so Electron can replace renderer-owned SSE with desktop IPC fanout while web runtime keeps the same HTTP path. Response and quick-question requests share the Chat Runtime SSE request boundary, while only normal responses enter the persisted chat stream transport. Response, queue, and steer bodies may include chat-owned `contextParts` and Cradle-owned `runtimeSettings`.
- **prompt-ingress.ts**: Chat-owned session-scoped prompt and composer-file ingress registry used by host surfaces such as Browser Panel; external page requests submit through the mounted ChatView composer send path, while host-captured files such as browser screenshots append to the mounted composer without sending.
- **prompt-ingress.test.ts**: Regression coverage for session-scoped prompt ingress routing, unregister behavior, and cleanup ordering when a ChatView remount replaces a handler.
- **chat-stream-transport.ts**: Chat-owned transport abstraction for starting response streams and joining active session streams. It chooses Electron main-process IPC when `window.cradle.chatStream` is available, buffers early IPC events in a bounded per-stream window until the renderer stream is attached, validates incoming chunks with AI SDK `uiMessageChunkSchema`, and falls back to the existing HTTP SSE parser outside Electron.
- **chat-stream-transport.test.ts**: Regression coverage for Electron event-backed stream creation, bounded early-event buffering, Electron error propagation, and HTTP SSE fallback behavior.
- **chat-continuation-metadata.ts**: Chat-owned reader for `metadata.cradle.continuation`, keeping queue/steer presentation metadata separate from provider-visible message parts.
- **chat-queue-list.tsx**: Shared compact durable queue list with localized queue/status badges, drag/drop reorder, up/down button reorder, and pending-item cancellation controls.
- **chat-runtime-view.tsx**: Chat session runtime boundary shared by normal tab routes, Jarvis embedded sessions, and the dedicated Electron tear-off renderer, passing runtime and bound-agent ownership into chat rendering while allowing host-owned composer chrome, send preparation, display text transforms, and the Claude model matrix toolbar control without moving runtime semantics out of Chat.
- **chat-session-prefetch.ts**: Chat-owned prefetch boundary for opening existing sessions; navigation surfaces call this helper to preload the Chat view chunk plus session metadata and transcript snapshots without owning chat query keys.
- **chat-todo-projection.ts**: Chat-owned TODO plugin-state reader and inline TodoWrite projection model; session surfaces read persisted `pluginState.todos`, while tool blocks can map live tool args into the same `todo` / `processing` / `completed` vocabulary.
- **use-session-todos.ts**: Session-level selector hook that scans persisted `UIMessage.parts` from newest to oldest and exposes the latest adapter-synthesized TODO snapshot for the Right Aside runtime surface.
- **runtime-session-status-command.ts**: Chat-owned HTTP reader for server-owned `/chat/sessions/{sessionId}/runtime-status` data, including active-goal discovery state, used by runtime status surfaces.
- **use-runtime-session-status.ts**: React Query hook for server-owned runtime session status; active chat surfaces keep it fresh through Chat Runtime event-tail invalidation instead of interval polling.
- **runtime-settings-command.ts**: Chat-owned HTTP command boundary for `/chat/sessions/{sessionId}/runtime-settings`, exposing session runtime access/interaction settings and the direct Chat Session Claude Agent matrix override stored in `sessions.config_json.claudeAgent.modelAliases`.
- **use-runtime-settings.ts**: React Query hook for Composer-owned runtime settings state, optimistic session updates, Claude Agent session matrix override updates, and runtime-status invalidation after a live update attempt.
- **claude-session-model-matrix-control.tsx**: Composer-adjacent Claude Agent matrix popover for direct Chat Sessions; reads provider-target defaults from model settings, writes session overrides through runtime settings, and can save the current draft back as the provider-target default.
- **runtime-settings-control.tsx**: Compact Composer dropdown for Cradle-owned access and interaction settings; idle changes persist session defaults and loaded settings are sent with new turns and queued continuations.
- **runtime-diagnostics-popover.tsx**: Dev-only top-right chat popover for resource-panel-style provider environment diagnostics such as status, model, reasoning, MCP, skills, plugins, usage, and config.
- **runtime-session-panel.tsx**: Right Aside runtime panel for the selected chat session; merges provider Plan slot state and adapter TODO snapshots into one Progress task surface, renders the provider-projected full crew/subagent agent list with Browser Panel handoff for provider-native subagent output tabs, then summarizes chat attention, server-owned runtime status, UI-visible status, runtime/provider/session identity, latest run timing, queue counts, and recent tool-call state derived from current message parts.
- **runtime-ui-slot-panel.tsx**: Provider-owned UI slot card renderer for chat runtime diagnostics; groups provider-declared `runtimePanel` slot states into environment, activity, and available sections while leaving Goal, Compact, and Plan to their primary chat workflow surfaces.
- **appshot-attachment-model.ts**: Cradle-owned AppShot `FileUIPart` metadata helpers; creates and reads `providerMetadata.cradle.appshot` while keeping model input compatible with normal image file parts.
- **appshot-attachment.tsx**: Cradle-owned AppShot composer/thread visual card; composer rendering keeps only the Codex-sized transition snapshot slot as the native transition target, and thread rendering uses the final capture image with Codex-like centered image, mask, shadow, sibling icon overlay, and caption treatment.
- **use-chat-session.ts**: Chat session hook — uses React Query for canonical snapshot rows and queue items, restores Cradle-owned stable message rows from IndexedDB before the server snapshot returns, relies on Chat Runtime event-tail invalidation plus explicit action refreshes for queue/runtime-status changes, hydrates AI SDK `UIMessage` snapshots, passively restores currently streaming assistant message ids for reload recovery, pauses driver-owned snapshot / runtime-status / passive stream work while the owning chat frame is hidden, discovers server-owned Codex active-goal continuation runs from runtime status, joins the active session AI SDK chunk stream after hydration, restores only the latest failed main assistant row as the current session error, drives streaming responses with text plus `FileUIPart[]`, intercepts Cradle-owned `/side` to create Browser Panel side-conversation tabs and optionally seed renderer-only side messages, invalidates session-list queries as soon as a normal new response is accepted so sidebar/recent-session ordering updates immediately, handles AI SDK native approval responses by resubmitting complete `messages` history and runtime-owned approval responses by submitting to the pending tool-approval endpoint, enqueues follow-up continuations while busy, projects accepted live steer items into the visible message list before canonical snapshot sync, locally releases stop state immediately, forwards loaded runtime settings with responses and queue items, refreshes snapshots and queue state after server-owned cancellation settles, and exposes low-frequency session controls plus `{ messageIds, messageCount, status, error }` so message text streaming stays at the message subscription boundary.
- **streaming-session-retention.ts**: Chat-owned retention filter for hidden streaming Chat Session frames; reads only the main chat store, while Browser Panel `/side` conversations and provider-thread detail tabs keep their in-memory transcripts in the renderer-only live chat store.
- **stable-message-cache.ts**: Cradle-owned IndexedDB adapter for terminal Chat Session message snapshot rows; keeps a bounded per-session transcript cache for renderer remount recovery while leaving server `messages.message_json` as canonical truth and excluding all streaming rows.
- **use-session-await.ts**: Session await summary hook used by the chat view to reflect pending await state with the shared interactive query refresh policy.
- **sse-chat-transport.ts**: Thin web/runtime HTTP SSE parser using `parseJsonEventStream` and `uiMessageChunkSchema`; also emits lightweight run activity notifications for app chrome and terminal run-settled events for unread reconciliation.
- **chat-view.tsx**: Read-only chat view — reads low-frequency session state from useChatSession, renders MessageBubbles by per-message store subscriptions + Composer, shows pending Chat Session queue items and the runtime settings control near the Composer, accepts workspace file drops into the composer, exposes host-owned composer addons plus send preparation/display text hooks for embedded surfaces such as Jarvis, consumes scroll/composer/Appshot runtimes for virtua, minimap, attention snapshots, send actions, slash commands, token usage, attachment capability, desktop capture, side chat creation handoff, the slash-triggered ChatGPT usage rail, the provider-owned Codex plan rail, and the composer-adjacent Codex review selector, and records the global Chat first-render performance measure once per module lifetime.
- **transcript/views/chat-transcript-view.tsx**: Props-only transcript surface that owns virtualized layout plus empty/error presentation. Storybook and screenshot fixtures render it with props-only `MessageBubbleView` rows.
- **transcript/containers/chat-transcript-content.tsx**: Runtime adapter that translates session message IDs into bounded `MessageBubbleById` subscriptions.
- **transcript/containers/chat-message-list-pane.tsx**: Runtime layout adapter that owns scroll refs, minimap data, and composer-overlay orchestration around the transcript surface.
- **transcript/fixtures/chat-transcript-fixtures.ts**: Server-free `UIMessage` fixtures for stable transcript stories and screenshot scenes.
- **fixtures/screenshots/chat-transcript-long-thread.png**: 1440×900 golden image captured from the server-free Long Thread story.
- **context/containers/**: Query and Browser Panel adapters for session context usage; these modules are the only Context surface code that reads runtime data or global stores.
- **context/views/**: Props-only detail and compact Context window presentation, used by the Composer popover and Storybook without a session runtime.
- **context/fixtures/context-usage-fixtures.ts**: Typed provider and compact-state fixtures for the Context surface's detailed, near-limit, fallback, loading, and error states.
- **context/stories/context-usage-view.stories.tsx**: Server-free Context surface gallery. It mounts only `*View` modules and fixture callbacks.
- **tool-blocks/views/tool-call-block-view.tsx**: Props-only `ToolCallBlockView` for canonical tool envelopes, local expand/detail state, approval callbacks, and bounded open-surface actions.
- **tool-blocks/containers/tool-call-block-container.tsx**: Runtime `ToolCallBlock` adapter that owns browser-panel subscriptions and translates View actions into workspace diff, subagent, workflow, and plan-document tabs.
- **tool-blocks/views/activity-feed-view.tsx**: Props-only `ActivityFeedView` that renders consecutive tool calls and reasoning parts as one chronological, collapsed-by-default feed with an aggregate count summary; the matching container owns browser-panel diff and plan-document handoff.
- **tool-blocks/containers/activity-feed-container.tsx**: Runtime `ActivityFeed` adapter that owns browser-panel subscriptions and translates feed actions into workspace diff and plan-document tabs.
- **tool-blocks/views/tool-hero/**: One props-only View per terminal, file-read, search, web, subagent/workflow, todo, plan, question, and MCP summary. `tool-hero-view.tsx` is only their pure descriptor dispatcher; workflow projection helpers live in `tool-blocks/lib/workflow-summary.ts`.
- **tool-blocks/fixtures/tool-block-fixtures.ts**: Server-free fixtures covering all 15 canonical Cradle tool kinds, all seven lifecycle states, approvals, errors, and activity-feed entry sets.
- **fixtures/screenshots/chat-tools-gallery.png**: Golden image captured from the props-only All Tool Kinds story.
- **codex-review-mode.ts**: Pure Codex review-mode prompt and branch ordering helpers; mirrors the native review guidelines, uncommitted/base-branch request messages, and merge-base diff instruction instead of sending raw `/review` text.
- **codex-review-mode.test.ts**: Regression coverage for Codex review-mode prompt construction and base branch ordering.
- **use-chat-scroll-runtime.ts**: Chat-owned scroll controller hook for ScrollArea and virtua refs, streaming keep-mounted indices, bottom-follow auto-scroll that detaches on manual upward scroll, transcript content resize observation, minimap progress writes, click/drag scroll actions, and Jarvis attention viewport snapshots.
- **use-chat-composer-runtime.ts**: Chat-owned composer integration runtime for session binding, runtime slash capabilities, runtime UI slots, provider slot state labels, fallback Cradle commands including `/side`, model attachment capability, token usage, continuation-mode send actions, and stop state.
- **use-runtime-composer-slash-commands.ts**: Chat-owned pre-session command hook that reads provider-owned draft runtime capabilities and projects them through the same slot-to-command helpers used by ChatSession composers.
- **composer-slot-states.tsx**: Thin composer-adjacent provider UI slot dispatcher that selects declared `composerState` slots plus chat-owned slash-opened usage state, then passes them to slot-specific renderers instead of owning each slot UI inline.
- **composer-slot-states.test.tsx**: Regression coverage for slash-opened usage rail rendering, provider-declared plan composer state, and dismissal without restoring always-on composer usage state.
- **composer-slots/**: Slot-specific composer rail renderers and shared primitives, including Codex goal, Codex plan-ready actions, slash-triggered ChatGPT usage, and the slash-triggered Codex review target selector. Runtime metadata and picker state stay out of this surface unless the provider explicitly declares `composerState` or ChatView opens a bounded UI action surface.
- **use-composer-appshot-capture.ts**: Composer-owned desktop Appshot capture runtime; keeps native hotkey subscription stable through refs, owns pending Appshot slots, measures action targets, and injects captured file parts into Composer without leaving capture orchestration in ChatView.
- **chat-share-export.tsx**: Chat-owned share dialog that renders an off-scroll Cradle-styled conversation surface, lets users export the full session or selected messages, and uses `modern-screenshot` to download or copy a PNG without depending on the virtualized message list.
- **chat-share-export.test.tsx**: Regression coverage for the export dialog default all-message preview, selected-message preview scope, and PNG render/download handoff.
- **chat-minimap.tsx**: Right-edge accessible chat minimap with compact barcode-style bars, per-message reading progress, per-bar hover previews, click-to-message, and drag-to-scroll behavior; scroll progress is written through an imperative ref and transform updates instead of React state
- **chat-minimap.test.tsx**: Regression coverage for the React 19 ref prop imperative handle and accessible native minimap button behavior
- **composer-attachment-state.ts**: Shared headless attachment controller; chat owns browser file conversion, pasted-file handling, UI action file-part appends, model attachment gating, and model-switch cleanup for chat, new-chat, and workspace launcher composers
- **composer-attachments.tsx**: Shared attachment UI primitives for hidden file input, attach button, attachment chips, and AppShot pending slots, consumed by all composer surfaces without duplicating visual behavior
- **composer-action-context.ts**: Composer-owned UI action geometry reader; measures Codex-style AppShot pending slots and emits renderer-owned `viewportPixels` animation targets for native capture.
- **chat-context-parts.ts**: Chat-owned structured context part types for composer-selected context tokens such as Skills, including inline prompt positions, kept under the `data-cradle-*` namespace so providers can opt into projection without owning UI selection state.
- **composer/views/composer-view.tsx**: Props-driven rich input used by chat, new-chat, workspace launchers, and Storybook. It owns local editor/attachment/picker interaction, accepts explicit native-file-drop capability, and renders grouped send/command/attachment/slot/external-signal/view inputs without reading Electron.
- **composer/containers/composer-container.tsx**: Runtime adapter that derives native file-drop capability from the Electron host and delegates rendering to `ComposerView`.
- **composer/stories/composer-view.stories.tsx**: Server-free empty, draft, attachment, streaming, sending, and disabled composer states.
- **composer/containers/draft-chat-composer-container.tsx**: New Chat runtime orchestrator for provider selection, runtime settings, remote-host gating, Appshot capture, OCR, slash actions, and submit options. It supplies the presentation slots rather than owning the outer JSX.
- **composer/views/draft-chat-composer-view.tsx**: Props-only New Chat composition surface; Storybook provides a `ComposerView` and readiness fixture without catalog, store, router, or Electron decorators.
- **composer/views/draft-chat-readiness-notice-view.tsx**: Props-only provider/agent readiness notice with an injected settings action.
- **prompt-editor.tsx**: Thin ProseMirror prompt editor owned by chat; models @ file mentions and `$` Skill mentions as inline atom nodes, serializes visible prompt text separately from Cradle-owned structured context parts, and keeps trigger ranges for shared autocomplete panels.
- **autocomplete-panel.tsx**: Generic composer autocomplete popover with shared fuzzy matching, keyboard handling, remote search debounce, loading state, and highlighted match rendering for trigger-specific panels.
- **mention-panel.tsx**: Fuzzy file picker above composer using fzf with highlighted matches and the shared workspace file icon renderer for file results
- **skill-mention-token.tsx**: Shared inline `$Skill` token presentation used by both the prompt editor atom DOM and user-message bubble rendering.
- **skill-mention-panel.tsx**: `$` Skill picker above composer; reads Cradle skill inventory entries from the chat runtime view and emits chat-owned skill context parts instead of writing to the skills namespace.
- **mention-panel.test.tsx**: Regression coverage for MentionPanel file-result icon rendering through the shared sprite-backed workspace file icon component.
- **slash-command-input.ts**: Shared slash trigger parsing, active command detection, required-argument send blocking, availability filtering, and trigger replacement helpers used by chat, new-chat, and workspace launcher textareas
- **slash-command-panel.tsx**: Fuzzy slash command picker above composer; renders web-owned command descriptors with runtime state badges and provider-owned row visuals such as the Codex `/compact` usage ring, disambiguates duplicate visible names by source, and does not fetch a slash command list from app-server
- **transcript/views/message-bubble-view.tsx**: Props-only `UIMessage` renderer for fixtures, Storybook, exports, and host-provided callbacks; it owns local execution folding and streaming presentation without stores, routes, Electron, or session context.
- **transcript/containers/message-bubble-by-id.tsx**: Bounded `messageId` store adapter that selects a message frame and delegates each segment to a focused runtime adapter.
- **transcript/containers/message-bubble-segments-container.tsx**: Runtime composition of selected message parts, image lightbox state, debug/actions slots, and `MessageBubbleFrameView` chrome.
- **transcript/views/run-debug-caption-view.tsx**: Props-only assistant run timing caption (Accept/TTFB/TTFT/Done) for fixtures and host-provided debug slots.
- **transcript/containers/run-debug-caption-by-id.tsx**: Store/query adapter that projects local run meta plus optional run-snapshot timings into `RunDebugCaptionView`.
- **transcript/views/{file-attachment,skill-context,plugin-context,file-line-comment-context}-view.tsx**: Props-only attachment/context presentation components shared by fixture rendering and their bounded part adapters.
- **transcript/containers/message-*-part-by-id.tsx**: One store-backed adapter per text, file, context, and warning part; these are the only transcript modules that subscribe by `messageId + partIndex`. Reasoning parts render inside activity feeds instead of standalone blocks.
- **reasoning-duration.ts**: WeakMap-keyed wall-clock tracker for live reasoning parts; the activity-feed bridge passes stable part identities so streaming parts resolve "Thought for Ns" while historical parts stay "Thought briefly"
- **tool-ui-classifier.ts**: Central trusted-object classifier for AI SDK dynamic-tool parts and Claude Agent tool IO; maps file reads, diffs, notebooks, terminal commands, search, web, subagents, task control, legacy/current TODO task tools, plan approval, user questions, MCP, worktrees, and unknown tools to stable UI categories; materializes partial streaming tool input so large tool calls classify before complete JSON arrives without running a Zod schema in the render path
- **blocks/bang-command-block.tsx**: Terminal-style renderer for persisted Composer bang command results; shows command, exit status, duration, timeout/truncation state, and collapsible stdout/stderr sections using the same terminal output section reader as tool blocks.
- **tool-blocks/views/tool-call-block-view.tsx**: Classified props-only tool invocation display built from `components/ui` primitives and MingCute icons; the container supplies Browser Panel handoff for file diffs, subagents, workflows, and plan documents.
- **tool-blocks/views/activity-feed-view.tsx**: Dense props-only chronological feed of consecutive tool calls and reasoning parts; collapsed header summarizes per-kind counts, expandable rows render terminal, diff, hero, and reasoning details. Its container owns Browser Panel diff and plan-document handoff.
- **blocks/edit-file-block.tsx**: File edit preview powered by `@pierre/diffs/react` `MultiFileDiff`, with split and stacked layout switching for chat tool output; the diff pane opens without layout-triggering height animation
- **blocks/tool-call-block.test.tsx**: Regression coverage for Edit File tool IO routing, collapsed diff previews, layout switching, and `@pierre/diffs/react` option wiring
- **tool-ui-classifier.test.ts**: Regression coverage for Claude Agent and AI SDK tool classification, including MCP precedence over URL-shaped tool inputs
- **chat-slash-commands.test.ts**: Regression coverage for slash command descriptor conversion, provider-declared slot actions, session-only runtime slot filtering, Cradle-owned `/appshot` command registration, provider slot state labels, fallback runtime descriptor replacement, merge ordering, duplicate visible-name detection, and runtime input immutability
- **composer.test.tsx**: Regression coverage for named send/stop actions, slash command insertion, inline argument hints, active command descriptions, duplicate command-name rendering, Cradle UI command callback dispatch, unavailable UI action presentation, UI action returned file attachments, workspace file drops, selected/pasted attachments, and raw `/command args` send-through
- **use-chat-session.test.ts**: Passive snapshot/reload regression tests for chat status derivation, main-message projection, and stop-action abort forwarding
- **use-chat-session-binding.test.tsx**: Hook lifecycle regression tests for session binding invalidation and stop cancellation status ownership
- **chat-streaming-handler.ts**: AI SDK chunk-to-store bridge that uses `@cradleapp/ai-sdk` to apply ordinary chunks and resumable stream snapshots, then replaces the corresponding Zustand message through a bounded rAF-aligned flush cadence so high-frequency provider deltas do not force full store normalization on every frame.
- **chat-streaming-handler.test.ts**: Regression coverage for passive replay reconstruction and snapshot recovery followed by later live deltas.
- **index.ts**: Barrel file re-exporting public API

## Presentation Boundaries

- New screenshotable chat surfaces export a props-only `*View`; routes, queries, stores, Electron APIs, and session lifecycle stay in `*Container`, `*Pane`, or `*ById` adapters.
- Storybook stories render View exports from fixtures. Do not mount routes or runtime containers in stories, and do not recreate the application provider stack in decorators.
- Runtime-only UI is passed into Views as data, callbacks, or bounded render slots. A View may own local interaction state such as expanded, copied, or selected.
- Run Storybook with `pnpm --filter @cradle/web storybook`; verify the static bundle with `pnpm --filter @cradle/web storybook:build`.
