Architecture

Prev Next

Architecture

The Command Center is a pipeline. Data enters as domain-specific config and exits as user-facing results with executable intent.

Layered Design

Image

Each layer has exactly one job:

Layer Responsibility Does NOT
Data Raw domain configs and definitions Know about the index format
Adapter Transform domain data → IndexItem[] Contain execution or UI logic
Index Collect and hold the unified index Search, score, or rank
Search Score queries against the index, return ranked results Know about domains, execution, or UI
UI Render results, capture selection Perform search, transformation, or routing
Execute Dispatch navigation or action from selected result Know about search, scoring, or rendering

Data Flow

Step-by-step, from bootstrap to user interaction:

Image

Bootstrap (runs once at app init)

Step What happens Component
1 Domain configs are loaded (JSON imports, static defs) Raw data
2 Each adapter normalizes its domain into IndexItem[] Adapter functions
3 Registry collects all providers via register() IndexRegistry
4 Indexer calls registry.build() and holds the result Indexer
5 Engine initializes fuzzy search over the built index CommandEngine
// composer.ts — this is the entire bootstrap
setupCommandCenter(); // registers all adapters
indexer.build(); // builds unified index
commandEngine.init(); // initializes search

Runtime (runs on every query)

Step What happens Component
6 User types into the command palette UI
7 Engine runs fuzzy search over the index CommandEngine
8 Result adapter transforms library output → CommandResult[] fuseSearchResultAdapter
9 UI groups results by type and renders UI
10 User selects a result UI
11 Executor dispatches route or commandId CommandExecutor

Separation of Concerns

The architecture enforces strict boundaries:

  • Adapters are the only components that touch raw domain data
  • The index is the only data shape that crosses the adapter-to-engine boundary
  • The engine is the only component that touches the search library
  • The result adapter is the only component that touches library-specific output
  • The executor is the only component that performs side effects

No component reaches across its boundary. This means:

  • Replacing the search library requires changing one file (engine.ts + result.adapter.ts)
  • Adding a new domain requires changing zero core files (just a new adapter + register call)
  • Changing how results render requires changing zero data or search files

Design Principles

  • Adapters as boundaries — all data normalization, keyword enrichment, and structural flattening happens in adapters, not in the core system
  • Index as source of truth — the unified IndexItem[] is the single representation consumed by search; there is no second index or shadow state
  • UI as consumer — the command palette renders CommandResult[] and delegates selection; it does not search, filter, or transform
  • Execution is dispatch, not decision — the executor reads route or commandId from the result and acts; it does not decide what action to take
  • New capabilities = new data — extending the system means writing an adapter and registering it, not modifying existing code