Shared Primitives, Different Affordances
As developer and data platforms mature, they tend to sprawl across surfaces: command-line tools, IDE integrations, APIs, and increasingly rich web UIs. Each surface serves a different mode of work, a different cognitive posture, and often a different class of user. The challenge isn’t simply supporting all of them—it’s creating continuity across them without collapsing everything into a lowest-common-denominator experience.
At Gauge, we've seen this evolution firsthand at companies like Loggly, npm, Remediant, and others building internal or developer-facing platforms at scale. The tension shows up everywhere: power users want speed and expressiveness, newer users need guidance and visibility, and organizations want coherence without constraining innovation. When it goes wrong, you get fractured systems, duplicated concepts, and users who feel like they’re relearning the product every time they switch contexts.
When it goes right, users move fluidly across tools, carrying the same mental model with them—even though each surface feels purpose-built.
The Trap of “Unification”
Many teams approach multi-surface design with the goal of unification. On paper, this sounds sensible: one experience, one system, one way of doing things. In practice, unification often means abstraction. And abstraction, when pushed too far, becomes flattening. We’ve seen platforms try to:
- Make the UI a visual wrapper around the CLI
- Force feature parity across all surfaces
- Reduce expressive workflows to accommodate point-and-click interactions
The result is usually unsatisfying for everyone. Power users feel constrained. The UI feels like a compromised development environment.
The problem isn’t that teams want coherence—it’s that they mistake sameness for continuity.
The CLI becomes bloated with concepts that don’t belong there. And the underlying system becomes harder to evolve because every change must be reconciled across every surface.
Continuity Is About Mental Models, Not Interfaces
True continuity doesn’t mean identical interactions. It means shared understanding. Across IDEs, CLIs, and UIs, users should encounter:
- The same core entities (packages, services, datasets, metrics, jobs)
- The same relationships (dependencies, lineage, ownership)
- The same intent behind actions, even if execution differs
- The same source of truth, surfaced differently
At npm, for example, publishing a package via the CLI and exploring it in the UI were radically different experiences—but they reference the same conceptual object. Versioning, ownership, and trust signals remain consistent. The user doesn’t have to translate between mental models when switching contexts.
This is the distinction that matters: conceptual parity without interaction parity.
Respecting the Strengths of Each Surface
Each surface has native affordances, and good design starts by honoring them rather than fighting them.
- CLI is optimized for speed, composition, automation, and repetition. It excels at expressing intent succinctly and chaining workflows together.
- IDE integrations support flow, context, and immediacy. They’re where users make decisions while working in code.
- UI excels at discovery, comparison, explanation, and reflection. It’s where users step back to understand systems, diagnose issues, and onboard others.
Problems arise when teams try to make one surface behave like another. A UI that mimics an IDE rarely feels good. A CLI overloaded with exploratory concerns becomes unwieldy.
The goal isn’t to blur boundaries, but to design transitions between them.
At Loggly, this meant allowing engineers to move from a CLI-driven deployment or query straight into a UI view that provided richer context—historical trends, anomalies, or cross-service correlations—without changing the underlying model of what they were working on. One useful framing we’ve seen work is to design the system around shared primitives, then let each surface expose those primitives differently. For example:
- A “job” is a job everywhere—but in the CLI it’s an ID and a status, while in the UI it’s a timeline with logs, retries, and lineage.
- A “metric” has the same definition in code and in dashboards, but the UI layers on validation, freshness indicators, and ownership metadata.
- A “dependency” is a graph edge in the system, but a navigable diagram in the UI and a reference in code.
This approach allows teams to maintain conceptual integrity without forcing uniform interactions. It also makes it easier for users to move between surfaces because they’re not learning new nouns every time—just new verbs.
Avoiding a Lowest-Common-Denominator Abstraction
The most dangerous design move in multi-surface systems is designing everything to the weakest surface. This often happens unintentionally, driven by good intentions: making things simpler, more accessible, more consistent.
But when every experience is designed around what can be represented everywhere, you end up with:
- Underpowered workflows
- Excessive constraints
- A system that resists advanced use cases
Instead, teams should decide explicitly where expressiveness lives, and where guardrails live.
At Remediant, security workflows required deep, sometimes risky actions. The CLI allowed precise, auditable commands for experts. The UI emphasized review, simulation, and approval. Both interacted with the same underlying model, but each was optimized for its role in the workflow.
Continuity came from shared concepts and trust signals—not from forcing identical capabilities.
Designing for Transitions, Not Just Surfaces
One of the most overlooked aspects of continuity is how users move between surfaces. Good questions to ask:
- How does a user go from a failed CI job to understanding root cause?
- How does a definition created in code become visible and trustworthy in the UI?
- How does exploratory work in the UI translate back into reproducible artifacts?
Designing these handoffs intentionally—often through deep linking, shared identifiers, and consistent language—does more for continuity than surface-level alignment ever will.
When users feel like they’re continuing a task rather than starting over, the system feels coherent.
What This Requires Organizationally
This kind of continuity doesn’t emerge from individual features. It requires:
- Strong system-level ownership
- Shared design principles across teams
- Agreement on core concepts and language
- Willingness to say no to forced parity
It also requires designers to think beyond screens and flows, and engage deeply with architecture, APIs, and developer workflows. The most effective designers we’ve worked with in this space weren’t trying to make everything “simple”—they were trying to make the system feel legible.
Closing Thought
Designing across IDEs, CLIs, and UIs is not about convergence. It’s about coherence.
When teams respect the strengths of each surface, anchor experiences in shared mental models, and design transitions as first-class experiences, users gain confidence. They trust the system. They move faster. And they stop feeling like the platform is fighting them.
That’s the real payoff—not uniformity, but fluency.