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 label
  • label — Human-readable text shown in the UI
  • action — Shell command executed when the entry is selected
  • target — URL or path for link-type entries
  • aliases — Array of alternate names for omarchy menu summon <alias> invocation
  • when — Optional shell condition; entry appears only if the test returns true
  • provider — References a custom QML provider for specialized submenu rendering
  • title — Optional header text when the submenu is open (defaults to label)
  • 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:

  1. File reading — The QML plugin loads omarchy-menu.jsonc from the system path
  2. Comment stripping — JavaScript regex removes // comments: raw.replace(/\/\/.*$/gm, '')
  3. 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:

  1. Opening default/omarchy/omarchy-menu.jsonc
  2. Creating a dotted ID at the appropriate hierarchy level
  3. Populating the relevant properties (action for commands, target for 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.jsonc serves 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.qml processes JSONC on each menu invocation for instant updates
  • Conditional visibility: The when property integrates shell conditions for dynamic menu contents
  • CLI aliases: Multiple aliases per 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →