# How to Create Menu Entries with Guards and Provider Functions in Omarchy

> Learn to create dynamic Omarchy menu entries using when guards and action provider functions in omarchy-menu.jsonc. Build context-aware menus easily.

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

---

**Use the `when` field for conditional visibility guards and the `action` field for provider functions in `omarchy-menu.jsonc` to build dynamic, context-aware menu entries.**

Omarchy’s extensible menu system is driven by a JSON-C configuration file that supports runtime conditional logic and external command providers. By leveraging **guards** to control visibility and **provider functions** to execute actions, you can create menu entries that adapt to the current environment, available binaries, or specific system states. This guide walks through the implementation details found in the `omacom/omarchy` source code.

## Understanding the Omarchy Menu Structure

Omarchy defines its core menu hierarchy in `default/omarchy/omarchy-menu.jsonc`. Each entry uses a dotted identifier (e.g., `setup.plugin.remove`) that determines its placement in the menu tree. The configuration accepts four primary fields per entry:

- **`icon`**: A Unicode character or Nerd Font icon for the visual indicator
- **`label`**: The display text shown in the launcher
- **`when`**: An optional shell command that acts as a **guard** to determine visibility
- **`action`**: The **provider function** or command executed when the entry is selected

User customizations belong in `~/.config/omarchy/extensions/omarchy-menu.jsonc`, which Omarchy hot-reloads automatically alongside the default configuration.

## Using Guards to Conditionally Display Entries

### The `when` Field Syntax

The **guard** mechanism relies on the `when` field, which Omarchy evaluates using `bash -c`. If the command exits with status `0`, the entry is displayed; any non-zero exit code filters the entry from the current menu render. This allows you to check for command existence, file presence, environment variables, or service states before showing an option.

In `default/omarchy/omarchy-menu.jsonc`, the *Remove Plugin* entry demonstrates this pattern by checking for existing plugin manifests:

```jsonc
"setup.plugin.remove": {
  "icon": "󰭌",
  "label": "Remove Plugin",
  "when": "compgen -G \"$HOME/.config/omarchy/plugins/*/manifest.json\"",
  "action": "omarchy-menu-plugin remove"
}

```

### Common Guard Patterns

You can implement guards using standard shell constructs:

- **Command existence**: `omarchy-cmd-present omarchy-menu-plugin`
- **File presence**: `[[ -e "$HOME/.config/omarchy/plugins/myplugin/manifest.json" ]]`
- **Session type check**: `[[ $XDG_SESSION_TYPE == wayland ]]`
- **Package availability**: `omarchy-pkg-present git`

## Implementing Provider Functions with the `action` Field

### Built-in Providers

The `action` field specifies the **provider function**—the executable or script that runs when a user selects the entry. Most built-in actions delegate to `bin/omarchy-menu-plugin`, a central dispatcher that handles enable, disable, clone, and remove operations while launching the Quickshell IPC surface.

The emoji picker entry shows a simple provider invocation:

```jsonc
"trigger.emoji": {
  "icon": "",
  "label": "Emoji",
  "aliases": ["emoji","emojis"],
  "action": "omarchy-menu-emoji"
}

```

### Custom Provider Scripts

For specialized workflows, you can point `action` to custom scripts. These scripts can invoke `omarchy-menu-select` to present dynamic submenus or execute arbitrary system commands. The provider receives no arguments by default, but you can wrap logic in shell scripts that parse the environment or call other Omarchy utilities.

## Creating Custom Menu Entries

### User Extension File

Create or edit `~/.config/omarchy/extensions/omarchy-menu.jsonc` to add personal entries without modifying core files. The format mirrors the default configuration, supporting the same `when` and `action` fields.

A minimal custom entry that only appears when Neovim is installed:

```jsonc
// ~/.config/omarchy/extensions/omarchy-menu.jsonc
{
  "personal.notes": {
    "icon": "🗒️",
    "label": "My Notes",
    "when": "[[ -x $(command -v nvim) ]]",
    "action": "omarchy-menu-plugin exec nvim ~/notes.md"
  }
}

```

### Practical Examples

**1. Platform-Specific Entry**
Display a Wayland information panel only on Wayland sessions:

```jsonc
{
  "system.wayland-info": {
    "icon": "",
    "label": "Wayland Info",
    "when": "[[ $XDG_SESSION_TYPE == wayland ]]",
    "action": "omarchy-menu-plugin exec weston-info"
  }
}

```

**2. Service Management Guard**
Show a removal option only when the SSH daemon is enabled:

```jsonc
{
  "service.sshd.remove": {
    "icon": "",
    "label": "Remove SSH Daemon",
    "when": "systemctl is-enabled sshd.service >/dev/null",
    "action": "omarchy-menu-plugin systemctl disable sshd.service && omarchy-menu-plugin systemctl stop sshd.service"
  }
}

```

**3. Dynamic List Provider**
Create a custom script at `~/.local/bin/my-menu-list-git-repos` to populate a dynamic submenu:

```bash
#!/usr/bin/env bash

# List all git repos under $HOME/projects

repos=($(find "$HOME/projects" -maxdepth 2 -type d -name ".git" -printf "%h\n"))
omarchy-menu-select "Pick a repo" "${repos[@]}" --mode=launch

```

Then reference it in your extension file:

```jsonc
{
  "dev.git-repos": {
    "icon": "",
    "label": "Git Repos",
    "action": "$HOME/.local/bin/my-menu-list-git-repos"
  }
}

```

## Summary

- **Guards** use the `when` field with shell commands evaluated by `bash -c` to conditionally display entries based on runtime state
- **Provider functions** specified in the `action` field execute when an entry is selected, typically delegating to `omarchy-menu-plugin` or custom scripts
- Core definitions live in `default/omarchy/omarchy-menu.jsonc` while user extensions belong in `~/.config/omarchy/extensions/omarchy-menu.jsonc`
- The dotted identifier syntax (e.g., `personal.notes`) determines menu hierarchy placement
- Changes to extension files trigger automatic hot-reloads without restarting the session

## Frequently Asked Questions

### How does Omarchy evaluate the `when` guard condition?

Omarchy passes the `when` string directly to `bash -c` at menu render time. If the command exits with status `0`, the entry is included; otherwise it is filtered out. This evaluation occurs every time the menu opens, ensuring entries reflect the current system state.

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

Yes. Create entries in `~/.config/omarchy/extensions/omarchy-menu.jsonc` using the same identifier as a default entry. Omarchy merges configurations with user extensions taking precedence, allowing you to override icons, labels, guards, or actions without modifying `default/omarchy/omarchy-menu.jsonc`.

### What is the difference between `omarchy-menu-plugin` and direct commands in the `action` field?

`omarchy-menu-plugin` is a specialized dispatcher that runs inside the Quickshell IPC surface, providing consistent UI patterns for enable, disable, and exec operations. Direct commands run outside this context and are suitable for simple launches or custom scripts that handle their own UI logic. Use `omarchy-menu-plugin exec` to launch external applications while maintaining integration with the Omarchy environment.

### Where can I find the complete schema documentation for menu entries?

Reference [`docs/menu.md`](https://github.com/omacom/omarchy/blob/main/docs/menu.md) in the Omarchy repository for the full JSON-C schema, guard syntax specifications, and provider conventions. For end-user guidance on the extension file location and format, consult [`manual/31-dotfiles.md`](https://github.com/omacom/omarchy/blob/main/manual/31-dotfiles.md).