Skip to main content
HUMΛN
Architecture
Architecture

The Companion is the new AI UX

rick··10 min·Technical

Every AI product ships the same interface: an empty text box and a cursor. The implicit contract is brutal — you figure out what this thing can do, you phrase it correctly, you discover the boundaries by trial and error. We have spent three decades teaching users that software shows them what it can do. Then we handed them a blank rectangle and called it the future.

This is the blank canvas problem, and it is quietly killing AI products. Not at the demo — demos are scripted, the presenter knows the magic words. It kills them in week two, when a real user stares at the input field, types something the system half-understands, gets a mediocre answer, and concludes the product is a toy. The capability was there. The user just had no way to find it.

The industry's answer so far has been two bad options. This post is about the third one — and what it actually takes to build it.

Option one: the chat box that hides everything

A chat interface has perfect affordance for exactly one action: typing. Everything else — every connector, every workflow, every report the system can generate — is invisible. Discoverability is delegated to the user's imagination.

The numbers behind this are unforgiving. If your AI product can do 200 things and the user can name 6 of them, your effective surface area is 6. The other 194 capabilities are sunk engineering cost. Worse, the user doesn't know there are 194 more — so they don't go looking. A feature that cannot be discovered does not exist.

Chat-first products try to patch this with onboarding tours, example prompts, and "try asking..." placeholders. These help for the first session and decay immediately after. The structural problem remains: capability lives in the model's weights and the platform's integrations, while discovery lives in the user's head. Nothing connects them.

Option two: the dashboard trap

The enterprise reflex is the opposite move: take the existing admin UI — sidebar, tabs, settings pages, forty routes — and bolt an AI assistant onto the corner. A sparkle icon. A drawer that slides out.

This produces what you might call AI as a feature: the assistant becomes one more item in the navigation, siloed away from the actual work. Users learn that the "real" way to do anything is still the dashboard — the AI drawer is for asking questions the docs should have answered. The assistant can't take actions because the actions live in the dashboard's forms. The dashboard can't explain itself because the intelligence lives in the drawer. You've built two products that share a login.

The deeper failure is architectural. Every navigation item you add competes with the assistant for the user's intent. If rescheduling a workflow means clicking through Settings → Workflows → Edit, the assistant that could do it in one sentence never gets asked. The org chart of your UI defeats the intelligence of your model.

HUMΛN's Companion canon names this failure mode precisely: the escape hatch. The moment users discover they can bypass the conversational surface for "important" tasks, they will — and the AI layer decays into a novelty. Our Rule 1 is blunt about it: the Companion IS the product. There is no "switch to classic view." If a capability cannot be expressed as a Companion intent or canvas, that is a product design failure requiring architectural resolution — not a UI shortcut.

The third way: the conversational surface is the platform

The resolution isn't a better chat box or a smarter dashboard. It's a different contract between capabilities and the interface: capabilities register themselves into the discovery surfaces, outputs are typed artifacts rather than prose, and the surface itself behaves like a living system.

In the Companion, this contract has four load-bearing parts.

1. Capabilities announce themselves

Every bundle installed on the platform — a finance pack, an HITL operator kit, a marketplace integration — must declare commands. Not "may." Must. An empty commands[] array fails validation in CI, because a bundle without commands is invisible: the palette can't surface it, the intent classifier can't route to it, the Companion can't auto-invoke it.

This is the actual interface, from packages/platform-extensions:

export interface BundleCommand {
  /** Unique within the bundle, e.g. 'show_approvals' */
  id: string;
  /** Display name shown in the palette, e.g. 'Show approvals' */
  name: string;
  /** One-line description shown in the palette */
  description: string;
  /** 'lucide:<IconName>' scheme or absolute URL to icon image */
  icon: string;
  /** Palette slash shortcut, e.g. '/approvals' */
  shortcut?: string;
  /** Grouping label in the palette UI */
  category?: string;
  /** If set, this command opens this canvas kind */
  canvas_kind?: string;
  /** Natural-language phrases the intent classifier can match */
  intent_triggers: string[];
  /** When true, the Companion may invoke without explicit user confirm */
  autonomous_ok?: boolean;
}

Look at intent_triggers. A command isn't just a palette entry — it's a set of natural-language hooks the intent classifier matches against live conversation. When a user types "show my pending approvals," the classifier doesn't free-associate against the model's general knowledge; it routes to a registered command with a known canvas, known permissions, and a known consequence level. When they type /approvals, the shortcut resolves directly. Two paths, one registration, zero guessing.

This inverts the blank canvas problem at the root. Discovery is no longer a documentation problem or a prompt-engineering problem. It's a manifest problem — and manifests are enforceable. The capability and its discoverability ship as one artifact, validated together, versioned together.

2. Output is typed canvases, not prose

A chat model answering "how did revenue trend last quarter?" with four paragraphs of text is doing the work and then throwing away the structure. The Companion doesn't return prose for structured questions. It returns a canvas — a typed, versioned, provenance-stamped artifact rendered by the platform.

There are currently 29 canvas kinds in CanvasKind: data_table, chart, decision_matrix, timeline, kanban_board, workflow_diagram, diff_view, solution_plan, execution_status, decision_trace, whiteboard, spreadsheet, metrics_dashboard, and more. Each has a strict data contract. Here is the chart contract — note that the AI writes intent, and the platform owns rendering:

