# How to Create Custom Omarchy Menu Extensions: A Complete Guide

> Learn to create custom Omarchy menu extensions by editing the omarchy-menu.jsonc file. This guide details merging custom menus with defaults for a personalized experience.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-08-31

---

**Omarchy menu extensions are created by editing `~/.config/omarchy/extensions/omarchy-menu.jsonc`, which gets merged with the default menu at runtime using the `mergeMenuSources` function in [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js).**

Omarchy's command menu system is built on the `omarchy.menu` Quickshell plugin and offers a flexible, JSONC-based extension mechanism. This guide explains how to add custom entries, submenus, and conditional visibility to tailor the launcher to your workflow.

---

## Understanding the Omarchy Menu Architecture

The menu structure is defined by two JSONC files that Omarchy merges when the shell starts:

- **`default/omarchy/omarchy-menu.jsonc`** – The shipped default menu definition
- **`~/.config/omarchy/extensions/omarchy-menu.jsonc`** – Your custom extensions

The merge logic lives in [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) within the `mergeMenuSources` function. This overlay system works key-by-key:

- Matching IDs receive **partial updates** (change only `label` or `icon` without touching `action`)
- New IDs are **appended** to the menu tree
- A synthetic `root` entry is injected when neither file defines one

If your extensions file doesn't exist, `omarchy-refresh-config` creates it automatically from the sample at `config/omarchy/extensions/omarchy-menu.jsonc`.

---

## Entry Schema for Custom Omarchy Menu Extensions

Each menu entry supports these core fields:

| Field | Purpose |
|-------|---------|
| `icon` | Nerd Font glyph displayed in the icon column |
| `label` | Human-readable title (defaults to entry ID) |
| `action` | Bash command executed when selected |
| `target` | ID of another submenu to open (turns entry into a navigation link) |
| `when` | Bash condition that hides the entry when false |
| `checked` | Bash condition that shows a checkmark when true |
| `disabled` | Bash condition that dims the entry when true |

Guards (`when`, `checked`, `disabled`) are evaluated in a batched Bash process for performance. For dynamic content—like listing installed applications—point a submenu to a **provider** such as `apps`, `fonts`, or `power-profiles`. Providers are defined in `shell/plugins/menu/Menu.qml`.

---

## Creating Your First Custom Menu Extension

### Step 1: Locate or Create the Extensions File

Ensure the file exists at:

```bash
~/.config/omarchy/extensions/omarchy-menu.jsonc

```

If missing, run:

```bash
omarchy-refresh-config

```

### Step 2: Add Entries Using Dotted-ID Notation

Use dot-separated IDs to place entries anywhere in the hierarchy. For example, `personal.notes` nests under `personal`.

### Step 3: Apply Changes Instantly

Omarchy monitors the extensions file. Press **Super + Space** or run:

```bash
omarchy menu refresh

```

No shell restart required.

---

## Practical Omarchy Menu Extension Examples

### Add a Simple Launcher Entry

Open a terminal with Vim for quick notes:

```jsonc
{
  // ~/.config/omarchy/extensions/omarchy-menu.jsonc
  "personal": {
    "label": "Personal"
  },

  "personal.notes": {
    "icon": "\uf15c",
    "label": "Notes",
    "action": "omarchy launch-terminal \"vim ~/notes.txt\""
  }
}

```

The `\uf15c` is a Nerd Font "file-text" glyph.

### Conditionally Show Entries Based on Package Installation

Display Syncthing UI only when the package is present:

```jsonc
{
  "personal.syncthing": {
    "icon": "\uf0e7",
    "label": "Syncthing UI",
    "action": "omarchy launch-browser http://localhost:8384",
    "when": "$(omarchy-pkg-present syncthing)"
  }
}

```

The `omarchy-pkg-present` utility returns exit code 0 only when the package is installed.

### Create a Submenu with a Built-in Provider

Reuse Omarchy's application launcher as a submenu:

```jsonc
{
  "tools": {
    "label": "Tools",
    "provider": "apps"
  }
}

```

---

## Controlling the Menu from CLI

The `bin/omarchy-menu` script provides programmatic access:

| Command | Effect |
|---------|--------|
| `omarchy menu` | Toggle the root menu |
| `omarchy menu toggle system` | Open/close the "system" submenu |
| `omarchy menu summon style.theme` | Directly activate a specific entry |
| `omarchy menu refresh` | Force re-parsing of all JSONC sources |

These commands work from shell scripts, keybindings, or automation tools.

---

## Testing Custom Omarchy Menu Extensions

Verify your extensions with the built-in test suite:

```bash
./test/shell

```

Specifically, [`test/shell.d/menu-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/menu-test.sh) validates JSONC parsing and merging, while [`test/shell.d/menu-guards-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/menu-guards-test.sh) checks conditional visibility logic. Run these after adding complex guards to catch syntax errors early.

---

## Summary

- Custom **Omarchy menu extensions** live in `~/.config/omarchy/extensions/omarchy-menu.jsonc`
- The `mergeMenuSources` function in [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) overlays your entries onto defaults
- Use **dotted IDs** (`category.item`) to position entries anywhere in the tree
- **Guards** (`when`, `checked`, `disabled`) enable conditional visibility via Bash expressions
- **Providers** (`apps`, `fonts`, etc.) generate dynamic submenu content
- Changes apply **instantly** without restarting the shell
- **Test** extensions with `./test/shell` before committing to your dotfiles

---

## Frequently Asked Questions

### What happens if my custom entry uses the same ID as a default entry?

Only the fields you explicitly declare are replaced. You can retitle or re-icon a default entry without redefining its action. Omit `action` entirely to keep the original behavior while changing the label.

### Can I remove or hide default menu entries?

Yes—override the entry with a `when` guard that always evaluates false: `"when": "false"`. The entry disappears from the menu while preserving the original definition in `default/omarchy/omarchy-menu.jsonc`.

### How do I find valid Nerd Font icon codes?

Browse [nerdfonts.com/cheat-sheet](https://www.nerdfonts.com/cheat-sheet) for glyph codes. Prefix with `\u` and use four hexadecimal digits (e.g., `\uf15c`). Verify the glyph renders in your terminal before adding to the menu.

### Do I need to restart Omarchy after editing the extensions file?

No. The `omarchy-shell` process watches `~/.config/omarchy/extensions/omarchy-menu.jsonc` via filesystem notification. Use `omarchy menu refresh` if you suspect the watcher missed an update.