Core Concepts
Every component in the Command Center exists to serve one question:
"How does the user's intent become a system action?"
This page defines the five primitives that answer it.
IndexItem
The canonical data shape of the Command Center. Every searchable entity — a route, an action, a setting, a piece of content — must be expressed as an IndexItem before it enters the system.
type CommandItemType = 'nav' | 'action' | 'entity' | 'content';
type IndexItem = {
id: string;
type: CommandItemType;
title: string;
description?: string;
keywords?: string[];
route?: string; // navigation target
commandId?: string; // action execution target
meta?: {
breadcrumb?: string;
module?: string;
weight?: number;
};
};
Rules
idmust be globally unique and stable. Convention:<type>.<domain>.<item>(e.g.nav.monetization.plans)typedetermines grouping in the UI and execution strategyrouteandcommandIdare mutually exclusive execution targetskeywordsdirectly control search recall — this is where search quality livesmetais for adapter-specific enrichment; the core system does not read it
IndexItem is the only shape that crosses the adapter boundary. If data cannot be expressed as an IndexItem, the Command Center cannot index it.
Adapter
A pure function that converts domain-specific data into IndexItem[].
Adapters are the transformation boundary between raw data (JSON configs, API responses, static definitions) and the unified index.
type IndexProvider = () => IndexItem[];
Responsibilities
- Flatten nested structures into individual items
- Generate stable, deterministic IDs
- Enrich keywords with parent context for search quality
- Skip inactive or irrelevant entries
- Return
IndexItem[]— nothing else
Non-responsibilities
- Adapters do not mutate source data
- Adapters do not contain UI logic, execution logic, or side effects
- Adapters do not access browser APIs or cookies
An adapter receives data and returns index items. That is its entire contract.
Registry
The IndexRegistry collects adapters and composes them into a unified index.
indexRegistry.register('routes', () => normalizeRoutesForFuseAdapter());
indexRegistry.register('settings', () => normalizeSettingsForFuseAdapter());
When build() is called, the registry invokes every registered provider and concatenates the results into a single IndexItem[]. This is the unified index that the engine searches over.
The registry is append-only during bootstrap. Once the index is built, the registry's job is done.
:::tip Why a registry
Without it, the composer would need to import and call every adapter directly — creating tight coupling between the composition layer and every data domain. The registry inverts this: domains register themselves, and the composer just calls build().
:::
Engine
The CommandEngine takes the unified index and makes it searchable.
It wraps a fuzzy search implementation and exposes a single method:
commandEngine.search(query) → CommandResult[]
CommandResult is the output shape — a search result enriched with score, display metadata, and match ranges:
type CommandResult = {
id: string;
title: string;
type: CommandItemType;
subtitle?: string;
icon?: ComponentType<SVGProps<SVGSVGElement>>;
route?: string;
commandId?: string;
score?: number;
matches?: readonly FuseResultMatch[];
};
subtitleprovides contextual breadcrumbs (e.g."AppCMS / Settings / Web Push")matchescarries Fuse.js match ranges for highlighted rendering in the UIiconallows adapters to attach domain-specific icons to results
The engine is initialized once after the index is built. It does not know what domains exist, what adapters produced the data, or how results will be used. It scores and ranks.
Key properties:
- Search is performed over
title,keywords, anddescription - Results are transformed from library-specific output into
CommandResultvia the result adapter - The search library is an implementation detail — replaceable without affecting any other layer
Executor
The CommandExecutor receives a CommandResult and dispatches the appropriate action.
executor.execute(result);
Two execution paths:
route→ delegates to the router (navigate(path))commandId→ looks up the handler inCommandRegistryand invokes it
The executor does not decide what to execute. That decision was made when the adapter assigned route or commandId to the IndexItem. The executor just follows through.
CommandRegistry
A simple map of commandId → handler.
commandRegistry.register({
id: 'theme.toggle',
handler: () => themeManager.toggle(),
});
Actions are registered independently of the index. An IndexItem with commandId: 'theme.toggle' will find and invoke this handler at execution time.
How They Connect

Each boundary is enforced by type:
- Adapters produce
IndexItem[] - The registry collects
IndexItem[] - The engine consumes
IndexItem[]and producesCommandResult[] - The executor consumes
CommandResult
No component reaches across its boundary. This is what makes the system extensible without modification.