# Omarchy Menu Provider System: How Dynamic Menu Generation Works

> Explore the Omarchy menu provider system, a runtime extension that dynamically generates submenu items using JavaScript modules. Learn how it works with static JSON-C definitions.

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

---

**The Omarchy menu provider system is a runtime extension mechanism that generates dynamic submenu items on demand by calling JavaScript provider modules declared in the static JSON-C menu definition.**

Menu providers solve a fundamental problem in desktop environments: the gap between static configuration files and live system state. The `omacom/omarchy` project implements this through a clean separation—the base hierarchy lives in `default/omarchy/omarchy-menu.jsonc`, while dynamic content is supplied by specialized modules under `shell/plugins/menu/providers/`.

---

## How the Provider Mechanism Works

The core logic resides in [[`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js)](https://github.com/omacom/omarchy/blob/quattro/shell/plugins/menu/MenuModel.js). When the QML UI (`Menu.qml`) requests rows for a submenu, the model performs a simple branch:

- **No provider declared**: Returns children directly from the static JSON-C structure.
- **Provider declared**: Dynamically imports the named module and invokes its `provide(menuId, context)` function.

The provider returns an array of menu items (or a Promise resolving to one). These rows are merged into the model with an added `providerMenu` property tracking their origin—critical for search indexing and targeted refreshes.

---

## Declaring a Provider in the Menu Definition

Static entries live in `default/omarchy/omarchy-menu.jsonc`. To enable dynamic generation, add a `"provider"` field:

```jsonc
{
  "id": "power",
  "label": "Power",
  "icon": "mdi:power",
  "provider": "power-menu"
}

```

When users open the *Power* submenu, [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) locates [`shell/plugins/menu/providers/power-menu.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/providers/power-menu.js) and executes its exported function.

---

## Writing a Custom Provider Module

Provider modules are standard JavaScript files exporting a `provide()` function. They receive the menu ID and a context object with Quickshell environment access.

Here's a minimal provider implementing reboot and shutdown actions:

```javascript
// shell/plugins/menu/providers/example-provider.js
export function provide(menuId, ctx) {
  return [
    {
      id: `${menuId}-reboot`,
      kind: "action",
      label: "Reboot",
      icon: "mdi:restart",
      action: "omarchy-reboot"
    },
    {
      id: `${menuId}-shutdown`,
      kind: "action",
      label: "Shutdown",
      icon: "mdi:power-off",
      action: "omarchy-shutdown"
    }
  ];
}

```

The `kind: "action"` designation tells the UI these are executable items. Other kinds include `"submenu"` for nested navigation or `"link"` for external URLs.

---

## Provider Integration in MenuModel.js

The merging logic in [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) handles the complexity of combining static and dynamic content:

```javascript
function loadProviderRows(menuId) {
  const entry = items[menuId];
  if (!entry.provider) return [];

  const providerModule = require(`./providers/${entry.provider}.js`);
  const rows = providerModule.provide(menuId, { /* context */ });
  rows.forEach(row => (row.providerMenu = menuId));
  return rows;
}

```

Key behaviors:
- **Path resolution**: Provider names map directly to filenames in `shell/plugins/menu/providers/`
- **Metadata injection**: Each row receives `providerMenu = menuId` for lifecycle management
- **Error isolation**: A failing provider returns empty rows rather than crashing the menu

---

## Built-in Provider Types

The Omarchy menu provider system ships with several standard implementations:

- **`power-menu`** — Generates sleep, reboot, shutdown, and lock actions based on available system capabilities
- **`settings`** — Discovers installed settings panels and hardware configuration modules
- **`app-discovery`** — Scans `$PATH` and parses `.desktop` files to populate application launchers

These providers enable the *Install* → *Applications* flow and system-dependent configuration menus without hard-coding every possible option.

---

## Refreshing Dynamic Content

Provider results are cached per session. When system state changes—power profile switches, new applications installed, settings modules added—the UI must update.

Trigger a targeted refresh via CLI:

```bash
omarchy-update-menu --menu=power

```

This command signals [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) to:
1. Discard cached rows where `providerMenu === "power"`
2. Re-execute the `power-menu` provider
3. Emit model change notifications to update the UI

The refresh granularity (per-menu rather than full rebuild) preserves performance for large menu hierarchies.

---

## Search Integration

Provider-generated rows participate fully in Omarchy's menu search. The `providerMenu` annotation enables:

- **Pruning**: When a provider refreshes, only its contributed rows are removed from the search index
- **Re-ranking**: Fresh provider data can influence result ordering based on current context
- **Filtering**: Search can exclude specific provider sources (e.g., hide applications during system recovery)

---

## Summary

- **Static foundation**: `default/omarchy/omarchy-menu.jsonc` defines the base hierarchy with optional `"provider"` hooks
- **Dynamic extension**: JavaScript modules in `shell/plugins/menu/providers/` implement `provide(menuId, context)` to generate runtime content
- **Seamless integration**: [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) merges static and provider rows, tracks provenance via `providerMenu`, and handles caching
- **Operational control**: The `omarchy-update-menu` CLI triggers granular refreshes; search indexing respects provider boundaries

---

## Frequently Asked Questions

### What file format does Omarchy use for its static menu definition?

Omarchy uses **JSON-C** (JSON with Comments) for `omarchy-menu.jsonc`. This format accepts standard JSON plus JavaScript-style line comments and trailing commas, making hand-editing more forgiving than strict JSON.

### Can a single menu entry combine static children with a provider?

Yes. When a provider is declared, its returned rows **merge** with any static children defined in the JSON-C file. The [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) implementation preserves both sources, allowing hybrid menus where some items are fixed and others are dynamically discovered.

### How do I debug a provider that isn't generating expected menu items?

Check three locations: first, verify the `"provider"` name in `omarchy-menu.jsonc` matches the filename (minus `.js`) in `shell/plugins/menu/providers/`. Second, ensure your `provide()` function exports correctly and handles the `context` parameter. Third, inspect Quickshell's JavaScript console—provider exceptions are caught but logged, and `console.log()` output from providers appears there.

### Is the provider system limited to built-in menu types?

No. The provider architecture is fully extensible. Create a new `.js` file in `shell/plugins/menu/providers/`, export a `provide()` function, and reference it by name in any menu entry's `"provider"` field. The system imposes no restrictions on provider logic—you can query D-Bus, read files, or call external binaries to build menu content.