Context
The renderer's interactive primitives (packages/ui/src/primitives/*) are already on the shadcn Base UI + Tailwind substrate (cva, data-slot, @base-ui/react). The chat conversation-flow display layer is the last bespoke island: packages/ui/src/components.tsx (MessageBody ~L4441, TurnSummary ~L4618, TurnView ~L4697, ToolActivity ~L6165) renders hand-written maka-* classNames whose CSS is spread across: styles/tool-output.css, styles/tool-stream.css, chat selectors in maka-tokens.css, .maka-turn-* in styles/settings/models.css (model-catalog preview), and .maka-bubble-truncated in styles/reasoning-panel.css. (styles/chat-message.css is the empty/hero state, not the main flow.)
Goal: migrate the conversation flow (bubbles, status/tool markers, tool/result/preview surfaces) onto a small set of @maka/ui chat primitives (Message/Bubble/Marker/Attachment), retiring the bespoke shell CSS, with zero visual change. This is governance (one substrate + a test net), not a redesign; the visual refresh is a separate follow-up.
Invariants (every slice)
- Zero visual change, locked by computed-style/cascade contract tests + before/after screenshots.
- Keep the neutral user-bubble token path (
--chat-user-bg / --user-message-bubble); never switch it to primary/accent.
- Replace only the bubble/row shell. Markdown prose under
.maka-bubble-assistant (task lists, code blocks, tables, blockquotes, links; maka-tokens.css:1088+) is OUT of scope and must be preserved. Do not touch .messages (chat scroll container).
- No change to runtime, streaming, Markdown rendering, permission, turn model, tool output, attachment IPC.
- New primitives live in
packages/ui/src/primitives/chat* and are exported from packages/ui/src/index.ts; do not grow the components.tsx sink.
- Each slice deletes its retired CSS.
scripts/check-dead-css.mjs --check only scans styles/ + reference-shell.css (NOT maka-tokens.css); the renderer-style-pruning-contract test does reach tokens via styles.css imports. Lean on contract tests + manual grep of maka-tokens.css.
Slices (flat PRs off main, landed in order)
Next component after this batch
Out of scope (stays hand-written)
Design tokens (maka-tokens.css), Markdown prose, feature-page layout CSS (sidebar / settings / module-pages / onboarding / etc.), and no-equivalent primitives (overlay-scroll-area, frame, kbd, skeleton, spinner, empty, alert, input-group).
Context
The renderer's interactive primitives (
packages/ui/src/primitives/*) are already on the shadcn Base UI + Tailwind substrate (cva,data-slot,@base-ui/react). The chat conversation-flow display layer is the last bespoke island:packages/ui/src/components.tsx(MessageBody~L4441,TurnSummary~L4618,TurnView~L4697,ToolActivity~L6165) renders hand-writtenmaka-*classNames whose CSS is spread across:styles/tool-output.css,styles/tool-stream.css, chat selectors inmaka-tokens.css,.maka-turn-*instyles/settings/models.css(model-catalog preview), and.maka-bubble-truncatedinstyles/reasoning-panel.css. (styles/chat-message.cssis the empty/hero state, not the main flow.)Goal: migrate the conversation flow (bubbles, status/tool markers, tool/result/preview surfaces) onto a small set of
@maka/uichat primitives (Message/Bubble/Marker/Attachment), retiring the bespoke shell CSS, with zero visual change. This is governance (one substrate + a test net), not a redesign; the visual refresh is a separate follow-up.Invariants (every slice)
--chat-user-bg/--user-message-bubble); never switch it toprimary/accent..maka-bubble-assistant(task lists, code blocks, tables, blockquotes, links;maka-tokens.css:1088+) is OUT of scope and must be preserved. Do not touch.messages(chat scroll container).packages/ui/src/primitives/chat*and are exported frompackages/ui/src/index.ts; do not grow thecomponents.tsxsink.scripts/check-dead-css.mjs --checkonly scansstyles/+reference-shell.css(NOTmaka-tokens.css); therenderer-style-pruning-contracttest does reach tokens viastyles.cssimports. Lean on contract tests + manual grep ofmaka-tokens.css.Slices (flat PRs off main, landed in order)
chat.tsxMessage+Bubble + contract; wireMessageBody; delete the bubble/row shell (.maka-bubble-user, assistant wrapper layout,.message.user/.assistant/.system,.maka-bubble-truncated). Keep Markdown prose.maka-turn-thinking: include or explicitly defer) →Marker; delete.maka-turn-*in BOTHmaka-tokens.css/tool-output.cssANDstyles/settings/models.css.ToolOutputStream+ the live dot (LiveIndicator) onto chat primitives; deleted.maka-tool-output-stream-*+ its per-feature@keyframes. Added canonical@keyframes maka-pulse(shared motion home) +npm run check:chat-visualfor the zero-visual diff.LiveIndicator/streamVariantskept internal (off-barrel) until a 2nd consumer.ToolActivitycard shell onto internaltoolVariants; deleted the.maka-tool*card CSS (+.toolInline/.toolItem/.toolArgs) and re-keyed the entrance /<summary>marker / pulse-ring residue onto[data-slot="tool"]. The error-banner half was carved out → PR3c.toolVariantskept internal (off-barrel) until a 2nd consumer..maka-tool-error*(ToolErrorBanneralready renders on theAlertprimitive — this is CSS retirement, not a new primitive). Delete the dead-icon/-body/-title; literalize the live container /-text/-copytints; syncvisible-copy-hygiene-contract..maka-overlay-previewbase and the.maka-load-tool-*card. Resolved the shared-.maka-tool-diff*note by co-migratingartifact-preview.tsxonto the barrel-exportedpreviewVariantsdiff parts (no temporary shared layer).@keyframes maka-tool-card-entermoved to maka-tokens.css.overlay-scroll-area) is a behavioral concern, evaluated separately.Next component after this batch
styles/composer.cssAND a chunk instyles/tool-output.css.Out of scope (stays hand-written)
Design tokens (
maka-tokens.css), Markdown prose, feature-page layout CSS (sidebar / settings / module-pages / onboarding / etc.), and no-equivalent primitives (overlay-scroll-area,frame,kbd,skeleton,spinner,empty,alert,input-group).