# How the Omarchy CLI Router Discovers and Routes Commands

> Learn how the Omarchy CLI router discovers commands by scanning bin/ for omarchy- executables and routes user input using an associative array mapping command names to file paths.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: internals
- Published: 2026-08-24

---

**The Omarchy CLI router dynamically discovers available commands by scanning the `bin/` directory for executables prefixed with `omarchy-`, then dispatches user input by looking up the first argument in an associative array that maps command names to absolute file paths.**

The Omarchy command-line interface in the `basecamp/omarchy` repository implements a lightweight, file-system-driven router written entirely in Bash. This Omarchy CLI router eliminates manual command registration by treating every executable script matching the `omarchy-*` pattern as a first-class subcommand, enabling automatic discovery and dispatch without configuration files.

## Command Discovery in bin/omarchy

The router's discovery mechanism is implemented in the central entry point at `bin/omarchy`. During initialization, the script scans the `bin/` directory to identify all executables beginning with the `omarchy-` prefix, building an associative array named `COMMANDS` that maps the command name (the portion after the prefix) to the absolute path of the executable.

```bash

# Excerpt from bin/omarchy

for exe in "$OMARCHY_PATH/bin/omarchy-"*; do
    cmd="${exe##*/omarchy-}"
    COMMANDS["$cmd"]="$exe"
done

```

This approach ensures that any new executable file added to the `bin/` directory with the correct naming convention is automatically available as a subcommand on the next invocation of `omarchy`, with no restart or reconfiguration required.

## Routing Logic and Argument Dispatch

After discovery completes, the router parses the command-line arguments to determine the target. The first positional argument is treated as the lookup key in the `COMMANDS` associative array. If a match is found, the router immediately executes the corresponding script using `exec`, passing any remaining arguments directly to the subcommand.

```bash

# Dispatch logic from bin/omarchy

if [[ -n "${COMMANDS[$first]}" ]]; then
    exec "${COMMANDS[$first]}" "${@:2}"
elif [[ -n "${PROMPT_ROUTES[$first]}" ]]; then
    # Handle group-level prompt routing

    ...
else
    echo "Unknown command: $first"
    exit 1
fi

```

This dispatch mechanism enables both **leaf commands** (direct executables like `omarchy-toggle-touchpad`) and **group commands** (logical containers like `omarchy-update-system-pkgs`) to coexist under a unified interface.

## Group Commands and Prompt Routes

Omarchy organizes commands into logical groups such as `toggle` and `update`. When a user invokes a group name without specifying a specific leaf command, the router falls back to **prompt routes**. The `PROMPT_ROUTES` associative array identifies which tokens should trigger this behavior, allowing the router to display available subcommands or interactive guidance rather than executing a binary.

The router also references the `GROUP_DESCRIPTIONS` associative array defined in `bin/omarchy` to supply human-readable headings for help output. This array determines which command groups are displayed to users and provides descriptive text for each category.

## Extending the Router with New Commands

Adding functionality to the Omarchy CLI requires no boilerplate code or registration steps. Simply create an executable file in the `bin/` directory following the `omarchy-<command-name>` naming convention.

The following example creates a custom `hello` command:

```bash

# Create the executable

cat > "$OMARCHY_PATH/bin/omarchy-hello" <<'EOF'
#!/usr/bin/env bash
echo "Hello, Omarchy!"
EOF

chmod +x "$OMARCHY_PATH/bin/omarchy-hello"

# Invoke via the router

omarchy hello

```

Because the router discovers commands dynamically at runtime, the new `omarchy-hello` command is immediately available without modifying the central router script. For commands that belong to new functional groups, add an entry to the `GROUP_DESCRIPTIONS` array in `bin/omarchy` to ensure proper categorization in help output.

## Key Implementation Files

- **`bin/omarchy`** – The central router script responsible for command discovery, routing table construction, and subcommand dispatch.
- **`bin/omarchy-<subcommand>`** – Individual command executables (e.g., `omarchy-toggle-touchpad`, `omarchy-update-system-pkgs`) discovered automatically by the router.
- **[`agents/skills/command-metadata.md`](https://github.com/basecamp/omarchy/blob/main/agents/skills/command-metadata.md)** – Documentation guidelines for adding or modifying CLI commands and maintaining `GROUP_DESCRIPTIONS`.
- **`test/cli`** – Automated test suite verifying router discovery and dispatch behavior.
- **[`docs/testing.md`](https://github.com/basecamp/omarchy/blob/main/docs/testing.md)** – Documentation covering the CLI test harness used to validate routing logic.

## Summary

- The Omarchy CLI router operates as a lightweight Bash dispatcher in `bin/omarchy` that requires no manual command registration.
- Discovery relies on a glob pattern (`omarchy-*`) to identify executables in the `bin/` directory, storing results in the `COMMANDS` associative array.
- Routing matches the first command-line argument against the `COMMANDS` array, executing the matching binary via `exec` with remaining arguments passed through.
- Group commands utilize the `PROMPT_ROUTES` array to trigger interactive subcommand listings when no leaf command is specified.
- Command descriptions and categorization are managed through the `GROUP_DESCRIPTIONS` associative array.
- New commands are added by dropping executables into `bin/` with the `omarchy-` prefix, enabling immediate availability without router modifications.

## Frequently Asked Questions

### How does the Omarchy CLI router discover new commands?

The router scans the `bin/` directory at runtime for any executable files matching the pattern `omarchy-*`. It extracts the substring following the prefix to create the command name, then populates the `COMMANDS` associative array with mappings from command names to absolute file paths. This file-system-driven approach eliminates the need for a central registry.

### What happens when I type a command that isn't a leaf executable?

When the first argument matches an entry in the `PROMPT_ROUTES` associative array rather than a direct executable, the router treats it as a group command. Instead of executing a binary, it triggers prompt logic that displays available subcommands within that group (such as all `update-*` or `toggle-*` variants), guiding the user toward the correct leaf command.

### Where are command group descriptions defined?

Group descriptions are stored in the `GROUP_DESCRIPTIONS` associative array inside `bin/omarchy`. This array maps group identifiers (like `toggle` or `update`) to human-readable strings used when generating help output or prompt listings. The [`agents/skills/command-metadata.md`](https://github.com/basecamp/omarchy/blob/main/agents/skills/command-metadata.md) file provides guidelines for maintaining these descriptions when adding new functional categories.

### Can I add custom commands without modifying the core router?

Yes. The Omarchy CLI router supports zero-configuration extensibility. Create any executable file in the `bin/` directory with the naming convention `omarchy-<your-command>`, make it executable with `chmod +x`, and it will be automatically discovered and routed on the next invocation. This design follows the Unix philosophy of treating commands as independent, composable scripts.