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

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:

"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:

"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:

// ~/.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:

{
  "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:

{
  "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:

#!/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:

{
  "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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →