How to Use the Omarchy Menu as a dmenu Replacement: Complete CLI and Scripting Guide
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 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 at 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:
- Sends a JSON payload
{"menu": "<mode>"}to theomarchy.menuplugin - Launches the QML UI with the merged menu model
- Writes the result to a temporary file and signals completion via a done file
- 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
# 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:
#!/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
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 normalization process enforces a consistent schema:
label: Display texticon: Optional icon name or pathexec: Command to execute on selectionwhen: Conditional guard (bash expression)checked: Toggle state expressiondisabled: Disable expression
User Extension Example
Create ~/.config/omarchy/extensions/omarchy-menu.jsonc to add scriptable entries:
{
"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, 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
whenconditions are excluded automatically checkedanddisabledstates 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:
# 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 |
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 |
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 |
Executable specification of expected behaviors |
Summary
- Install: Omarchy menu ships with the desktop; no separate package needed
- Basic CLI:
omarchy menu selectfor lists,omarchy menu summon --mode inputfor prompts - Scripting: Read from stdin, capture stdout, check exit status — standard Unix patterns
- Customization: Extend
~/.config/omarchy/extensions/omarchy-menu.jsoncand 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 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 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 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.
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 →