How Omarchy Resolves Command Routes Using Longest‑Prefix Matching
Omarchy resolves command routes by normalizing input strings, checking for exact ID matches first, then scanning aliases in order, effectively implementing longest‑prefix matching where specific identifiers take precedence over shorter aliases.
Omarchy’s command routing system powers both its interactive menu navigation and CLI command dispatch. According to the basecamp/omarchy source code, the routing logic lives in the MenuModel module and employs a deterministic five-step algorithm that prioritizes exact matches over aliases.
Route Resolution Pipeline in MenuModel.js
The resolveRoute function in shell/plugins/menu/MenuModel.js processes user input through a strict priority chain. This design ensures that longer, more specific identifiers always win against shorter aliases, creating a reliable longest-prefix matching behavior.
Input Normalization
Every route string undergoes aggressive normalization before comparison:
var raw = String(input || "").toLowerCase().replace(/_/g, "-")
This converts input to lowercase and replaces all underscores with hyphens, ensuring that power_menu and power-menu are treated identically.
Root Shortcut Handling
The router catches three special cases that map to the root menu:
- Empty strings
- The literal
"go" - The literal
"menu"
When any of these are detected, the function immediately returns "root".
Exact-ID Match (Longest‑Prefix Priority)
The algorithm first checks if the normalized string corresponds directly to an existing menu item ID:
if (item(items, raw)) return raw
This exact match check is the core of the longest-prefix strategy. Because unique identifiers are typically more specific than aliases, verifying the exact ID first guarantees that precise routes take precedence over generic shortcuts.
Alias Iteration
If no exact ID matches, the router walks the ordered itemOrder array. For each non-app entry, it examines all declared aliases (also normalized) and returns the first matching alias:
for (var i = 0; i < order.length; i++) {
var entry = item(items, order[i])
if (!entry || entry.kind === "app" || !entry.aliases) continue
for (var j = 0; j < entry.aliases.length; j++) {
var alias = String(entry.aliases[j] || "").toLowerCase().replace(/_/g, "-")
if (alias === raw) return entry.id
}
}
The nested loop preserves the menu’s declared order, making routing deterministic and predictable.
Fallback Behavior
When no ID or alias matches, the normalized input string is returned unchanged:
return raw
This allows upstream callers to handle unknown routes—such as attempting to open the string as a URL or displaying an error message—without the router making assumptions about external resources.
Practical Routing Examples
The following examples demonstrate how resolveRoute handles different inputs against a hypothetical menu structure:
// Example 1 – exact ID match takes precedence
resolveRoute(items, order, "system") // → "system"
// Example 2 – alias match with automatic underscore conversion
resolveRoute(items, order, "power_menu") // → "system"
// (assuming "system" has alias "power-menu")
// Example 3 – unknown routes pass through unchanged
resolveRoute(items, order, "foobar") // → "foobar"
Key Source Files
Understanding Omarchy’s routing requires examining these specific files:
shell/plugins/menu/MenuModel.js– Contains theresolveRoutefunction implementing the normalization and matching logic described abovedocs/menu.md– Documents the menu schema, including thealiasesfield used for route resolutiondocs/cli-router.md– Explains how CLI commands generate routes that rely on this same MenuModel logic
Summary
- Normalization is aggressive: All input becomes lowercase with underscores converted to hyphens.
- Exact IDs beat aliases: The longest-prefix behavior emerges because exact identifiers are checked before alias scanning begins.
- Order matters: Aliases are evaluated in the sequence defined by
itemOrder, making routing deterministic. - Graceful degradation: Unknown routes fall back to the normalized input string, allowing flexible downstream handling.
Frequently Asked Questions
How does Omarchy handle underscores in command routes?
Omarchy automatically converts underscores to hyphens during normalization. When you type omarchy menu power_menu, the router transforms it to power-menu before checking against IDs and aliases, as implemented in shell/plugins/menu/MenuModel.js.
Why is exact-ID matching performed before alias checking?
Checking exact IDs first ensures that specific, unambiguous identifiers take precedence over generic shortcuts. This creates a longest-prefix matching effect where precise commands always win, preventing shorter aliases from shadowing more specific menu items.
What happens if I enter a route that doesn't match any menu item?
The router returns the normalized input string unchanged. This fallback mechanism allows the calling code to handle unknown routes appropriately—typically by attempting to open the string as a URL or displaying a "command not found" error.
Does the routing order affect which alias gets selected?
Yes. The algorithm iterates through itemOrder sequentially and checks aliases in their declared array order. The first match wins, so menu structure definition directly impacts routing resolution priority.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →