---
summary: "Menu bar status logic and what is surfaced to users"
read_when:
  - Tweaking mac menu UI or status logic
title: "Menu bar"
---

**Open Dashboard** and Gateway window actions use the **Web** experience by
default. Enable **Native experience (Experimental)** under **Dashboard → Settings
→ This Mac → App** to use native chat windows. The preference applies to the menu
bar, Dock, main **Gateways** menu, and **File → New Gateway Window…** (Cmd-N).
Settings always opens the web Dashboard settings page. See
[WebChat](/platforms/mac/webchat) for switching behavior and native chat features.

## What is shown

- The menu bar icon and the first status row of the menu show the current agent work state.
- Health status is hidden while work is active. It returns once all sessions are idle.
- A root "Context" item opens a submenu with recent sessions instead of expanding them in the root menu.
- A "Devices" block in the root menu lists paired **devices** only (from `node.list`), not client/presence entries.
- A root "Usage" section appears below Context when provider usage snapshots are available, followed by cost details when available. Cost totals for **Today** and the daily chart use the Mac’s local time zone.
- When two or more Gateways are available, the first status row includes the primary Gateway name. A root "Gateways" section then lists every Gateway with its health and primary marker. Select a row to open or focus that Gateway in the chosen experience. Hold Option to reveal "Set as Primary…" for eligible saved Gateways.
- **Quick Chat** opens the floating main-session composer. Its current global shortcut appears beside the item.
- **Settings…** (Cmd-,) opens Dashboard settings. App and device preferences live under **This Mac**, voice controls under **Talk**, and app update preferences under **Updates**.
- **Connection…** opens the native Connection window. This is a standard macOS settings window with **Connection** and **Gateways** toolbar tabs. **Debug** also appears while the developer toggle is enabled. The window remains available when the Gateway is unreachable.
- **About OpenClaw** selects **About** in the native Connection window, with the app version, build information, resource links, and **Copy Build Info**. It works without a Gateway connection.

The app's main **Gateways** menu is always present. It lists the primary Gateway, when configured, followed by **This Mac** when it also hosts a local Gateway, then saved Gateways, with Command-1 through Command-9 assigned in that order. Each card shows health, version and shortened build ID, endpoint, latency, and the number of open windows in the selected experience when available. Browser-authenticated profiles also show **Access** and their session expiry. A **Primary** badge identifies the primary Gateway. A front-window marker follows the selected experience's frontmost Gateway window. Selecting a card opens that Gateway in the chosen experience or brings its existing window to the front. Hold Option to reveal **New … Window**, or press Option-Command with the same digit. Both open another independent window for that Gateway. **Manage Gateways…** opens **Connection → Gateways** and remains available when no Gateways are configured.

Right-click the OpenClaw Dock icon for **Open Dashboard** and **Settings…**. When more than one Gateway is configured, the Dock menu also lists every Gateway from the same catalog, including the primary Gateway, **This Mac** when available, and saved profiles. Selecting one opens or focuses it in the chosen experience; a checkmark identifies that experience's frontmost Gateway window.

Gateway status dots follow each open Dashboard’s live connection, including saved Gateways that are not primary. Green means connected, red means a connection error, and gray means no current connection result. If multiple windows show the same Gateway, it stays green while any of them is connected. The checkmark identifies the selected window’s Gateway; **Primary** is a separate setting.

Gateway health checks run only while the main **Gateways** menu is open. Cards show cached facts while refreshing, or **checking…** before the first result. After a failure they show **unreachable** with the last successful contact time. Closing the menu cancels its checks and disconnects saved Gateways used for those checks with no open Web or Native windows. The primary connection stays connected, and cached facts remain available until the app quits.

The Devices and Automations summaries refresh while the menu is open. Closing it stops their menu-owned polling. Cached summaries remain available when reopening the same Primary Gateway. Changing Primary refreshes Devices, Automations, Usage, and cost details from the newly selected Gateway. Manage jobs in the Dashboard's **Cron Jobs** page.

The Automations summary shows the full enabled-job count and previews up to eight jobs, ordered by next run.