export interface ChartCanvasData {
  kind: 'chart';
  chart_type:
    | 'bar' | 'line' | 'area' | 'scatter' | 'pie' | 'donut' | 'histogram'
    | 'heatmap' | 'funnel' | 'treemap' | 'sankey' | 'radar' | 'waterfall'
    | 'candlestick' | 'bubble' | 'gauge' | 'boxplot';
  data: Record<string, unknown>[];
  x?: string;
  y?: string | string[];
  title?: string;
  stacked?: boolean;
  /** Pass-through for advanced customization; AI should not use this. */
  advanced?: Record<string, unknown>;
}

The model declares "bar chart, this data, x is month, y is revenue." It never emits SVG, never hallucinates a charting library, never produces a different visual style on Tuesday than it did on Monday. The declarative gap between AI intent and platform rendering is where consistency lives.

And canvases aren't screenshots of an answer — they're live objects. The full CanvasSpec carries actions (each with a consequence level and a requires_confirmation flag), data_bindings for live data, an agent_did identifying which agent produced it, and a provenance_receipt_id linking it to the audit chain. A canvas knows who made it, what it's allowed to do next, and how to prove both. Try retrofitting that onto a markdown response.

3. Discovery is structural, not aspirational

The Companion has exactly three discovery surfaces, and adding a fourth requires a canon amendment:

  1. The command palette — type / and every registered command appears, grouped by category, filterable, keyboard-navigable. This is the union of everything installed bundles have declared. It cannot drift from reality because it is generated from reality.
  2. Contextual suggestion chips — at most 3 visible, drawn from a pool of 9, ranked against the current conversation, installed connectors, and active signals. Chips cycle when dismissed. They are the system saying "given where you are, here's what's adjacent."
  3. The home canvas — a briefing hard-capped at 5 cards, ranked by priority: pending approvals first, degraded-connector alerts second, recent work, then suggestions. The cap is a runtime invariant enforced by the backend, not a styling choice. If the briefing service has nothing worth saying, no canvas opens at all — the Companion just talks.

That 5-card cap deserves a beat. The instant a home surface exceeds a handful of items, it becomes a dashboard, users treat it as a task list, signal-to-noise collapses, and you've rebuilt the thing you were escaping — except now it's generated by an LLM, so it's a noisy dashboard. Restraint here is not minimalism for its own sake. It's the difference between a briefing and a backlog.

4. The surface is alive

This part sounds cosmetic and isn't. Every canvas in the product opens and closes with spring physics — { stiffness: 280, damping: 26, mass: 0.8 }, defined once in canvas-physics.ts and imported everywhere. No hard cuts, no display: none toggles, no per-component CSS transitions drifting out of sync. On mobile, canvases slide up from the bottom with a stiffer spring and close on a swipe that crosses 35% of the canvas height.

Why elevate animation constants to canon? Because the Companion's core claim is that canvases are living things — artifacts that appear, grow, update, and recede as the conversation moves. If one canvas springs into view and another blinks in via CSS transition, the illusion of a coherent physical world breaks, and with it the user's intuition that these objects are part of one system. Physics is the body language of the interface. Inconsistent body language reads as dishonesty, even when nobody can articulate why.

This is a paradigm, not a feature

It's tempting to read the above as a UI skin you could add in a sprint. The dependency graph says otherwise. To make the conversational surface the platform, you need:

Intent routing as infrastructure. Matching "show my pending approvals" to a registered command requires a classifier that ranks against every installed bundle's intent_triggers, scoped to this org's installations. That's an index (CommandIndexService builds it per org, cached), a resolution endpoint, and a confidence model deciding when to act versus when to ask.

Typed canvas contracts. Twenty-nine kinds means twenty-nine data contracts, twenty-nine renderers, and a versioning story for each. The discipline that the model writes declarative intent — never markup — has to be enforced at the schema boundary, or entropy wins.

Governance underneath. A surface where AI can take actions is only shippable if every action carries identity and consequence metadata. Each CanvasAction declares its consequence level (low/medium/high) and whether confirmation is required. Every canvas carries the DID of the agent that produced it and a provenance receipt. The conversational surface can only be the product because the trust layer beneath it makes every action attributable, scoped, and auditable. Without that substrate, "the AI can do everything from chat" is a security incident with good UX.

None of this is a feature flag. It's an architecture — which is exactly why most teams bolt a drawer onto a dashboard instead.

The stakes

The transition we're in looks like the GUI transition of the 1980s, with the same trap. Early GUI software was command-line programs with menus stapled on; it lost to software designed around direct manipulation from the first line of code. Today's equivalent: chat stapled onto dashboards, losing to products where the conversational surface is the architecture.

The blank canvas problem is the moat, because solving it can't be faked. You can fine-tune a friendlier model in a quarter. You cannot retrofit self-registering capabilities, typed artifact contracts, structural discovery, and a governance substrate onto a 40-route admin panel without rebuilding it. The products that win the AI UX transition will be the ones where a user's third session is more capable than their first — because the system kept showing them what's adjacent — and where every one of those capabilities arrived with its own discoverability, enforced at CI time, rendered with the same physics as everything else.

That's what the Companion is: not a chat feature on a platform, but the platform wearing a conversational face. The reference implementation argument is simple — these rules are written down as canon, enforced in validators and tests, and shipped in production types you can read. The blank canvas is a choice. Stop making it.


This is Part 1 of the Companion Platform Series. Part 2: Building discoverable AI capabilities. Part 3: AI-native mobile UX.