# How the Omarchy Menu System Works: Entries, Guards, and Providers Explained

> Understand the Omarchy menu system. Learn how JSONC entries, Bash guards, and IPC providers create dynamic, responsive menus.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: internals
- Published: 2026-09-10

---

**Omarchy’s menu system uses JSONC-defined entries with Bash-based guards for conditional visibility and state, alongside dynamic providers that supply submenus via IPC, all batched through a subprocess to keep the UI responsive.**

The Omarchy menu system powers the desktop environment's dynamic, context-aware application launcher through a declarative JSONC configuration. By combining **guards** (conditional Bash expressions) with **providers** (external submenu generators), the system renders entries that react instantly to hardware detection, package presence, and user settings without blocking the UI thread.

## Declarative Menu Entries in JSONC

The foundation of the Omarchy menu system resides in `default/omarchy/omarchy-menu.jsonc`, which describes a tree of items. Each entry supports optional fields that control visibility, state, and data source:

- **`when`** — A Bash expression that determines row visibility. If the expression exits with a non-zero status, the entry is hidden.
- **`checked`** — A Bash expression that, when true, renders a ✓ marker next to the entry.
- **`disabled`** — A Bash expression that, when true, dims the row and disables cursor selection.
- **`provider`** — The name of an external binary that supplies a submenu dynamically (e.g., listing installed applications).

## Guard Evaluation for Conditional Entries

Guards enable context-aware menus by evaluating system state via Bash. All three guard types—`when`, `checked`, and `disabled`—are processed through the same pipeline but write different result tags (`w`, `c`, and `d` respectively) to distinguish their effects.

### The Batch Guard Execution Flow

When a menu opens, the system batches all guard evaluations into a single subprocess to prevent UI blocking:

1. **Collect guards** — `MenuModel.guardScript(root.items)` walks the item list and constructs a Bash script that prints lines formatted as `<id>:w:1`, `<id>:c:0`, or `<id>:d:1` for each guard condition.

2. **Execute script** — The `guardProc` Process element in `shell/plugins/menu/Menu.qml` runs the script via `bash -lc <script>`, capturing stdout line-by-line.

3. **Parse results** — On process exit, the output splits into three maps: `whenResults`, `checkedResults`, and `disabledResults`.

4. **Rebuild UI** — If the menu remains open (`root.opened`), `root.rebuildDisplay()` applies the corresponding CSS classes (`hidden`, `checked`, `disabled`) based on the result maps.

The evaluation is fully batched; a `guardsPending` flag prevents new evaluations from starting while a subprocess is active, ensuring the menu never blocks on individual guard commands.

## Dynamic Submenus via Providers

While guards filter and style static entries, **providers** inject entire submenus dynamically. A provider is any binary implementing the MenuProvider IPC contract.

### Provider Integration Flow

1. **Register provider** — In `shell/plugins/menu/Menu.qml`, the `providers` property maps names to binaries:
   ```qml
   property var providers: {
       apps: "omarchy-menu-apps",
       "my-apps": "omarchy-menu-my-apps"
   }
   ```

2. **Reference in JSONC** — An entry points to the provider via the `provider` field:
   ```jsonc
   "my.apps": {
       "icon":"󰀻",
       "label":"My Apps",
       "provider":"my-apps"
   }
   ```

3. **Load and merge** — When selected, `openExistingMenu(id)` loads the provider's surface, reads its JSONC output, and merges rows into the current tree via `mergeProviderRows`.

4. **Live updates** — Providers can emit a `changed` signal; the menu refreshes only the provider's rows without rebuilding the entire tree, maintaining performance.

## Practical Configuration Examples

To add a conditional "Hybrid GPU" entry that appears only when hybrid graphics hardware is detected:

```jsonc
"trigger.hardware.hybrid-gpu": {
  "icon":"",
  "label":"Hybrid GPU",
  "when":"omarchy-hw-hybrid-gpu",
  "action":"omarchy-launch-floating-terminal-with-presentation omarchy-toggle-hybrid-gpu"
}

```

To register a custom provider in the QML layer, extend the providers map in `shell/plugins/menu/Menu.qml`:

```qml
property var providers: {
  apps: "omarchy-menu-apps",
  "my-apps": "omarchy-menu-my-apps"
}

```

The guard script generation logic in [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) collects conditions into a single evaluable string:

```js
function guardScript(items) {
  let lines = []
  items.forEach(item => {
    if (item.when)    lines.push(`${item.id}:w:${item.when ? "1" : "0"}`);
    if (item.checked) lines.push(`${item.id}:c:${item.checked ? "1" : "0"}`);
    if (item.disabled)lines.push(`${item.id}:d:${item.disabled ? "1" : "0"}`);
  });
  return lines.length ? `for i in ${lines.join(' ')}; do eval "$i"; done` : "";
}

```

## Summary

- **Configuration** — Menu structure is declared in `default/omarchy/omarchy-menu.jsonc` using standard JSONC syntax with optional guard and provider fields.
- **Guard Batching** — All conditional expressions are evaluated in a single subprocess via `MenuModel.guardScript()` and `guardProc` to prevent UI lag.
- **State Management** — Guards control three distinct properties: `when` (visibility), `checked` (selection state), and `disabled` (interaction lock).
- **Provider Architecture** — External binaries registered in `Menu.qml` supply dynamic submenus through the MenuProvider IPC contract, merged via `mergeProviderRows`.
- **Performance** — Guard results and provider updates are cached and applied incrementally, ensuring the Omarchy menu system remains responsive during rapid system state changes.

## Frequently Asked Questions

### How does Omarchy handle multiple guards without slowing down the menu?

The system batches all guard evaluations into a single Bash script executed by `guardProc`. This subprocess runs asynchronously, and the UI updates only after all results are parsed into `whenResults`, `checkedResults`, and `disabledResults`. A `guardsPending` flag prevents redundant executions if the menu changes rapidly.

### Can I create custom providers for the Omarchy menu system?

Yes. Any binary implementing the MenuProvider IPC contract can supply submenu data. Register the provider in the `providers` map inside `shell/plugins/menu/Menu.qml`, then reference it via the `provider` field in your JSONC entry. The menu calls `openExistingMenu()` to load your provider and merges its output using `mergeProviderRows`.

### What happens if a guard Bash expression returns an error?

For `when` expressions, a non-zero exit status (including errors) causes the entry to be hidden. For `checked` and `disabled`, the specific guard type determines the default fallback state, but generally, a failed expression evaluates as false (unchecked or enabled), ensuring the menu remains functional even when hardware detection scripts fail.

### Where is the menu configuration stored and how is it parsed?

The primary definition lives at `default/omarchy/omarchy-menu.jsonc`. The menu QML watches this file for changes. The JSONC structure supports comments and defines a tree where each node may contain `when`, `checked`, `disabled`, or `provider` fields that the system evaluates at runtime.