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

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:

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
routeorcommandIdfrom 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