Nous Portal & Hermes Agent
Designing a developer console from an existing visual language
- Client
- Nous Research
- Role
- Senior Product DesignerProduct UI, end to endDesign system owner
- Year
- 2025 – 2026
- Discipline
- Product DesignAI / ML InterfacesDesign SystemsWeb

Nous had a strong visual language and a growing number of places it needed to live. A language proves itself on the screens it was never drawn for — a billing table, a terminal with no colour guarantee, an empty state at 2am. My job was to extend it into those places without diluting it, and to make it reproducible by people who were not in the original conversations.
Concepts in, product out
Leigh Taylor set the visual language and the initial concept for the Portal itself. I designed the product from there — every screen, state and flow in the console. A concept tells you what something should feel like; it does not tell you what happens when a run fails at step thirty, or how a billing table behaves at 2am with three months of data in it. That gap is the work.

Research where the concepts ran out
I synthesised the 2025–2026 literature on agentic developer interfaces into a prioritised list — the W3C APG combobox pattern for the command palette, agent activity ledgers from the visibility-into-AI-agents work (arXiv 2401.13138), cost-transparency primitives, human-in-the-loop approval for spend-affecting actions — tiered by leverage and ticked off as each shipped.

The console
Token usage renders as ASCII glyph art with LINE / AREA / ASCII as a first-class toggle. A developer console can borrow an idiom its audience already reads fluently, and a terminal-native chart says more about what this product is than any amount of brand language.
Glyph art means nothing to a screen reader, so the chart is aria-hidden inside a container with role="img" and a text summary. A crosshair HUD prints values as a status line rather than a tooltip that covers the data it describes.

Running agents, and stopping them
An agent card carries two independent signals: whether it is online, and whether it is healthy. Collapsing those into one status light is the obvious simplification and it fails exactly when it matters — an agent can be stopped and fine, or running and broken, and those need different responses from the person looking at it.
The available actions change with state rather than greying out. A running agent offers recovery, access control, channel configuration and stop; a stopped one offers start and delete. Nothing is shown that cannot be done.
Colour carries meaning consistently: amber for warnings that need attention, red only for actions that are irreversible or states that need it — stop, delete, offline. Reserving red rather than spending it on every alert is what keeps it legible when an agent is about to be destroyed.

What it costs, and why
Usage runs across the top as one row of tiles — spend, requests, input and output tokens, cache reads — and breaks down per model and per tool call below, so an unexpected bill has a traceable cause. The sidebar carries the number that actually matters day to day: balance, burn rate, and how long the money lasts. "$10 · run out in 30 days · $0.3/day" is a more useful sentence than any chart.
Billing was the hardest information design in the product. Subscription credits expire and roll over by plan rules; top-up credits never expire; usage draws down subscription credit first. That is three rules a user has to hold at once before they can predict their own bill, and getting it wrong means either a surprise charge or an agent that stops mid-run.
The page states the precedence in one sentence and then shows the two balances separately rather than collapsing them into a single misleading total. Auto-refill exists but carries its own guardrail — a trigger threshold, a refill amount, and a monthly ceiling — because an automated action that spends money without a stated limit is not a convenience.
The low-balance warning is amber. Red is the obvious choice and the wrong one here: saturated red adjacent to this blue produces a chromostereopsis shimmer, which the contrast audit had already flagged. The tier CTAs escalate rather than repeat — Try, Unlock, Unleash, Liberate — so the pricing table reads as a ladder instead of four identical buttons at different prices.

Keyboard first, because the audience is
The navigation rail is numbered 1–6 and those keys jump straight to a section, with a ⌘K palette over the top. Single-key shortcuts are suppressed inside inputs and contenteditable regions per WCAG success criterion 2.1.4 — the detail that separates a keyboard interface from a keyboard trap.

Consent in plain language
For an AI product the prompt is the sensitive thing, so the data-use choice cannot hide behind a policy link. Privacy Mode states its consequence directly: inference payloads are not stored, not used for training, product improvement or support, and inputs remain volatile. The alternative is written just as plainly rather than being framed as the generous default.
Email preferences say what they do not cover, too — transactional mail about account activity, billing and security still sends regardless of any toggle. A preference screen that only advertises what it switches off is quietly dishonest, and users find out at the worst moment. Only critical announcements are on by default.

The system
I extracted the language into tokens named for the role they play rather than the value they hold — BG/Primary-Background/Main, Text/White-Background/Secondary — which is what let it survive a terminal, where a background colour cannot be guaranteed. Sigurd Variable for display, DM Sans for body, DM Mono for captions and buttons. It ships as a real codebase rather than a Figma file with a handoff ritual attached.
Auditing the palette
I computed the contrast matrix and wrote down the failures as carefully as the passes. #0000f2 on #f5f5f5 is 8.4:1 and clears AAA. Dark text on that blue is 2.1:1 and is never allowed. The blue on near-black is 2.2:1, so a dark theme needs a lighter blue entirely. Saturated red beside it shimmers, and a blue focus ring on a blue active pill is invisible until you swap it for currentColor.