Manual Cron refreshes and successful job changes supersede older reads. An in-flight response therefore cannot restore a deleted job to the list.

## State model

- Source: `WorkActivityStore` (`apps/macos/Sources/OpenClaw/WorkActivityStore.swift`).
- Events arrive as `ControlAgentEvent` with a `runId`. The handler (`ControlChannel.routeWorkActivity`) reads `sessionKey` from the event payload and defaults to `"main"` if absent.
- Priority: the main session (`sessionKey == "main"` by default) always wins. If main is active, its state shows immediately. If main is idle, the most recently active non-main session shows instead. The store does not flip mid-activity. It only switches when the current session goes idle or main becomes active.
- Activity kinds:
  - `job`: high-level command execution (`state: started|streaming|done|error|...`).
  - `tool`: `phase: start|result` with `name`, optional `meta`/`args`.

## IconState enum (Swift)

- `idle`
- `workingMain(ActivityKind)`
- `workingOther(ActivityKind)`
- `overridden(ActivityKind)` (debug override)

### ActivityKind -> badge symbol

`ActivityKind` wraps a `ToolKind` (`bash`, `read`, `write`, `edit`, `attach`, `other`) or a bare `job`. Each maps to an SF Symbol badge drawn over the critter icon (`IconState.badgeSymbolName`):

| Kind            | Symbol                             |
| --------------- | ---------------------------------- |
| `bash`          | `chevron.left.slash.chevron.right` |
| `read`          | `doc`                              |
| `write`         | `pencil`                           |
| `edit`          | `pencil.tip`                       |
| `attach`        | `paperclip`                        |
| `other` / `job` | `gearshape.fill`                   |

### Visual mapping

- `idle`: normal critter, no badge.
- `workingMain`: badge with symbol, full tint (`.primary` prominence), leg "working" animation.
- `workingOther`: badge with symbol, muted tint (`.secondary` prominence), no scurry.
- `overridden`: uses the chosen symbol/tint regardless of real activity.

## Context submenu

- The root menu shows one "Context" row with a session count/status. That row opens a submenu (`MenuSessionsInjector`).
- The submenu header shows the active session count for the last 24 hours.
- Each session row keeps its token bar, age, preview, thinking/verbose toggle, reset, compact, and delete actions.
- Loading, disconnected, and session-load error messages render inside the Context submenu.
- Usage and cost sections stay root-level below Context so they remain glanceable without opening the submenu.

## Status row text (menu)

- With two or more Gateways, the connection label appends the primary Gateway's catalog display name, such as `OpenClaw Active — Mac Studio`.
- While work is active: `<Session role> · <activity label>` (`"\(roleLabel) · \(activity.label)"` in `MenuContentView`), where role label is `Main` or `Other`.
- When idle: falls back to the health summary.

## Event ingestion

- Source: control-channel `agent` events, routed by `ControlChannel.routeWorkActivity(from:)`.
- Parsed fields:
  - `stream: "job"` with `data.state` for start/stop.
  - `stream: "tool"` with `data.phase`, `data.name`, optional `data.meta`/`data.args`.
- Tool labels come from `ToolDisplayRegistry.resolve(name:args:meta:)`. Unresolved names fall back to the raw tool name.

## Debug override

- Enable the developer toggle in **Dashboard → Settings → This Mac → Developer**. Then open **Connection… → Debug → Icon override**:
  - `System (auto)` (default)
  - `Working: main` / `Working: other` (per tool kind: bash, read, write, edit, other)
  - `Idle`
- Stored under `UserDefaults` key `openclaw.iconOverride`, and mapped to `IconState.overridden`.

## Testing checklist

- Trigger main session job: icon switches immediately and status row shows the main label.
- Trigger non-main session job while main is idle: icon/status shows the non-main session and stays stable until it finishes.
- Start main while another session is active: icon flips to main instantly.
- Rapid tool bursts: badge does not flicker (2s grace window before clearing a finished tool, `WorkActivityStore.toolResultGrace`).
- Health row reappears once all sessions are idle.

## Related

- [macOS app](/platforms/macos)
- [Menu bar icon](/platforms/mac/icon)
- [Usage tracking](/concepts/usage-tracking)
