nexus/.planning/phases/23-brainstormer-flow/23-UI-SPEC.md

24 KiB
Raw Blame History

phase slug status shadcn_initialized preset created
23 brainstormer-flow draft true new-york / neutral / css-variables 2026-04-01

Phase 23 — UI Design Contract

Visual and interaction contract for Phase 23: Brainstormer Flow. Generated by gsd-ui-researcher. Verified by gsd-ui-checker.


Design System

Property Value Source
Tool shadcn/ui ui/components.json — unchanged from Phase 21/22
Style new-york ui/components.json
Base color neutral ui/components.json
CSS variables true ui/components.json
Component library Radix UI (via shadcn new-york) ui/components.json
Icon library lucide-react ^0.574.0 ui/components.json
Font System UI (font-sans, inherited) ui/src/index.css

Existing shadcn components available (no install needed): avatar, badge, button, card, checkbox, collapsible, command, dialog, dropdown-menu, input, label, popover, scroll-area, select, separator, sheet, skeleton, tabs, textarea, tooltip

Existing custom components to reuse/extend:

  • ChatMessage.tsx — extend with role === "system" rendering branch for handoff/spec/status-update messages
  • ChatPanel.tsx — extend with Brainstormer default agent selection on new conversation
  • AgentIcon (from AgentIconPicker.tsx) — used for Brainstormer identity in all message identity bars
  • agentRoleColors (from agent-role-colors.ts) — general role maps to text-slate-600 dark:text-slate-400 for Brainstormer avatar
  • issuesApi — referenced from ui/src/api/issues for task creation link-out

New DB migration required:

  • Add message_type column to chat_messages table: text("message_type") — values: null (normal), "handoff", "spec_card", "task_created", "status_update". Used by Phase 23 system message rendering to determine which specialized card to display.

Layout Contract

Layout Unchanged

The overall layout established in Phase 21 and unmodified in Phase 22 remains:

[ CompanyRail ] [ Sidebar ] [ <main> ] [ ChatPanel ] [ PropertiesPanel ]

Phase 23 adds new UI surfaces inside ChatPanel and ChatMessageList only. No layout-level changes.

Default Brainstormer Selection (AGENT-01)

When the user opens a new conversation (no prior messages), the ChatPanel auto-selects the workspace agent with role === "general" as the default. The ChatAgentSelector renders this agent immediately without user action.

Selection precedence:

  1. If a general role agent exists in the workspace — select it
  2. If multiple general agents exist — select the first by createdAt ascending
  3. If no general agent exists — fall back to the first agent alphabetically (same as current behavior)
  4. Auto-selection fires only when activeAgentId === null and the conversation has zero messages

The auto-selected agent is visually indistinguishable from a manually selected agent — the ChatAgentSelector shows its icon + name normally.

Spec Card Layout (AGENT-02)

When the Brainstormer completes its questioning flow, it emits a spec card as a system role message with message_type: "spec_card". The ChatMessage component renders a ChatSpecCard instead of a markdown message.

┌─────────────────────────────────────────────┐
│  [Brain icon]  Brainstormer — Spec Ready     │  ← identity bar (standard)
├─────────────────────────────────────────────┤
│  What: {what field text}                     │
│  Why: {why field text}                       │
│  Constraints: {constraints field text}       │
│  Success: {success field text}               │
├─────────────────────────────────────────────┤
│  [ Send to PM ]  [ Edit ]  [ Save as Draft ] │  ← action row
└─────────────────────────────────────────────┘
  • Container: rounded-lg border border-border bg-card p-4 max-w-[480px] — uses bg-card (secondary 30% surface) to visually distinguish spec from normal prose
  • Section labels ("What", "Why", "Constraints", "Success"): text-[11px] font-semibold uppercase tracking-wide text-muted-foreground — same weight/size pattern as Phase 22 timestamps
  • Section content: text-[15px] font-normal text-foreground leading-relaxed — standard body
  • Vertical rhythm between sections: space-y-4 (16px gaps)
  • Action row: flex gap-2 pt-4 border-t border-border mt-4 — separated from content with a border
  • "Send to PM" button: variant="default" size="sm" — primary action
  • "Edit" button: variant="outline" size="sm" — secondary action
  • "Save as Draft" button: variant="ghost" size="sm" — tertiary action

Handoff Indicator Layout (AGENT-05, CHAT-09)

When the user clicks "Send to PM", a handoff message is inserted as a system role message with message_type: "handoff". The ChatMessage component renders a ChatHandoffIndicator.

┌───────────────────────────────────────────────┐
│  ──  Brainstormer → PM: spec handed off  ──   │  ← separator-style indicator
└───────────────────────────────────────────────┘
  • Container: flex items-center gap-3 py-2 text-[13px] text-muted-foreground
  • Left and right: <hr className="flex-1 border-border" /> — lines flanking the label
  • Center label: whitespace-nowrap — "Brainstormer → PM" + brief description (see Copywriting)
  • Arrow character: unicode, not a Lucide icon — matches the simple prose style
  • No background, no border-radius — this is a separator, not a card

Task Created Notification Layout (AGENT-03, AGENT-06)

When the PM agent creates Nexus issues from the spec, a system role message with message_type: "task_created" appears. The ChatMessage component renders a ChatTaskCreatedBadge.

[ #123  Issue title text  →  View task ]
  • Container: inline-flex items-center gap-2 rounded-md border border-border bg-card px-3 py-1 text-[13px]
  • Issue ID badge: text-[11px] font-semibold text-muted-foreground — e.g. "T-123"
  • Issue title: text-[13px] text-foreground
  • "View task" link: text-primary underline-offset-2 hover:underline — navigates to the issue detail page
  • Multiple tasks from one spec: render one ChatTaskCreatedBadge per task, stacked vertically with gap-2 wrapper

Status Update Notification Layout (AGENT-07)

When an Engineer or Generalist completes a task, a system role message with message_type: "status_update" appears. The ChatMessage component renders a ChatStatusUpdateBadge.

[ ✓  Engineer completed T-123: Issue title ]
  • Container: inline-flex items-center gap-2 rounded-md border border-border bg-card px-3 py-1 text-[13px]
  • Icon: CheckCircle2 (lucide), 14×14px, text-green-500 dark:text-green-400 — indicates completion
  • Text: text-[13px] text-foreground — agent name + action + task reference
  • Task reference: text-primary underline-offset-2 hover:underline — link to issue detail

Spacing Scale

Inherited from Phase 21 and Phase 22. No new tokens for Phase 23.

Token Value Phase 23 Usage
xs 4px Section label letter-spacing, gap within inline badges
sm 8px Action button gap in spec card row (gap-2), badge padding
md 16px Spec card padding (p-4)
lg 24px (no new usage)
xl 32px (no new usage)

New spacing values (Phase 23 only):

  • Spec card section vertical rhythm: space-y-4 (16px) — between What/Why/Constraints/Success blocks
  • Spec card action row top: pt-4 (16px) — from content to action row border
  • Task badge height: py-1 (6px top/bottom) — compact inline badge
  • Handoff indicator vertical: py-2 (8px) — matches section separator rhythm

Typography

All inherited from Phase 21 and 22. No new type tokens for Phase 23.

Role Size Weight Line Height Usage
Body / message text 15px (0.9375rem) 400 1.6 Spec card content, chat message prose (unchanged)
Label / UI chrome 13px (0.8125rem) 400 1.4 Task badge text, handoff indicator label, agent selector (unchanged)
Spec section label 11px (0.6875rem) 600 1.4 "What", "Why", "Constraints", "Success" labels in spec card
Message timestamp 11px (0.6875rem) 400 1.4 Identity bar timestamps (Phase 22, unchanged)

Weights used: 400 (regular) and 600 (semibold). No additional weights. Same constraint as Phase 21/22.

Spec section label note: The 11px / 600 uppercase-tracked label pattern matches the existing text-[11px] text-muted-foreground timestamp pattern from Phase 22. The semibold weight at 11px + uppercase tracking-wide provides adequate differentiation from surrounding 15px prose. No new weight is introduced.


Color

All values inherited from Phase 21 CSS variable system. No new color variables introduced.

Role Catppuccin Mocha Tokyo Night Catppuccin Latte Phase 23 Usage
Dominant (60%) --background #1e1e2e --background #1a1b26 --background #eff1f5 Unchanged
Secondary (30%) --card #181825 --card #16161e --card #e6e9ef Spec card background, task badge background, status badge background
Accent (10%) --accent #45475a --accent #3b4261 --accent #bcc0cc Hovered rows (unchanged)
Primary --primary --primary --primary "Send to PM" button, task/status reference links
Destructive --destructive --destructive --destructive Not used in Phase 23
Muted text --muted-foreground --muted-foreground --muted-foreground Handoff indicator label, spec section labels, task ID badges

Accent reserved for (unchanged from Phase 22):

  1. Hovered conversation list row
  2. Currently active/selected conversation row
  3. Code block toolbar background on hover
  4. Input focus-within ring
  5. Slash command popover highlighted item

Task completion check icon: text-green-500 dark:text-green-400 — same Tailwind semantic color pattern as Phase 22 agent role colors. Sufficient contrast in all three themes.

Brainstormer avatar color: text-slate-600 dark:text-slate-400 — mapped from agentRoleColors["general"] in the existing agent-role-colors.ts utility. No new color needed.

Spec card border: border-border — resolves correctly via CSS variable in all three themes.


Component Inventory

New components to build in Phase 23:

Component shadcn base Notes
ChatSpecCard.tsx button, card Spec fields (What/Why/Constraints/Success) + action row; rendered inside ChatMessage when messageType === "spec_card"
ChatHandoffIndicator.tsx none Separator-style indicator; flex items-center gap-3 with flanking <hr> elements
ChatTaskCreatedBadge.tsx none Inline badge for a single created task; receives taskId, taskTitle, taskUrl props
ChatStatusUpdateBadge.tsx none Inline badge for task completion; receives agentName, taskId, taskTitle, taskUrl props
useBrainstormerDefault.ts none Hook: queries workspace agents, returns the general role agent ID for auto-selection on new conversations

Existing components to modify:

Component Change
ChatMessage.tsx Add rendering branch for messageType prop: "spec_card"ChatSpecCard, "handoff"ChatHandoffIndicator, "task_created"ChatTaskCreatedBadge, "status_update"ChatStatusUpdateBadge, null → existing markdown/bubble rendering
ChatPanel.tsx Wire useBrainstormerDefault to set activeAgentId when activeConversationId === null and activeAgentId === null

DB migration component:

  • server/src/db/migrations/XXXX_add_message_type.ts — adds message_type text nullable column to chat_messages table

Icons (lucide-react) — Phase 23 additions:

  • CheckCircle2 — task completion status badge
  • Brain — recommended default icon for the Brainstormer agent (user configures, but brain is a valid AGENT_ICON_NAME)

All icons from Phase 21 and Phase 22 remain unchanged.


Interaction Contract

Brainstormer Default Agent (AGENT-01)

Interaction Behavior
User opens new conversation (no messages) useBrainstormerDefault resolves general role agent; ChatAgentSelector reflects that agent immediately
User changes agent mid-flow Normal agent selector behavior (Phase 22); no lock-in to Brainstormer
No general agent in workspace Fall back to first agent alphabetically; no error state; log warning to console

Structured Questioning Flow (AGENT-02)

The Brainstormer agent's structured questioning flow is entirely server-side (system prompt + LLM). The UI has no state machine for question steps — it renders the agent's streamed responses normally via the existing ChatMessage + ChatMarkdownMessage pipeline.

The spec card is produced when the LLM outputs a message with message_type: "spec_card" and a structured JSON body in content. The server parses this and stores it as a system role message. The UI detects messageType === "spec_card" and renders ChatSpecCard.

Interaction Behavior
Brainstormer streams a clarifying question Standard streaming rendering (Phase 22 pipeline); no special UI
User answers a question Standard message send; no special UI
Brainstormer produces spec card message_type: "spec_card" message appears; ChatSpecCard renders inline in message thread

Spec Card Actions (AGENT-02)

Interaction Behavior
Click "Send to PM" Optimistic: spec card action buttons disabled immediately; ChatHandoffIndicator appended to thread; POST to /api/conversations/:id/handoff with spec content and targetRole: "pm"
Click "Edit" Spec card enters edit mode: each field (What/Why/Constraints/Success) becomes an editable <textarea>; "Save changes" and "Discard" buttons replace the original action row
Click "Save changes" (in edit mode) PATCH spec card message with updated content; reverts to read-only spec card
Click "Discard" (in edit mode) Revert to read-only spec card; no server call
Click "Save as Draft" Spec card persists as-is; no handoff action; action buttons remain; [Draft] badge appended to spec card header in text-muted-foreground text-[11px]
"Send to PM" succeeds PM agent begins streaming a response; ChatHandoffIndicator already in thread; PM's response follows below it
"Send to PM" fails Toast: "Could not send to PM. Try again."; spec card action buttons re-enabled

Handoff Indicator (AGENT-05, CHAT-09)

Interaction Behavior
Handoff message renders ChatHandoffIndicator is non-interactive — display only; no click, no hover state
Multiple handoffs in one conversation Each handoff gets its own separator row in chronological position

Task Created (AGENT-03, AGENT-06)

Interaction Behavior
Task badge renders ChatTaskCreatedBadge is inline; "View task" link navigates via React Router to the issue detail page
Multiple tasks from one spec Multiple ChatTaskCreatedBadge elements stacked vertically
Task ID not yet known (optimistic) Badge shows "Creating task..." in text-muted-foreground until taskId is available; no spinner — inline text is sufficient

Status Update (AGENT-07)

Interaction Behavior
Status update message renders ChatStatusUpdateBadge is inline read-only; "View task" link navigates to issue detail
Multiple status updates Each is a separate system message in the thread; rendered independently

Spec Card Edit Mode

Interaction Behavior
Click field textarea Standard browser focus; no special behavior
Tab between fields Natural tab order: What → Why → Constraints → Success → Save → Discard
Escape in edit mode Discard changes (same as "Discard" button click)
Save with all fields empty "Save changes" button disabled when all four fields are empty
Save with some fields empty Allowed — partial specs are valid

Copywriting Contract

All Phase 21 and Phase 22 copy is preserved unchanged. Phase 23 additions:

Element Copy Notes
Spec card header "Spec Ready" Preceded by Brainstormer identity bar; no separate heading needed
Spec card section label: What "What" text-[11px] uppercase tracking-wide text-muted-foreground
Spec card section label: Why "Why" Same style
Spec card section label: Constraints "Constraints" Same style
Spec card section label: Success "Success" Same style
Spec card "Send to PM" button "Send to PM" variant="default" size="sm"
Spec card "Edit" button "Edit" variant="outline" size="sm"
Spec card "Save as Draft" button "Save as Draft" variant="ghost" size="sm"
Spec card "Save changes" button (edit mode) "Save changes" variant="default" size="sm"
Spec card "Discard" button (edit mode) "Discard" variant="ghost" size="sm"
Spec card draft badge "[Draft]" text-[11px] text-muted-foreground ml-2; appended to Brainstormer name in identity bar
Handoff indicator label "Brainstormer → PM: spec handed off" text-[13px] text-muted-foreground; is unicode, not icon
Task created badge: creating state "Creating task..." Shown before taskId is available
Task created badge: view link "View task" text-primary underline-offset-2 hover:underline
Status update: completion "{agentName} completed {taskId}" e.g. "Engineer completed T-123"; task title truncated to 40 chars with ellipsis
Status update: view link "View task" Same style as task created badge
Send to PM failure toast "Could not send to PM. Try again." Standard toast pattern; no new toast component needed
Spec card edit field placeholder: What "What should be built?" textarea placeholder; shown when field is empty
Spec card edit field placeholder: Why "Why is this important?" textarea placeholder
Spec card edit field placeholder: Constraints "Any constraints or requirements?" textarea placeholder
Spec card edit field placeholder: Success "How will success be measured?" textarea placeholder

Tone: Direct, functional, no corporate language. Consistent with Phase 21/22.


States and Loading

Component Loading state Empty state Error state Notes
ChatSpecCard n/a n/a "Could not render spec." in text-destructive text-[13px] — shown if content cannot be parsed Fallback if JSON parse fails
ChatHandoffIndicator n/a n/a n/a Display only; no async operation
ChatTaskCreatedBadge "Creating task..." inline text n/a "Task creation failed." in text-destructive text-[13px] with retry link Retry link: text-primary underline cursor-pointer
ChatStatusUpdateBadge n/a n/a n/a Display only; task link navigates if available
useBrainstormerDefault activeAgentId stays null while agents load Falls back to first agent Silent fallback (no error UI — agent selector shows "Select agent" fallback)

Optimistic updates:

  • "Send to PM" click: ChatHandoffIndicator appended immediately before API call completes; spec card buttons disabled. On API failure, ChatHandoffIndicator is removed and buttons re-enabled with failure toast.
  • Task creation: ChatTaskCreatedBadge appears with "Creating task..." state; updates in place when taskId resolves.

Theme Integration Contract

Phase 23 extends Phase 21/22's zero-new-plumbing approach:

  • Spec card uses bg-card and border-border — resolves correctly in all three themes via CSS variables
  • Task/status badges use bg-card and border-border — same
  • Handoff separator uses border-border for the <hr> lines — correct in all themes
  • CheckCircle2 completion icon uses text-green-500 dark:text-green-400 — same Tailwind semantic pattern as Phase 22 agent role colors
  • No hardcoded hex colors introduced in Phase 23

THEME-01 / THEME-02 checklist (Phase 23 surfaces):

  • ChatSpecCard: bg-card, border-border, text-foreground, text-muted-foreground — all CSS variables
  • ChatHandoffIndicator: text-muted-foreground, border-border — CSS variables
  • ChatTaskCreatedBadge: bg-card, border-border, text-foreground, text-primary — CSS variables
  • ChatStatusUpdateBadge: same as task badge + text-green-500 dark:text-green-400

Accessibility

Inherits all Phase 21 and Phase 22 accessibility contracts. Phase 23 additions:

Concern Requirement
Spec card role="region" with aria-label="Specification"
Spec card action buttons Standard labeled buttons — no icon-only ambiguity
Spec card edit textareas Each has an explicit aria-label: "What to build", "Why it matters", "Constraints", "Success criteria"
Handoff indicator aria-label="Agent handoff from Brainstormer to PM" on the container; aria-hidden="true" on the <hr> decorators
Task created badge role="status" on the badge container; "View task" link has aria-label="View task {taskId}"
Status update badge role="status" on the badge container; same link labeling pattern
System messages in thread aria-live="polite" on ChatMessageList (established Phase 21) handles announcement of spec cards, handoffs, task badges — no new plumbing needed
Spec card "Send to PM" disabled state aria-disabled="true" when action is in-flight; aria-busy="true" on the card region

Animation and Motion

Inherits Phase 21 and Phase 22 animation contracts. Phase 23 additions:

Element Animation Duration Easing CSS
Spec card appear animate-in fade-in slide-in-from-bottom-2 200ms ease-out — shadcn default
Handoff indicator appear animate-in fade-in 150ms ease-out
Task badge appear animate-in fade-in slide-in-from-bottom-1 150ms ease-out
Status badge appear Same as task badge 150ms ease-out
Spec card edit mode toggle No animation — immediate swap; avoids layout shift (matches Phase 22 edit mode pattern)
"Creating task..." → resolved Content swap with no animation — immediate; simple text replacement

Reduced motion: All Phase 23 entrance animations must respect prefers-reduced-motion via motion-safe: Tailwind prefix — matching the established pattern from Phase 21/22.


Registry Safety

Registry Blocks Used Safety Gate
shadcn official All existing Phase 21/22 components (already installed) not required
Third-party none not applicable

No third-party shadcn registries used in Phase 23. No new npm packages are required — all new components are built from existing shadcn primitives (button, card, textarea), Lucide icons, and CSS variable tokens already present in the project.


Checker Sign-Off

  • Dimension 1 Copywriting: PASS
  • Dimension 2 Visuals: PASS
  • Dimension 3 Color: PASS
  • Dimension 4 Typography: PASS
  • Dimension 5 Spacing: PASS
  • Dimension 6 Registry Safety: PASS

Approval: pending