Skip to main content
Back to Blog
/ 7 min read

Designing for Intent, Not Screens

A technical walkthrough of how DeepHarness's CommandBar resolves intent to flow type to agent routing to streamed response — and why fixed screens are dead.

M
Martin

For twenty years, product design has been about screens. You define a set of views. You build navigation between them. You fill each view with components that display data or collect input. The user’s job is to find the right screen for their task.

This model assumes the product team can anticipate every task. That assumption was always wrong — it was just less visibly wrong when products were simpler. A dashboard with four views can plausibly cover the space. A platform that handles data discovery, visualization, monitoring, advisory analysis, and multi-agent orchestration across any data domain cannot.

We stopped designing screens. We started designing for intent.

The Cognitive CommandBar

The CommandBar is a single input surface. You open it, describe what you need, and the system routes your intent through a pipeline that selects the right agents, the right model tier, and the right output format. The result is not a navigation event — it is a generated response that may include charts, dashboards, configurations, or analysis, assembled from components that match your specific request.

The pipeline has six stages, and each one makes a decision that shapes the response.

Stage 1: Intent Classification

Every query enters quickClassify(), which produces an aiIntent — a discrete classification of what the user is trying to accomplish. The classification is deterministic and fast. It does not call an LLM. It uses a combination of keyword detection, entity recognition, and pattern matching to map the query to one of several intent types: dashboard generation, agent building, data analysis, monitoring, advisory, and general conversation.

The classification has a priority hierarchy. If a query mentions both “dashboard” and “agent,” the dashboard intent wins. The reasoning is that the user wants a dashboard that uses agents, not a new agent that happens to involve dashboards. This priority ordering was learned from production usage patterns, not assumed from first principles.

If the query contains two or more @mentions of specific agents, the intent is forced to group-chat regardless of the query content. @mentions are an explicit signal that overrides classification.

Stage 2: Flow Type Resolution

The aiIntent maps to a FlowType, which determines which handler processes the request. There are four flow types, and the mapping is deterministic:

Dashboard generation routes to the general chat flow with the dashboard_builder agent and a create_dashboard tool. Agent building routes to the agent builder flow with the agent-builder agent and a deploy_agent tool. Group chat routes to the group chat flow, which runs round-robin conversations across the mentioned agents. Everything else routes to the general chat flow with SSE streaming.

The flow type determines the API endpoint, the agent configuration, the available tools, and the response format. This is the architectural decision that separates “describe what you want” from “get a coherent response” — the flow type is the bridge.

Stage 3: Agent Selection via Q-Learning

Within the flow handler, agent selection is not a lookup table. It is a reinforcement-learning problem.

The Q-learning router encodes the current state as a tuple of four components. The intent hash maps the classified intent to one of 11 discrete values. The complexity bucket scores the query from 0 to 100 and buckets it into simple, moderate, or complex. The entity bitmask encodes which entity types appear in the query — data sources, metrics, time ranges, comparisons, thresholds, geographic references — as a 6-bit mask. The recent agent hash captures conversational momentum by hashing the last agent used.

Action selection is epsilon-greedy with decay. Epsilon starts at 0.15 and decays to 0.01 over time, which means the router explores aggressively early and exploits learned values as it accumulates experience. The Q-table maps state-action pairs to expected values, updated via Bellman equations after each interaction.

Training uses experience replay with a circular buffer of 10,000 interactions and batch updates of 32. The Q-table is persisted to disk every 50 updates and survives server restarts. The router gets better with use — not because of periodic retraining, but because every interaction produces a training signal.

This is what replaces the “which screen should I navigate to?” problem. The user states intent, and the system routes it to the agent most likely to produce a good outcome, based on learned experience with similar queries.

Stage 4: The Delegate Tool

Many queries require more than one agent. A request to “build a dashboard showing API latency by region with alerting when p99 exceeds 500ms” involves data discovery, visualization recommendation, widget configuration, and monitoring setup. No single agent covers all of that.

The delegate tool enables inter-agent communication within a single request. The primary agent — typically general — can call any specialist agent as a tool invocation. The specialist executes, returns its result, and the primary agent incorporates it into the response.

Three constraints prevent abuse. Delegation depth is capped at 3 — an agent can delegate to a specialist, which can delegate to another specialist, but no further. An agent cannot delegate back to general, which prevents cycles. And each delegation emits SSE events — delegate-start and delegate-complete — so the user sees the delegation chain in real time.

The delegate tool is what makes the system feel like a single coherent agent while actually running a distributed computation. The user does not need to know that their request was handled by three specialists coordinating through delegation. They see a single response.

Stage 5: The StreamClassifier

The API returns results as Server-Sent Events. Raw SSE is a flat stream of typed events — text-start, text-delta, tool_call_start, tool_call_end, delegate-start, delegate-complete, done. This is useful for the transport layer but meaningless to the user.

The StreamClassifier transforms this flat stream into three cognitive phases that the UI renders as a progression.

Observe corresponds to intent classification and context gathering. When the system acknowledges the query, identifies relevant agents, and scopes the data sources, the StreamClassifier maps those events to the Observe phase.

Reason corresponds to routing and planning. Agent selection, model tier determination, delegation strategy, and blueprint generation are mapped to the Reason phase.

Act corresponds to execution and output. Data retrieval, chart rendering, configuration generation, and final response assembly are mapped to the Act phase.

The mapping is based on event types and sequences, not on content analysis. A delegate-start event always maps to the Reason phase. A tool_call_end event with a widget result always maps to Act. This makes the classification deterministic and fast.

The result is that the user sees the system thinking through their request in a structured way, rather than watching a stream of text appear character by character. The cognitive phases make the system’s process legible.

Stage 6: Widget Registry and Component Contracts

When the pipeline produces a dashboard or visualization, the output is not raw HTML. It is a set of widget selections from a registry of 60+ components, each bound to data and arranged in a layout.

Each widget in the registry is defined as a contract: the data shape it accepts, the configuration options it exposes, the layout constraints it respects, and the interaction patterns it supports. A line chart widget accepts time-series data with a specific schema. A funnel chart widget accepts stage data with conversion rates. A geographic choropleth accepts region-keyed numeric data.

The agent does not generate the component. It selects the contract that matches the data and intent, configures it, and binds data. The registry handles rendering. This separation is what makes generated-on-demand interfaces reliable — the components are pre-built and tested, and the generation is limited to selection and configuration.

Default positions and sizes are defined per widget type, but layouts are responsive to the combination of widgets selected. A dashboard with two charts and a metric card lays out differently than one with six charts and a data table. The layout is a function of the selection, not a fixed grid.

Why Fixed Screens Are Dead

The six-stage pipeline replaces the screen paradigm with something fundamentally different. A screen is a pre-built answer to an anticipated question. The CommandBar pipeline generates answers to questions the product team never anticipated, using agents that learn which answers work, components that are assembled on demand, and a narration layer that makes the process visible.

This does not mean screens disappear entirely. Navigation, settings, account management — these are fixed surfaces that serve fixed functions. But the core experience of “I need information” or “I need something built” no longer routes through a hierarchy of pre-built views. It routes through intent classification, agent selection, delegation, and component assembly.

The interface becomes a function of the query. Not a map of the product. Not a hierarchy of features. A function that takes intent as input and produces an interface as output.

That is what designing for intent looks like in practice. Not as a design philosophy. As an architecture.