How the Menu Definition in `default/omarchy/omarchy-menu.jsonc` Works with Guards and Providers
The Omarchy menu definition uses declarative JSONC configuration where Guard conditions control row visibility and state, while Providers generate dynamic content, enabling a responsive menu system that updates without shell restarts.
The omacom/omarchy repository implements its desktop menu through a static JSONC file located at default/omarchy/omarchy-menu.jsonc. This file serves as the single source of truth for the menu structure, enhanced by two powerful abstractions: Guards for conditional logic and Providers for dynamic data. Together, these mechanisms allow the Quickshell-based shell to render complex, context-aware menus while maintaining declarative simplicity.
Understanding Guards in the Omarchy Menu Definition
Guards are Bash-style expressions defined directly in the JSONC that control three aspects of menu rows: visibility, checked state, and interactivity. According to the menu documentation, these expressions are evaluated in a single batched process to maximize performance.
When, Checked, and Disabled Conditions
Each guard type serves a distinct purpose in the menu lifecycle:
when(w): Hides the row entirely when the expression evaluates to 0checked(c): Displays a checkmark (✓) when the expression evaluates to 1disabled(d):Dims the row and prevents selection when the expression evaluates to 1, while keeping it visible
The evaluation results are transmitted from the shell to the UI as compact status lines in the format <id>:<w|c|d>:<0|1>.
// Example from default/omarchy/omarchy-menu.jsonc
"system.suspend": {
"icon": "",
"label": "Suspend",
"when": "! omarchy-toggle-enabled suspend-off",
"action": "systemctl suspend"
},
"trigger.toggle.idle-lock": {
"icon": "",
"label": "Stay Awake",
"disabled": "[[ -f $HOME/.config/idle-lock.conf ]]",
"action": "omarchy-toggle-idle"
}
Batched Bash Evaluation for Performance
Rather than spawning individual processes for each condition, the omarchy.menu plugin collects all guard expressions and evaluates them in one Bash invocation. This batching strategy caches common lookups—such as omarchy-pkg-present checks—ensuring the menu remains responsive even with dozens of conditional rows.
Working with Providers in omarchy-menu.jsonc
While static JSONC defines fixed menu structures, Providers enable dynamic content generation. Defined in shell/plugins/menu/Menu.qml through a providers map, these scripts emit tab-delimited rows on-demand, allowing the menu to reflect real-time system state.
Volatile vs Static Providers
Providers operate in two modes depending on their data source:
- Static providers: Execute once during menu initialization
- Volatile providers: Re-run each time their submenu opens, useful for detecting newly installed fonts or recent files
// Submenu delegating to the fonts provider
"style.font": {
"icon": "",
"label": "Font",
"provider": "fonts"
},
"apps": {
"icon": "",
"label": "Apps",
"provider": "apps"
}
The fonts provider emits lines in the format label\tvalue\tcurrent, while the apps provider queries the system's desktop entry database to populate application lists with correct icons and launch actions.
Merging Static and Dynamic Rows
When a submenu declares both a provider and static children, MenuModel.js executes the swapProviderRows function to combine these sources. This hybrid approach allows persistent entries—such as a "Refresh" button—to coexist with dynamically generated content:
"submenu.example": {
"provider": "fonts",
"children": {
"refresh": {
"label": "Refresh Font Cache",
"action": "fc-cache -fv"
}
}
}
The Menu Loading Pipeline
The transformation from JSONC files to rendered UI follows a strict four-phase pipeline implemented in shell/plugins/menu/MenuModel.js:
Load and Merge Phase
The mergeMenuSources function overlays user-defined extensions onto the base configuration from default/omarchy/omarchy-menu.jsonc. This merging preserves the positional order of entries while allowing selective field overrides, enabling users to extend the default menu without modifying core files.
Guard Evaluation Phase
All guard expressions are batched and executed once per menu (or submenu) load. The results populate a lookup table that Menu.qml consults during rendering to determine which rows to display, check, or dim.
Provider Population Phase
For each submenu containing a provider key, the associated script executes—either once or on every entry (if volatile). The provider's stdout is parsed into row objects and merged with any static children before the final model is exposed to the QML layer.
Hot-Reload Capability
Because the menu monitors its source JSONC files for changes, modifications to omarchy-menu.jsonc or user overlays apply instantly without requiring a shell restart, facilitating rapid iteration on menu configurations.
Practical Configuration Examples
Complete row definitions demonstrate how guards and providers interact in production configurations:
// Row with comprehensive guard usage
"trigger.toggle.screensaver": {
"icon": "",
"label": "Screensaver",
"when": "omarchy-toggle-enabled screensaver",
"checked": "[[ \"$(omarchy-get-screensaver-mode)\" == \"on\" ]]",
"disabled": "[[ -f $HOME/.config/screensaver.lock ]]",
"action": "omarchy-toggle-screensaver"
}
// Package-aware conditional disabling
"install.style.font.cascadia": {
"icon": "",
"label": "Cascadia Mono",
"disabled": "omarchy-pkg-present ttf-cascadia-mono-nerd",
"action": "omarchy-install-font 'Cascadia Mono' ttf-cascadia-mono-nerd 'CaskaydiaMono Nerd Font'"
}
Summary
- Guards in
default/omarchy/omarchy-menu.jsoncuse Bash expressions to control visibility (when), checked state (checked), and interactivity (disabled) through batched evaluation for performance. - Providers generate dynamic menu content on-demand, with volatile variants refreshing on each submenu open, while static children merge with provider output via
swapProviderRows. - The menu system supports hot-reloading and user overlays through
mergeMenuSources, allowing extensions without core file modification. - Key implementation files include
shell/plugins/menu/MenuModel.jsfor logic processing andshell/plugins/menu/Menu.qmlfor provider registration and UI rendering.
Frequently Asked Questions
What is the difference between when and disabled guards in Omarchy?
The when guard completely hides a menu row when its expression evaluates to 0, removing it from the menu structure entirely. The disabled guard keeps the row visible but applies visual dimming and prevents selection when evaluating to 1, useful for showing unavailable options while maintaining menu context.
How do providers handle dynamic content in omarchy-menu.jsonc?
Providers are external scripts referenced by the provider key in submenu definitions. They output tab-delimited text lines that MenuModel.js parses into row objects, merging them with any static children defined in the JSONC. Volatile providers execute on every submenu open to reflect current system state, while static providers run once during initialization.
Can I override the default menu without modifying the source JSONC?
Yes. The mergeMenuSources function in shell/plugins/menu/MenuModel.js overlays user-provided JSONC files onto the default default/omarchy/omarchy-menu.jsonc configuration. This merging preserves entry positions and only overrides explicitly declared fields, allowing you to extend or modify the menu while keeping the base repository files untouched.
Why are guards evaluated in a single batched Bash process?
Batching guard evaluations minimizes process spawning overhead by executing all Bash expressions in one shell invocation. This approach caches common lookups—such as package presence checks via omarchy-pkg-present—and transmits results in the compact <id>:<w|c|d>:<0|1> format, ensuring the menu renders instantly even with complex conditional logic.
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 →