How to Create Custom Omarchy Menu Extensions: A Complete Guide
Omarchy menu extensions are created by editing ~/.config/omarchy/extensions/omarchy-menu.jsonc, which gets merged with the default menu at runtime using the mergeMenuSources function in shell/plugins/menu/MenuModel.js.
Omarchy's command menu system is built on the omarchy.menu Quickshell plugin and offers a flexible, JSONC-based extension mechanism. This guide explains how to add custom entries, submenus, and conditional visibility to tailor the launcher to your workflow.
Understanding the Omarchy Menu Architecture
The menu structure is defined by two JSONC files that Omarchy merges when the shell starts:
default/omarchy/omarchy-menu.jsonc– The shipped default menu definition~/.config/omarchy/extensions/omarchy-menu.jsonc– Your custom extensions
The merge logic lives in shell/plugins/menu/MenuModel.js within the mergeMenuSources function. This overlay system works key-by-key:
- Matching IDs receive partial updates (change only
labeloriconwithout touchingaction) - New IDs are appended to the menu tree
- A synthetic
rootentry is injected when neither file defines one
If your extensions file doesn't exist, omarchy-refresh-config creates it automatically from the sample at config/omarchy/extensions/omarchy-menu.jsonc.
Entry Schema for Custom Omarchy Menu Extensions
Each menu entry supports these core fields:
| Field | Purpose |
|---|---|
icon |
Nerd Font glyph displayed in the icon column |
label |
Human-readable title (defaults to entry ID) |
action |
Bash command executed when selected |
target |
ID of another submenu to open (turns entry into a navigation link) |
when |
Bash condition that hides the entry when false |
checked |
Bash condition that shows a checkmark when true |
disabled |
Bash condition that dims the entry when true |
Guards (when, checked, disabled) are evaluated in a batched Bash process for performance. For dynamic content—like listing installed applications—point a submenu to a provider such as apps, fonts, or power-profiles. Providers are defined in shell/plugins/menu/Menu.qml.
Creating Your First Custom Menu Extension
Step 1: Locate or Create the Extensions File
Ensure the file exists at:
~/.config/omarchy/extensions/omarchy-menu.jsonc
If missing, run:
omarchy-refresh-config
Step 2: Add Entries Using Dotted-ID Notation
Use dot-separated IDs to place entries anywhere in the hierarchy. For example, personal.notes nests under personal.
Step 3: Apply Changes Instantly
Omarchy monitors the extensions file. Press Super + Space or run:
omarchy menu refresh
No shell restart required.
Practical Omarchy Menu Extension Examples
Add a Simple Launcher Entry
Open a terminal with Vim for quick notes:
{
// ~/.config/omarchy/extensions/omarchy-menu.jsonc
"personal": {
"label": "Personal"
},
"personal.notes": {
"icon": "\uf15c",
"label": "Notes",
"action": "omarchy launch-terminal \"vim ~/notes.txt\""
}
}
The \uf15c is a Nerd Font "file-text" glyph.
Conditionally Show Entries Based on Package Installation
Display Syncthing UI only when the package is present:
{
"personal.syncthing": {
"icon": "\uf0e7",
"label": "Syncthing UI",
"action": "omarchy launch-browser http://localhost:8384",
"when": "$(omarchy-pkg-present syncthing)"
}
}
The omarchy-pkg-present utility returns exit code 0 only when the package is installed.
Create a Submenu with a Built-in Provider
Reuse Omarchy's application launcher as a submenu:
{
"tools": {
"label": "Tools",
"provider": "apps"
}
}
Controlling the Menu from CLI
The bin/omarchy-menu script provides programmatic access:
| Command | Effect |
|---|---|
omarchy menu |
Toggle the root menu |
omarchy menu toggle system |
Open/close the "system" submenu |
omarchy menu summon style.theme |
Directly activate a specific entry |
omarchy menu refresh |
Force re-parsing of all JSONC sources |
These commands work from shell scripts, keybindings, or automation tools.
Testing Custom Omarchy Menu Extensions
Verify your extensions with the built-in test suite:
./test/shell
Specifically, test/shell.d/menu-test.sh validates JSONC parsing and merging, while test/shell.d/menu-guards-test.sh checks conditional visibility logic. Run these after adding complex guards to catch syntax errors early.
Summary
- Custom Omarchy menu extensions live in
~/.config/omarchy/extensions/omarchy-menu.jsonc - The
mergeMenuSourcesfunction inshell/plugins/menu/MenuModel.jsoverlays your entries onto defaults - Use dotted IDs (
category.item) to position entries anywhere in the tree - Guards (
when,checked,disabled) enable conditional visibility via Bash expressions - Providers (
apps,fonts, etc.) generate dynamic submenu content - Changes apply instantly without restarting the shell
- Test extensions with
./test/shellbefore committing to your dotfiles
Frequently Asked Questions
What happens if my custom entry uses the same ID as a default entry?
Only the fields you explicitly declare are replaced. You can retitle or re-icon a default entry without redefining its action. Omit action entirely to keep the original behavior while changing the label.
Can I remove or hide default menu entries?
Yes—override the entry with a when guard that always evaluates false: "when": "false". The entry disappears from the menu while preserving the original definition in default/omarchy/omarchy-menu.jsonc.
How do I find valid Nerd Font icon codes?
Browse nerdfonts.com/cheat-sheet for glyph codes. Prefix with \u and use four hexadecimal digits (e.g., \uf15c). Verify the glyph renders in your terminal before adding to the menu.
Do I need to restart Omarchy after editing the extensions file?
No. The omarchy-shell process watches ~/.config/omarchy/extensions/omarchy-menu.jsonc via filesystem notification. Use omarchy menu refresh if you suspect the watcher missed an 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 →