Understanding Omarchy's Menu Guards and Providers: A Deep Dive into Dynamic Desktop Menus
Omarchy's menu system uses guards to conditionally show, mark, or disable entries based on Bash expressions, and providers to dynamically populate submenus at runtime.
The Quickshell desktop plugin omarchy.menu powers Omarchy's entire menu infrastructure. According to the basecamp/omarchy source code in shell/plugins/menu/MenuModel.js, the system separates static menu definitions from dynamic runtime behavior through two core mechanisms: guards for conditional visibility and state, and providers for on-demand content generation.
What Are Menu Guards?
Guards are Bash-style expressions attached to menu entries via three keys: when, checked, and disabled. These expressions are documented in docs/menu.md and evaluated in a single batched Bash process per menu reload, minimizing overhead.
The Three Guard Types
Each guard serves a distinct purpose in controlling menu presentation:
-
when— Hides the entire row if the expression fails (returns false). For submenus, if all visible descendants are hidden, the submenu itself disappears—except provider-backed submenus, which remain and load on demand. -
checked— Adds a "✓" marker when the expression succeeds, indicating the current active choice. Used for defaults, DNS configurations, channel selections, and similar stateful options. -
disabled— Keeps the row visible but dims it and makes it unselectable. Disabled rows also receive the "✓" marker to signal that the item is already installed or active.
The batching system outputs results in a structured format: <id>:w:<0|1> for when, <id>:c:<0|1> for checked, and <id>:d:<0|1> for disabled.
Guard Helper Functions
Performance-critical helper functions like omarchy-pkg-present and omarchy-cmd-present are defined in MenuModel.js at line 104 and injected into the guard script via guardHelpers(). This design eliminates the overhead of spawning multiple Bash processes for each expression.
// Example: Guard usage to conditionally show/hide based on git installation
{
"install.git": {
"label": "Git",
"action": "omarchy-pkg-add git",
"when": "omarchy-pkg-missing git",
"disabled": "omarchy-pkg-present git"
}
}
In this example, the when guard keeps the row visible only if git is not installed, while disabled dims it with a checkmark when git is already present.
What Are Menu Providers?
Providers supply submenu rows at runtime rather than from static JSONC definitions. An entry with provider: "<name>" delegates row generation to a named provider implementation.
Built-in Provider Types
The providers map in Menu.qml defines several provider types:
-
apps— Native QML provider that enumerates desktop applications with icons, launch feedback, and uninstall support. -
fontsandpower-profiles— Bash one-liners returning tab-delimited lines in the formatlabel\tvalue\tcurrent.
// Example: Provider usage for dynamic font listing
{
"fonts": {
"label": "Fonts",
"provider": "fonts",
"icon": "f"
}
}
When the user opens the "Fonts" submenu, the fonts provider executes a Bash script emitting lines like Monospace\tmonospace\t$(omarchy-default-font), and the menu constructs rows dynamically.
Volatile Providers
Providers marked with the volatile flag re-run every time their submenu is entered. This ensures newly installed fonts or changed system states appear immediately without restarting the shell.
Implementation Architecture
The core logic resides in shell/plugins/menu/MenuModel.js:
swapProviderRows()at line 36 merges provider-returned rows while preserving existing static items.- Guard batching and evaluation orchestrate the conditional logic.
- JSONC parsing and item merging handle the static configuration from
default/omarchy/omarchy-menu.jsonc.
Adding a new provider requires only two steps: extend the providers map in Menu.qml, then reference it via provider: in any JSONC entry.
Key Files Reference
| File | Purpose |
|---|---|
docs/menu.md |
Schema documentation for guards and providers |
shell/plugins/menu/MenuModel.js |
Core JavaScript implementation |
default/omarchy/omarchy-menu.jsonc |
Default static menu definition |
Summary
-
Guards (
when,checked,disabled) control visibility and state using batched Bash expressions with helper functions fromMenuModel.js. -
Providers generate submenu content dynamically; native QML providers handle complex cases while Bash one-liners handle simple lists.
-
The volatile flag enables real-time updates without shell restarts.
-
All guard expressions execute in a single Bash process for performance.
-
Custom providers integrate by extending
Menu.qmland referencing them in JSONC entries.
Frequently Asked Questions
How do Omarchy menu guards improve performance?
Omarchy's menu guards execute all expressions in a single batched Bash process per menu reload, returning structured output like <id>:w:<0|1>. This design eliminates the overhead of spawning separate processes for each guard check, which would be prohibitively expensive in a frequently-accessed desktop menu.
Can providers and static entries coexist in the same submenu?
Yes. The swapProviderRows() function in MenuModel.js merges dynamically generated provider rows with existing static items. This allows hybrid submenus that combine fixed entries with runtime-generated content.
What happens if all entries in a submenu are hidden by when guards?
The submenu itself disappears—unless it is provider-backed. Provider-backed submenus remain visible and load on demand when entered, ensuring dynamic content is always accessible even when static entries are conditionally hidden.
How do I add a custom provider to Omarchy's menu?
Extend the providers map in shell/plugins/menu/Menu.qml with your provider name and implementation (either a Bash command or native QML handler). Then reference it in any JSONC menu entry using "provider": "your-name". Volatile providers can be marked to refresh on every submenu entry.
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 →