How the Omarchy CLI Router Resolves Commands and Handles Dispatch
The Omarchy CLI router dynamically discovers commands by scanning for omarchy-* executables, parsing embedded metadata comments to build a routing table, and employing a two-phase resolution strategy that prioritizes fast binary-prefix matching before falling back to full route lookup, ultimately dispatching via exec or rendering rich help output.
The Omarchy CLI router serves as the central dispatch mechanism for the basecamp/omarchy repository, transforming scattered shell scripts into a cohesive command-line interface. Unlike static command registration, this router employs a metadata-driven architecture that automatically discovers new binaries and handles complex routing scenarios including aliases, command groups, and contextual help generation.
Command Discovery and Metadata Parsing
The router begins by dynamically discovering available commands rather than maintaining a hardcoded list.
Dynamic Discovery with load_commands
In bin/omarchy, the load_commands function iterates over every executable matching the pattern omarchy-* within the same directory. This discovery phase happens at lines 15-18, where each found binary is passed to register_command for metadata extraction. This design allows new commands to become available immediately upon being added to the bin/ directory without modifying the router itself.
Metadata Extraction in register_command
Each command script embeds configuration data using structured comment headers formatted as # omarchy:<key>=<value>. The register_command function, located at lines 48-99, reads the first approximately 80 comment lines from each binary to extract metadata keys including group, name, summary, args, and aliases.
As the parser processes each command, it populates two critical lookup tables:
COMMAND_ROUTE: Maps command keys to their full route definitionsROUTE_TO_KEY: Maps human-readable route strings back to their internal keys
These mappings enable both fast lookups and reverse lookups throughout the dispatch lifecycle.
Route Registration and Resolution
Once metadata is parsed, the router constructs multiple entry points for each command.
Primary and Fallback Route Registration
The register_route function (lines 95-103) creates several access paths for every command:
- Primary route: The full command path (e.g.,
omarchy theme set) - Filename fallback: A route derived directly from the binary name
- Alias routes: Additional shortcuts defined in the metadata (lines 101-108)
This multi-route strategy ensures users can invoke commands through intuitive names while maintaining backward compatibility with script filenames.
Fast Binary-Prefix Matching
Before consulting the full routing table, resolve_direct_route (lines 95-107) attempts an optimization. It joins input arguments with dashes and checks whether a binary named omarchy-<joined-args> exists directly. If found, the router stores the binary path in DIRECT_RESOLVED_PATH and the number of consumed arguments in DIRECT_RESOLVED_CONSUMED, bypassing the heavier routing table lookup entirely.
Full Routing Table Lookup
When the fast path fails, resolve_route (lines 161-176) performs a comprehensive search. It walks the argument list from longest to shortest, checking each prefix against the ROUTE_TO_KEY mapping. The first match becomes RESOLVED_KEY, allowing commands to be invoked with partial arguments when unambiguous.
Dispatch Logic and Help Handling
The router prioritizes help generation over execution when appropriate, creating a self-documenting interface.
The Fast Path: dispatch_fast_or_help
Located at lines 145-190, dispatch_fast_or_help processes the result of resolve_direct_route. This function implements a "help-first" philosophy:
- If remaining arguments contain
--helpor-h, it loads command metadata viaload_command_by_binaryand renders detailed help viashow_command_help, or JSON output viashow_command_json - If no arguments remain but the command requires them, it displays help instead of executing
- Otherwise, it immediately
execs the resolved binary with leftover arguments
Fallback Dispatch with dispatch_or_help
When full routing is required, dispatch_or_help (lines 210-267) handles the complexity. After resolve_route identifies a match, it applies the same help-detection logic. If the resolved key represents a command group (e.g., omarchy theme without a subcommand), the router lists available commands in that group rather than failing. If no route matches, it invokes suggest_command to offer closest matches before exiting with an error.
Group Resolution and Command Execution
The router distinguishes between executable commands and organizational groups.
Group Validation Utilities
Functions group_exists, group_has_binary_commands, and group_has_child_commands (lines 84-96) enable the router to differentiate between a parent group container and a concrete executable command. When a user invokes only a group name, the router queries these utilities to determine whether to display the group's command list or proceed with execution.
Process Replacement via exec
Finally, after all resolution and validation checks complete, the router executes the target binary at line 224 using:
exec "$binary_path" "${remaining[@]}"
This exec call replaces the current shell process with the target command, preserving exit status and process integrity while passing through any unconsumed arguments.
Summary
-
Dynamic discovery: The router scans
bin/foromarchy-*executables at startup, requiring no manual registration -
Metadata-driven: Commands self-document via
# omarchy:<key>=<value>comments parsed byregister_command -
Two-phase resolution: Fast binary-prefix matching (
resolve_direct_route) precedes full table lookup (resolve_route) -
Help-first design: Both dispatch paths check for
--help,--json, and missing required arguments before execution -
Group awareness: The router validates groups separately from commands, showing command lists when group names are invoked alone
-
Clean execution: All valid commands ultimately dispatch via
execto replace the router process entirely
Frequently Asked Questions
How does Omarchy discover new commands without configuration files?
The load_commands function in bin/omarchy (lines 15-18) scans the bin/ directory for any executable matching omarchy-* and automatically registers them by parsing their embedded metadata comments. This allows adding new commands simply by dropping scripts into the directory.
What is the priority order for route resolution in the Omarchy CLI?
Resolution occurs in two phases: first, resolve_direct_route checks if the arguments form a valid binary name directly; second, resolve_route walks the argument list from longest to shortest against the ROUTE_TO_KEY table. The fast path prioritizes direct binary matches, while the fallback allows partial command matching.
How does the router handle ambiguous or misspelled commands?
When dispatch_or_help fails to find a matching route, it invokes suggest_command to calculate and display the closest matching valid commands. If the user invokes only a group name like omarchy theme, the router lists all available subcommands rather than executing.
Can custom aliases be defined for Omarchy commands?
Yes, aliases are defined within command scripts using the # omarchy:aliases=<alias1>,<alias2> metadata format. The register_command function (lines 101-108) processes these values and registers additional routes pointing to the same command key, enabling shortcuts like omarchy up for omarchy update.
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 →