Skip to content

ADR: Build a generic "canvas-mode" shell in nova-frontend-litjs instead of a console-specific chat UI

Context

The Figma flow for new-hire-preboarding-console (design/figma-export.md, node 576:13854) specifies every screen as the same shell: a persistent chat-glass-panel (the "Nova" conversational agent, left) plus a canvas (the step-specific content, right — heading, body, and primary/secondary CTA buttons). The candidate advances either by talking to Nova or by clicking a canvas button; both must drive the same step state.

No such component exists today. A repo review across the four candidate homes for this UI turned up:

  • nova-frontend-litjs/src/policy-editor/ — the only existing two-panel "chat left, content right" component in the codebase. It's a real precedent for panel layout and for a chat turn triggering a change in the other panel, but it is wired specifically to nova-advisor-agent's own WebSocket protocol (/ws/chat + /ws/yjs/{room} for Yjs collaborative document editing) and to policy-review semantics (accept/decline changes). Extending it directly would mean either dragging Yjs/policy concepts into onboarding, or forking it — both wrong.
  • nova-frontend-litjs/src/nora-widget-ionic/home-page-web.ts — the generic superagent chat surface used across Nova. It is single-pane: full chat overlay with a step accordion rendered inside the chat thread (nova-status-accordion), not a separate content panel. Its SSE contract (agent_dispatch / fa_node / agent_result / text chunks, per nova-frontend-litjs's own flow.md) has no notion of "render this in a side panel."
  • nova-superagent-agent — grepped for any existing widget-render directive (render_widget, ui_action, open_widget, etc.). None exists. The agent can stream text and step-status updates into a chat thread; it cannot currently instruct a frontend to show specific canvas content.
  • nova-frontend-sn-app — a passive ServiceNow portal shell that loads sp_instance widgets (including the litjs bundle). It has no canvas concept of its own and isn't the runtime host for the guest console anyway (nova-guest-console-app is a standalone Novaworks-portal app, per its own KB).
  • nova-guest-console-app — currently a plain task-list React app with no persistent-chat-driving-canvas behavior at all.

Building this as a one-off inside nova-guest-console-app's React frontend would satisfy this Feature alone, but the explicit ask was for something reusable across web, mobile (nova-frontend-mobile), and SN-hosted surfaces — the same reuse boundary every other nova-frontend-litjs component already respects.

Decision

Build a new, generic canvas-mode shell component in nova-frontend-litjs, not inside nova-guest-console-app and not as an extension of policy-editor:

  • New component (name TBD at implementation, e.g. nova-canvas-shell): persistent chat panel (reusing nora-ask-widget/nora-chat-input primitives, not policy-editor's WS client) + a swappable canvas slot that any consumer fills with step-specific content (heading, body, CTA buttons) — modeled on the Figma shell's stageLabel → title → subtitle → contentStack → cta structure, generalized rather than hardcoded to onboarding.
  • The canvas advances via either input path, both converging on the same step-state update: a canvas CTA button click, or a chat-driven directive from the agent.
  • The chat-driven path requires new capability in nova-superagent-agent: an explicit SSE directive (e.g. canvas_step or similar — exact shape is an implementation detail, not decided here) distinct from today's text/step-accordion vocabulary. This is real backend work, not just a frontend component — call it out as its own task when this Feature Set reaches Construction.
  • policy-editor stays exactly as it is (Advisor-specific, WS/Yjs-based). It's cited here as prior art for panel CSS/layout conventions to borrow from, not a dependency to extend.
  • nova-guest-console-app's React frontend consumes the new shell the same way it already consumes other @novaworks/lit-components widgets (file:./lit-components local dependency, per its KB) — no new integration pattern needed on that side once the component exists.

Consequences

  • new-hire-preboarding-console/spec.md's UX Description/Key User Flows depend on this shared component rather than a console-specific chat widget — implementation can't start on those flows until the shell (or at least its canvas-slot contract) exists in nova-frontend-litjs.
  • Mobile (nova-frontend-mobile) and any future SN-hosted step-driven flow get this pattern for free once built, instead of each reimplementing a two-panel chat UI — the reuse boundary this ADR exists to protect.
  • Adds a real, non-trivial backend task to nova-superagent-agent (the new SSE directive) that isn't captured in this Feature's spec.md yet — flagged as an open item there and must be scoped before implementation-plan.md is written for this Feature.
  • Risk: without a concrete SSE directive shape agreed early, frontend and agent work can drift out of sync — the directive's request/response shape should be nailed down (even informally) before either side starts coding, not discovered independently by both.
  • Risk: policy-editor and the new shell will look superficially similar (both two-panel, both chat-driven) — future contributors need to be told explicitly not to converge them, since their protocols and domains are genuinely different; see the KB pattern note added to nova-frontend-litjs/skills.md.