How JSONC Format Powers Omarchy's Menu System: A Deep Dive into Configuration-Driven UI
Omarchy uses JSONC (JSON with comments) as the single source of truth for its entire menu hierarchy, enabling declarative menu customization without code changes.
The JSONC format plays a central role in how the Omarchy desktop environment defines, extends, and documents its interactive menu system. Unlike traditional binary or compiled menu configurations, Omarchy stores its complete top-level menu definition in default/omarchy/omarchy-menu.jsonc. This approach separates presentation logic from data structure, making the system both maintainable and approachable for contributors.
What Is JSONC and Why Omarchy Chose It
JSONC extends standard JSON by allowing JavaScript-style // comments. This single addition transforms a rigid data format into a self-documenting configuration language.
The decision to use JSONC rather than plain JSON or YAML follows a specific design philosophy in Omarchy: data structures should carry their own documentation. The omarchy-menu.jsonc file contains extensive inline comments that explain field semantics, provider mechanisms, and extension patterns—information that would otherwise require a separate documentation file prone to drift.
Anatomy of the Omarchy Menu JSONC File
Located at default/omarchy/omarchy-menu.jsonc, the core menu definition uses dot-separated IDs to represent hierarchical relationships. Each segment creates a nested submenu, enabling flat file storage of arbitrarily deep menu trees.
Key Properties in Menu Entries
Every object in the JSONC file supports these fields:
icon— Glyph from the Omarchy icon font displayed alongside the labellabel— Human-readable text shown in the UIaction— Shell command executed when the entry is selectedtarget— URL or path for link-type entriesaliases— Array of alternate names foromarchy menu summon <alias>invocationwhen— Optional shell condition; entry appears only if the test returns trueprovider— References a custom QML provider for specialized submenu renderingtitle— Optional header text when the submenu is open (defaults tolabel)iconFont— Override font family for the icon glyph
Entry Type Inference
The Quickshell runtime at shell/plugins/menu/Menu.qml infers each entry's kind automatically:
| Condition | Resulting Kind |
|---|---|
Contains action |
Command item |
Contains target |
Link item |
| Neither present | Submenu container |
This inference eliminates boilerplate—developers supply only semantically relevant fields.
Practical JSONC Examples from the Source
The following snippets demonstrate real patterns from default/omarchy/omarchy-menu.jsonc:
// Omarchy menu definition.
// Kind is inferred: action -> action, target -> link, otherwise submenu.
// Dotted IDs define the tree. provider:"name" points a submenu at one of the shell's providers...
// aliases alternate `omarchy menu summon <name>` routes; also searchable.
// iconFont font family used for the icon glyph, when it differs from the menu font
// title header text shown when the submenu is open; defaults to label
"system": {"icon":"","label":"System","aliases":["power-menu"]},
"learn.keybindings": {"icon":"","label":"Keybindings","action":"omarchy-menu-keybindings"},
"trigger.share.clipboard": {"icon":"","label":"Clipboard","action":"omarchy-menu-share clipboard"},
"setup.plugin.remove": {"icon":"","label":"Remove Plugin","when":"compgen -G \"$HOME/.config/omarchy/plugins/*/manifest.json\"","action":"omarchy-menu-plugin remove"},
The system entry illustrates alias functionality—both omarchy menu summon system and omarchy menu summon power-menu resolve to the same submenu. The setup.plugin.remove entry demonstrates conditional visibility using a shell glob test that checks for existing plugin manifests.
Runtime Consumption: From JSONC to Interactive UI
The transformation from static file to interactive menu occurs in shell/plugins/menu/Menu.qml. The parsing pipeline follows three stages:
- File reading — The QML plugin loads
omarchy-menu.jsoncfrom the system path - Comment stripping — JavaScript regex removes
//comments:raw.replace(/\/\/.*$/gm, '') - JSON parsing and tree building — The cleaned content parses into an object, then maps to internal Quickshell data structures keyed by dotted IDs
This runtime parsing means menu changes require no compilation or restart—modifications to the JSONC file reflect immediately in the next menu invocation.
Extending the Menu System Without Code Changes
The JSONC architecture enables zero-code customization for most menu extensions. Adding a new entry requires only:
- Opening
default/omarchy/omarchy-menu.jsonc - Creating a dotted ID at the appropriate hierarchy level
- Populating the relevant properties (
actionfor commands,targetfor links, or neither for submenus)
For conditional entries, the when property accepts any shell command that returns exit code 0 for visibility. This integration with the shell environment allows dynamic menu contents based on system state—installed packages, running processes, or file existence.
Command-Line Integration with JSONC Aliases
The aliases field creates multiple entry points for the same functionality. This design aligns the menu system with Omarchy's CLI-first philosophy.
# Summon the "system" submenu (alias "power-menu" works too)
omarchy menu summon system
omarchy menu summon power-menu
# Run the keybindings helper directly via its action
omarchy-menu-keybindings # same command that the menu entry triggers
# Use a dotted ID to invoke a submenu item in a script
omarchy menu summon learn.keybindings
The dotted ID syntax enables precise targeting of nested items without traversing parent menus programmatically.
Summary
- JSONC location:
default/omarchy/omarchy-menu.jsoncserves as the canonical menu definition - Self-documenting: Inline
//comments explain schema and semantics without external documentation - Hierarchical IDs: Dot-separated keys like
"learn.keybindings"define tree structure in a flat file - Type inference: The runtime deduces entry kinds from field presence, eliminating boilerplate
- Runtime parsing:
shell/plugins/menu/Menu.qmlprocesses JSONC on each menu invocation for instant updates - Conditional visibility: The
whenproperty integrates shell conditions for dynamic menu contents - CLI aliases: Multiple
aliasesper entry create flexible command-line invocation patterns
Frequently Asked Questions
How does Omarchy parse JSONC comments?
The Quickshell plugin at shell/plugins/menu/Menu.qml uses a JavaScript regex to strip comments before parsing: raw.replace(/\/\/.*$/gm, ''). This removes // line comments while preserving the underlying JSON structure, then passes the cleaned content to JSON.parse().
Can I add custom menu items without modifying Omarchy's source code?
Yes. The JSONC file is parsed at runtime, so adding entries to default/omarchy/omarchy-menu.jsonc requires no recompilation. For user-specific customizations without touching system files, check whether Omarchy's configuration overlay system supports user-level menu overrides in ~/.config/omarchy/.
What happens if a menu entry has both action and target properties?
The type inference logic in Menu.qml prioritizes explicit fields: an action takes precedence and creates a command item, while target creates a link only when no action is present. Having both likely results in command behavior, though this pattern should be avoided for clarity.
How do conditional menu entries work in practice?
The when property accepts any shell command. Entries appear only when the command exits with status 0. The setup.plugin.remove entry demonstrates this with "when":"compgen -G \"$HOME/.config/omarchy/plugins/*/manifest.json\"", which tests for the existence of any plugin manifest files before showing the removal option.
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 →