# How the Omarchy Menu System Defines Entries and Providers in `omarchy-menu.jsonc`

> Discover how the Omarchy menu system defines entries and providers in omarchy-menu.jsonc. Learn about static commands, conditional guards, and dynamic JavaScript provider functions for generating submenus.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: internals
- Published: 2026-08-19

---

**The Omarchy menu system uses a hierarchical JSONC configuration file where dotted keys define menu paths, and each entry can specify static commands, conditional guards, or delegate to JavaScript provider functions that generate submenu items at runtime.**

The Omarchy desktop environment implements a flexible, data-driven menu architecture through a single configuration file. Located in the `basecamp/omarchy` repository, this system allows users and developers to declare application launchers, system controls, and dynamic submenus using declarative syntax that supports hot-reloading and user-level extensions.

## Structure of the `omarchy-menu.jsonc` File

The core menu definition resides at `default/omarchy/omarchy-menu.jsonc`. This file contains a single JSONC object where **keys are dotted identifiers** that implicitly create the menu hierarchy. For example, a key named `personal.notes` automatically establishes a `personal` parent node containing a `notes` child, eliminating the need to manually declare intermediate containers.

At runtime, the shell merges this default configuration with user extensions found at `~/.config/omarchy/extensions/omarchy-menu.jsonc`, allowing local overrides without modifying core repository files.

### Core Entry Properties

Each menu entry object supports the following properties:

- **label** (string): The display text shown in the menu interface.
- **icon** (string, optional): An icon identifier from the Omarchy icon font.
- **command** (string, optional): The shell command executed when the entry is activated.
- **provider** (string, optional): The name of a JavaScript function that returns dynamic submenu items.
- **guard** (string, optional): A JavaScript expression evaluated to determine entry visibility.
- **children** (object, optional): Inline nested menu definitions for static sub-trees.

## Static Commands vs Dynamic Providers

The menu system distinguishes between static entries that execute fixed commands and dynamic entries that populate their submenus at runtime through provider functions.

### Defining Static Menu Entries

Static entries map directly to executable actions. These are ideal for launching applications or triggering system commands.

```jsonc
{
  "system.shutdown": {
    "label": "Shutdown",
    "icon": "power",
    "command": "systemctl poweroff"
  },
  "apps.browser": {
    "label": "Web Browser",
    "icon": "firefox",
    "command": "firefox"
  }
}

```

When a user selects the **Shutdown** entry, the shell executes `systemctl poweroff` immediately.

### Implementing Provider Functions

**Providers** enable dynamic content generation. Defined as JavaScript functions in `shell/plugins/menu/providers/`, these modules export functions that receive a context object and return an array of entry objects conforming to the same schema as static definitions.

```javascript
// shell/plugins/menu/providers/runningAppsProvider.js
export function runningAppsProvider(context) {
  const apps = getRunningApps(); // Platform-specific helper
  return apps.map(app => ({
    label: app.name,
    command: `focus-app ${app.id}`,
    icon: "application"
  }));
}

```

To invoke a provider, reference its exported function name in the `provider` field:

```jsonc
{
  "apps.running": {
    "label": "Running Applications",
    "icon": "apps",
    "provider": "runningAppsProvider"
  }
}

```

When the user expands **Running Applications**, the shell invokes `runningAppsProvider`, caches the returned array, and renders the dynamic items as a submenu.

## Conditional Visibility with Guards

**Guards** allow conditional entry visibility based on runtime state. These are JavaScript expressions evaluated in the same context as providers. If a guard evaluates to a falsy value, the entry is omitted from the rendered menu.

```jsonc
{
  "hardware.nvidia": {
    "label": "NVIDIA Settings",
    "command": "nvidia-settings",
    "guard": "hw.nvidiaPresent"
  }
}

```

In this example, the **NVIDIA Settings** entry only appears when the `hw.nvidiaPresent` helper reports a compatible GPU. Guards can reference any context variables available to providers, making them suitable for hardware detection, package availability checks, or user preference validation.

## Loading Order and Runtime Behavior

The menu system follows a specific initialization sequence implemented in `shell/plugins/menu/Menu.qml`:

1. **Default Loading**: The parser reads `default/omarchy/omarchy-menu.jsonc` into an internal object tree.
2. **Extension Merging**: User configuration from `~/.config/omarchy/extensions/omarchy-menu.jsonc` is deep-merged, allowing additions and overrides of existing dotted keys.
3. **Provider Registration**: Provider functions are imported from `shell/plugins/menu/providers/` and bound to their string identifiers.
4. **Hot-Reload**: File system watchers monitor both JSONC files; any modification triggers a complete reparse and UI refresh without restarting the shell.

This architecture ensures that developers can iterate on menu configurations instantly, while end-users can extend functionality safely without touching repository files.

## Summary

- The **Omarchy menu system** centralizes configuration in `omarchy-menu.jsonc`, using dotted keys to define implicit hierarchies.
- **Static entries** specify `command` strings for immediate execution, while **dynamic entries** reference JavaScript **providers** that return submenu items at runtime.
- **Guards** are JavaScript expressions that conditionally hide entries based on hardware, software, or user context.
- User extensions at `~/.config/omarchy/extensions/omarchy-menu.jsonc` are merged with defaults, enabling safe customization.
- The system supports **hot-reloading** via `shell/plugins/menu/Menu.qml`, applying changes immediately upon file save.

## Frequently Asked Questions

### What is the difference between a command and a provider?

A **command** is a static shell string executed immediately when the user selects the entry. A **provider** is a JavaScript function that returns an array of entry objects, enabling dynamic content generation such as listing recent files, running processes, or available AI models. Providers are evaluated only when their parent menu opens, ensuring lazy initialization of expensive operations.

### How do I add a custom provider to Omarchy?

Create a new JavaScript file in `shell/plugins/menu/providers/` that exports a function returning an array of entry objects. The function receives a context object containing platform helpers. Then reference the function name in the `provider` field of your `omarchy-menu.jsonc` entry. Ensure the filename matches the function name for clarity, though the system resolves providers by their export name rather than filename.

### Why is my menu entry not appearing?

Check the **guard** expression if defined; the entry is hidden when the guard evaluates to falsy. Verify that the dotted key path is correct and that you have not accidentally overwritten the entry in a user extension. For provider-based entries, inspect the browser console or shell logs for JavaScript errors in your provider function, as runtime exceptions will cause the submenu to render empty.

### Can I override default menu entries without editing core files?

Yes. Create or edit `~/.config/omarchy/extensions/omarchy-menu.jsonc` and define an entry with the same dotted key as the default you wish to override. The merge process deep-merges objects at matching keys, allowing you to redefine properties like `label`, `command`, or `provider` while inheriting unspecified properties from the default configuration.