# How the Omarchy Menu's `checked` Field Wires to Shell Conditions

> Learn how the Omarchy menu's checked field wires to shell conditions. Discover how Bash expressions determine menu item visibility and state.

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

---

**The `checked:` field in Omarchy's JSONC menu definition contains a Bash expression that gets evaluated once per menu opening, with the Boolean result stored in `checkedResults` and rendered as a "✓" glyph via `MenuModel.labelFor()`.**

The Omarchy desktop environment uses a dynamic menu system where check-marks reflect real-time shell state. This article explains how the `checked` field in menu definitions connects to underlying shell conditions, tracing the full execution pipeline from JSONC configuration to QML rendering.

## Where Menu `checked` Fields Are Defined

Menu entries live in `default/omarchy/omarchy-menu.jsonc`. Each entry can specify a **`checked:`** property containing arbitrary Bash code.

The syntax is straightforward:

```jsonc
"setup.default.browser.firefox": {
  "icon": "",
  "label": "Firefox",
  "checked": "[[ \"$(omarchy-default-browser)\" == \"firefox\" ]]",
  "action": "omarchy-default-browser firefox"
}

```

When this menu opens, the Firefox entry displays a check-mark only if `omarchy-default-browser` currently returns `"firefox"`.

## How MenuModel.js Processes `checked` Guards

The [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) module orchestrates evaluation. It collects guards, builds a Bash script, executes it, and maps results for UI consumption.

### Step 1: Collect Guard Expressions

Lines 85-88 scan the parsed menu entries and accumulate `checked:` expressions (alongside `when:` and `disabled:`):

```js
if (entry.checked) guards += guardLine(ids[i], "c", entry.checked)

```

The `"c"` tag identifies this as a **checked** guard versus `"d"` for disabled or `"w"` for when.

### Step 2: Build the Guard Evaluation Script

The `guardLine` function (lines 69-71) generates Bash that runs each expression in a subshell:

```js
function guardLine(id, tag, expression) {
  return "if { " + substituteGuardReaders(expression) +
         "; } >/dev/null 2>&1; then echo " + id + ":" + tag + ":1; " +
         "else echo " + id + ":" + tag + ":0; fi\n"
}

```

This produces deterministic output: `<id>:<tag>:1` for true, `<id>:<tag>:0` for false.

### Step 3: Execute and Parse Results

The combined `guardScript` runs once. Output lines populate two maps:

- `root.checkedResults` — id → Boolean for `checked` guards
- `root.disabledResults` — id → Boolean for `disabled` guards

This single batch evaluation minimizes shell fork overhead during menu rendering.

### Step 4: Generate Display Labels with `labelFor`

The `labelFor` helper (lines 84-88) appends "✓" when `checkedResults` shows true:

```js
function labelFor(entry, checkedResults, disabledResults) {
  var marked = (entry.checked && checkedResults && checkedResults[entry.id]) ||
               isDisabled(disabledResults, entry);
  return marked ? entry.label + " ✓" : entry.label;
}

```

The check-mark is **textual** (Unicode U+2713), not a separate icon or widget state.

## Complete Execution Example

Given the Firefox browser entry above, the generated guard script looks like:

```bash

# Prelude: cache expensive readers

__omarchy_read_2=$(omarchy-default-browser 2>/dev/null) || :

# Guard evaluation for checked state

if { [[ "$__omarchy_read_2" == "firefox" ]] ; } >/dev/null 2>&1; then
  echo setup.default.browser.firefox:c:1
else
  echo setup.default.browser.firefox:c:0
fi

```

The `substituteGuardReaders()` call replaces `$(omarchy-default-browser)` with the cached variable, eliminating redundant process spawns.

Parsed result stored in JavaScript:

```js
root.checkedResults = {
  "setup.default.browser.firefox": true   // "Firefox ✓" displayed
}

```

QML binding for the menu row:

```js
label: MenuModel.labelFor(entry, root.checkedResults, root.disabledResults)

```

## Performance and Caching Characteristics

| Aspect | Implementation |
|--------|---------------|
| **Evaluation timing** | Once per menu open, not per-frame |
| **Reader caching** | `substituteGuardReaders()` collapses duplicate `$()` calls |
| **Output parsing** | Line-oriented, delimiter-separated (`:`) |
| **UI update** | Reactive binding to `root.checkedResults` |

This design keeps menu opening latency low even with dozens of `checked` conditions.

## Key Source Files

| File | Responsibility |
|------|--------------|
| `default/omarchy/omarchy-menu.jsonc` | JSONC menu definitions with `checked:` expressions |
| [`shell/plugins/menu/MenuModel.js`](https://github.com/omacom/omarchy/blob/main/shell/plugins/menu/MenuModel.js) | Guard collection, script generation, result parsing, `labelFor()` |
| `shell/plugins/menu/Menu.qml` | QML container consuming `checkedResults` for rendering |

## Summary

- **`checked:`** contains Bash expressions evaluated at menu-open time
- **[`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js)** batches all guards into one script execution
- **`guardLine()`** generates tagged output (`:c:1` or `:c:0`)
- **`checkedResults`** map stores Boolean outcomes by entry id
- **`labelFor()`** appends "✓" based on `checkedResults[entry.id]`
- The pipeline is **single-batch, cached-reader, reactive-bound** for performance

## Frequently Asked Questions

### What happens if a `checked` expression fails or returns non-zero?

The `guardLine` wrapper redirects stderr to `/dev/null` and treats non-zero exit as false (`:0`). The menu entry simply appears unchecked; no error propagates to the UI.

### Can `checked` expressions reference environment variables or functions?

Yes. The guard script runs with full shell context, so exported variables, functions from `~/.bashrc`, and Omarchy's own shell library are all available.

### Why use textual "✓" instead of a QML `checked` property?

The Omarchy menu uses a unified list widget where styling (icons, labels, shortcuts) is controlled through `labelFor()`. Embedding the check-mark in the label string keeps the rendering pipeline simple and consistent across entry types.

### How do I debug a `checked` expression that behaves unexpectedly?

Run the generated guard script manually. Extract it from [`MenuModel.js`](https://github.com/omacom/omarchy/blob/main/MenuModel.js) logging or temporarily add `set -x` to see actual values. The cached reader variables (like `__omarchy_read_2`) are visible in the generated output.