# How to Use the Omarchy Menu as a dmenu Replacement: Complete CLI and Scripting Guide

> Replace dmenu with Omarchy menu using select or input modes. This guide shows how to leverage Omarchy for CLI and scripting, returning choices via stdout.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-08-31

---

**The Omarchy menu can replace dmenu entirely by invoking `omarchy menu` with `select` or `input` modes, which return user choices via stdout using a temporary file handshake protocol.**

The **`omarchy.menu`** Quickshell plugin provides a modern, extensible alternative to classic dmenu-style selectors. Whether you need a simple text prompt for shell scripts or a searchable list interface, the same underlying system powers both the graphical desktop menu and command-line usage. This guide covers installation, CLI invocation, programmatic integration, and customization of the Omarchy dmenu replacement.

## Understanding the Omarchy Menu Architecture

The menu system separates configuration from execution through two core components implemented in the [omacom/omarchy](https://github.com/omacom/omarchy) repository.

### Static Definition Layer

Menu entries live in **JSONC files** that merge at runtime:

- **System defaults**: `default/omarchy/omarchy-menu.jsonc`
- **User extensions**: `~/.config/omarchy/extensions/omarchy-menu.jsonc`

The merge logic resides in **[`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js)** at [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js). This JavaScript module exposes functions like `stripJsonc()`, `parseMenuJsonc()`, `normalizeItem()`, and `mergeMenuSources()` to combine these sources into a unified, searchable model.

### Runtime Execution Layer

The **`omarchy-menu`** wrapper script at `bin/omarchy-menu` forwards commands to the running Quickshell instance via IPC. When invoked in **select** or **input** mode, it:

1. Sends a JSON payload `{"menu": "<mode>"}` to the `omarchy.menu` plugin
2. Launches the QML UI with the merged menu model
3. Writes the result to a temporary file and signals completion via a *done* file
4. Returns the value through stdout and exits with appropriate status codes

This design ensures **identical behavior** between interactive desktop use and scripting scenarios.

## Basic CLI Usage for dmenu Replacement

The `omarchy menu` command supports several subcommands that mirror dmenu workflows.

### Essential Commands

```bash

# Toggle root menu (default select behavior)

omarchy menu

# Toggle root menu, never close if already visible

omarchy menu summon

# Generic text input prompt — blocks until Enter pressed

omarchy menu summon --mode input "Enter file name:"

# Open specific submenu directly by path

omarchy menu toggle system

# Reload merged JSONC without restarting shell

omarchy menu refresh

```

The **`select`** and **`input`** modes are the primary dmenu replacements. **Select** presents a filterable list; **input** provides a single-line text prompt with optional placeholder text.

### Mode Comparison

| Mode | Use Case | Returns |
|------|----------|---------|
| `select` | Choose from predefined options | Selected label or key |
| `input` | Free-text entry with prompt | Typed string |
| (default) | Full graphical menu | Nothing (launches actions directly) |

## Scripting the Omarchy Menu

The `omarchy menu` CLI follows Unix conventions: zero exit status on success, non-zero on cancellation. This makes it suitable for shell and Python automation.

### Bash Integration

Capture selections using stdin redirection or here-strings:

```bash
#!/usr/bin/env bash

# dmenu-style list from inline data

choice=$(omarchy menu select "Choose browser:" \
    <<< $'Firefox\nChromium\nEdge\nZen' \
    2>/dev/null)

if [[ $? -eq 0 ]]; then
    echo "Launching: $choice"
    $choice &
else
    echo "No selection made"
    exit 1
fi

```

The wrapper reads newline-delimited items from **stdin**, displays them in a searchable list, and writes the chosen label to **stdout**.

### Python Integration

```python
import subprocess
import shlex

def omarchy_dmenu(prompt: str, items: list[str]) -> str | None:
    """
    Present a dmenu-style selector using Omarchy's menu.
    Returns the selected item, or None if cancelled.
    """
    result = subprocess.run(
        shlex.split('omarchy menu select') + [prompt],
        input='\n'.join(items).encode(),
        capture_output=True,
        text=True
    )
    return result.stdout.strip() if result.returncode == 0 else None

# Example usage

theme = omarchy_dmenu('Select color scheme:', ['light', 'dark', 'auto'])
if theme:
    subprocess.run(['gsettings', 'set', 'org.gnome.desktop.interface', 'color-scheme', theme])

```

This pattern replaces `dmenu`, `rofi -dmenu`, or `wmenu` in existing toolchains.

## Customizing Menu Entries for CLI Use

Any entry defined in the merged JSONC configuration becomes available to the CLI. The [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) normalization process enforces a consistent schema:

- **`label`**: Display text
- **`icon`**: Optional icon name or path
- **`exec`**: Command to execute on selection
- **`when`**: Conditional guard (bash expression)
- **`checked`**: Toggle state expression
- **`disabled`**: Disable expression

### User Extension Example

Create `~/.config/omarchy/extensions/omarchy-menu.jsonc` to add scriptable entries:

```jsonc
{
  "entries": [
    {
      "label": "Quick Scripts",
      "entries": [
        {
          "label": "Screenshot Region",
          "exec": "grim -g \"$(slurp)\" - | wl-copy",
          "icon": "camera-photo"
        },
        {
          "label": "Lock Screen",
          "exec": "loginctl lock-session",
          "icon": "system-lock-screen",
          "when": "[[ -n $WAYLAND_DISPLAY ]]"
        }
      ]
    }
  ]
}

```

After running `omarchy menu refresh`, these entries appear in both the graphical menu and any **`omarchy menu toggle "Quick Scripts"`** invocations.

## Guard Expressions and Conditional Items

The Omarchy menu supports **dynamic visibility** through bash guard scripts generated at runtime. In [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js), the `guardScript` property contains the combined conditions for all visible entries.

When using the menu as a dmenu replacement, guards are evaluated **before** the list renders. This means:

- Items with failing `when` conditions are excluded automatically
- `checked` and `disabled` states are computed fresh on each invocation

For scripts requiring predictable output, ensure your `when` expressions depend on stable environment variables rather than transient state.

## Route Handling for Direct Submenu Access

The **`toggle`** and **`summon`** subcommands support **routing** to arbitrary menu paths:

```bash

# Open nested submenu directly

omarchy menu toggle "System/Power"

# Skip root menu, jump to themed sub-tree

omarchy menu toggle "Dev Tools/Containers"

```

Routes use `/` as delimiter and match against the merged menu structure. This enables **context-specific scripting**: bind different shortcuts to different menu branches without duplicating configuration.

## Key Files Reference

| Path | Purpose |
|------|---------|
| [`docs/menu.md`](https://github.com/omacom/omarchy/blob/main/docs/menu.md) | Complete format specification, provider system, and CLI documentation |
| `bin/omarchy-menu` | Bash IPC wrapper — entry point for all CLI usage |
| [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) | Core parsing, merging, and search implementation |
| `default/omarchy/omarchy-menu.jsonc` | Shipped default menu definition |
| `~/.config/omarchy/extensions/omarchy-menu.jsonc` | User customizations (created as needed) |
| [`test/shell.d/menu-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/menu-test.sh) | Executable specification of expected behaviors |

## Summary

- **Install**: Omarchy menu ships with the desktop; no separate package needed
- **Basic CLI**: `omarchy menu select` for lists, `omarchy menu summon --mode input` for prompts
- **Scripting**: Read from stdin, capture stdout, check exit status — standard Unix patterns
- **Customization**: Extend `~/.config/omarchy/extensions/omarchy-menu.jsonc` and refresh
- **Routing**: Use `toggle <path>` for direct submenu access in keybindings

The `omarchy.menu` plugin unifies graphical and command-line menu usage through the same **[`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js)** foundation, making it a capable drop-in replacement for dmenu that grows with your workflow.

## Frequently Asked Questions

### Can I use Omarchy menu in scripts that expect dmenu compatibility?

Yes. The `omarchy menu select` command accepts newline-delimited items via stdin and writes the selected item to stdout, matching dmenu's interface. Exit codes follow the same convention: 0 for selection, non-zero for cancellation. Pipe data in and capture output exactly as you would with dmenu or rofi.

### How does the temporary file handshake work?

When the QML UI receives a selection, it writes the value to a temp file and creates a companion *done* file. The `bin/omarchy-menu` wrapper polls for this signal, then reads and emits the value. This indirection allows the graphical interface to run asynchronously while the CLI blocks predictably.

### What happens if I modify the JSONC files while running?

Changes are not picked up automatically. Run `omarchy menu refresh` to re-parse and merge the configuration without restarting Quickshell. The [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) `mergeMenuSources()` function re-executes, combining system defaults with your latest user extensions.

### Can I override individual default entries instead of replacing the whole menu?

Yes. The merge strategy in [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) is additive by default, but entries sharing the same `label` and route can override or extend parent definitions. Use your `~/.config/omarchy/extensions/omarchy-menu.jsonc` to shadow specific items while inheriting the rest of the default structure.