Skip to Content

← All archived intake epics

Intake: agentic-ui-polish

breakdown.md

Breakdown: Agentic interface UI polish — shell and layout, then the conversation

  • scope-slug: agentic-ui-polish · source: Jamie's intake interrogation (2026-08-27); no scope.md behind this batch. Rulings quoted per stub.
  • initiative: Scale the bridge / objective: Q2-2026 Objective 3 — Validate Technical Infrastructure & Payout Flow (inherited from agentic-app-foundation, the batch that built this app; the tie is as indirect for polish as it was for the scaffold — flagged, not dressed up)
  • personas: Admin, CSM, SDM, Expert, Vendor, Customer

What I understood

The agentic app shipped as a deliberately minimal cut: one full-screen chat, a slim header (name + sign-out), a two-line "Ask me anything" empty state, a detached "Thinking…" shimmer, and alert boxes bolted above the input for degraded availability and failed turns. Jamie confirmed all four cross-cutting irritations — mobile viewport/keyboard behaviour, the max-w-3xl column framing on large screens, the bolted-on banner styling, and generic-not-Sustentus brand — and ruled the polish visual/UX refinement only (2026-08-27). The one item at the functional edge that is IN: a branded welcome with generic starter-prompt chips that send through the existing send path — generic because the assistant has no workspace data access yet, revised when it does.

Timing is a deliberate ruling, not an accident of the queue: this batch runs after ai-platform-enablement/agentic-tenant-context has shipped (Jamie, 2026-08-27) — one polish pass over surfaces that have their tenant/role context, instead of polishing copy and states that batch is about to change. A cross-batch prerequisite cannot be a depends-on: (those are in-batch), so it is recorded here and in each stub's Notes for Define: check agentic-tenant-context's state at pickup.

Where it sits

Not a product seam — the agentic layer itself (apps/agent, the agentic-interface Vercel project). No service-journey step or feature-role-matrix entity changes; all work lands in apps/agent (plus packages/ui where a chat refinement is genuinely reusable — the Message/PromptInput primitives live there). The services boundary is untouched: the app keeps importing only @sustentus/services/ai, and nothing here adds data access — that is agentic-tenant-context's job, which this batch waits for but does not build on.

Build order

  1. agent-shell-layout-polish — header (UserButton, platform link, theme toggle), column framing, mobile viewport, brand foundation — depends-on: none
  2. agent-chat-experience-polish — branded welcome + starter prompts, message-level refinements, in-flow status and error presentation — depends-on: agent-shell-layout-polish

Parallelizable

A plain chain — stub 2 styles the conversation inside the frame stub 1 establishes.

Out of scope (whole scope)

  • Conversation persistence, history, or multi-conversation — the chat stays ephemeral by design; changing that is a scope, not polish.
  • Workspace-data-aware chat or prompts. The starter chips are generic conversation starters; wiring tenant data into the conversation belongs to the ai-platform-enablement surfaces.
  • Any change to /api/chat or /api/ai/availability behaviour, the availability probe's semantics, or the error-sanitisation policy (raw provider errors stay out of the DOM).
  • proxy.ts, the "authenticated user" gate, and Clerk configuration.
  • The platform's own AI surfaces in apps/web, and the later redirection batch.

_done/agent-chat-experience-polish.md

Stub: Assistant conversation experience polish

  • feature-slug: agent-chat-experience-polish
  • scope: agentic-ui-polish
  • personas: Admin, CSM, SDM, Expert, Vendor, Customer
  • initiative: Scale the bridge / objective: Q2-2026 Objective 3 — Validate Technical Infrastructure & Payout Flow
  • depends-on: agent-shell-layout-polish
  • sequence: 2 of 2

Problem

The conversation surface is functional but bare: a two-line centred empty state, assistant replies distinguished from the user's only by bubble alignment, no way to copy a reply, no sense of time, a "Thinking…" shimmer detached from the conversation, and degraded/error alerts that sit bolted above the input rather than belonging to the exchange they describe. For the app that is supposed to be the platform's agentic face, the conversation itself is the least designed thing in it.

Proposed change

A pass over assistant-chat.tsx and the shared Message/PromptInput primitives it uses:

  • Branded welcome with starter prompts — brand mark, proper copy hierarchy, and 3–4 clickable generic conversation-starter chips that send through the existing sendMessage path. Generic on purpose: the assistant has no workspace data access from the chat yet; the chips get revised when data-aware surfaces land.
  • Message-level refinements — an assistant brand mark on replies, copy-to-clipboard on assistant messages, subtle timestamps, and a streaming affordance that lives in the reply bubble and transitions into the streamed text instead of a detached shimmer line.
  • In-flow status presentation — restyle the degraded-availability notice and the turn-failure alert to sit naturally in the conversation, keeping their exact semantics: the sanitised copy, the non-blocking degraded behaviour, and the send-while-errored retry affordance are all deliberate and stay.

Acceptance criteria (rough)

  • The empty state shows the branded welcome; clicking a starter chip sends that text as a normal user turn.
  • Assistant replies carry a brand mark, a copy action, and a timestamp; user messages remain visually distinct; both themes correct.
  • While a turn streams, the pending affordance appears where the reply will be and resolves into it without layout jump.
  • Degraded and error states render in the conversation flow with today's copy and today's behaviour — sending stays possible in both.

Out of scope (this feature)

  • Conversation persistence or history — refresh still starts fresh, and the welcome copy still says so.
  • Any change to /api/chat, the availability probe, or what the error messages reveal.
  • Data-aware starter prompts or any read of tenant data.

Notes for Define

Jamie's rulings (2026-08-27): all four message-level refinements IN (identity, copy, timestamps, streaming affordance); chips are generic-now-revise-later; banner restyle IN with semantics frozen. Mind the send-guard comment in assistant-chat.tsx — PromptInput resets the form before the submit handler runs, so the errored-state send path must survive the restyle. Cross-batch timing: runs after ai-platform-enablement/agentic-tenant-context ships — check at pickup whether the empty-state "can't reach your workspace data yet" claim is still true and word the welcome accordingly. Chat primitives live in packages/ui (Message, MessageContent, MessageResponse, PromptInput, Shimmer) — refinements that are reusable belong there with Storybook coverage, app-specific ones stay in apps/agent. touches: apps/agent/components/assistant-chat.tsx, packages/ui/src/compound/ai/, apps/storybook/.

_done/agent-shell-layout-polish.md

Stub: Agent app shell and layout polish

  • feature-slug: agent-shell-layout-polish
  • scope: agentic-ui-polish
  • personas: Admin, CSM, SDM, Expert, Vendor, Customer
  • initiative: Scale the bridge / objective: Q2-2026 Objective 3 — Validate Technical Infrastructure & Payout Flow
  • depends-on: none
  • sequence: 1 of 2

Problem

The agent app's frame is the scaffold cut: a header with a plain name and a Sign out button where every other Sustentus app shows the Clerk UserButton, no way back to the platform, no surfaced theme toggle despite next-themes being wired, an h-screen layout that fights mobile browser chrome and the on-screen keyboard, and a max-w-3xl column that floats unframed on large screens. It reads generic, and the conversation polish (stub 2) would be styling messages inside a frame that undermines them.

Proposed change

A pass over apps/agent/app/page.tsx, layout.tsx and globals.css, per the brand-guidelines skill: replace name + Sign out with the standard Clerk UserButton; add a visible link back to the platform app; surface the dark/light theme toggle; make the full-height layout behave on mobile (dynamic-viewport sizing, input never hidden by the keyboard, no scroll-jumping); and frame the conversation column deliberately on large screens. Brand typography and colour become the baseline stub 2 builds on. The gate stays "authenticated user and nothing finer", and /sign-in remains the only public route.

Acceptance criteria (rough)

  • The header shows the Clerk UserButton (sign-out lives in its menu), a platform link, and a theme toggle; both themes render correctly across the app.
  • On a phone, the input is visible and usable with the keyboard open, and sending does not jump the scroll position.
  • On a large screen the conversation column reads as deliberately framed — width, background and header alignment per the brand pass.
  • proxy.ts and the route surface are untouched; no new route is public.

Out of scope (this feature)

  • Everything inside the conversation itself — welcome, messages, banners are stub 2.
  • Conversation persistence, navigation, or any second page.
  • The platform-link's reverse direction (a platform → assistant entry point in apps/web) — that is an apps/web change and belongs to the later redirection batch.

Notes for Define

Jamie's rulings (2026-08-27): UserButton, platform link and theme toggle all IN; mobile viewport and column width confirmed irritations; visual/UX only. Cross-batch timing: this batch runs after ai-platform-enablement/agentic-tenant-context has shipped — check its state at pickup; if it landed role-aware chrome in the header, polish what exists rather than reverting it. The platform link target should be the platform's root URL from configuration, not a hardcoded domain — check how apps/web addresses its own origin before inventing an env var. touches: apps/agent/app/page.tsx, apps/agent/app/layout.tsx, apps/agent/app/globals.css, apps/agent/components/providers.tsx.