2025-12-09 17:51:05 +00:00
---
summary: "Menu bar status logic and what is surfaced to users"
read_when:
- Tweaking mac menu UI or status logic
2026-01-31 16:04:03 -05:00
title: "Menu Bar"
2025-12-09 17:51:05 +00:00
---
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
# Menu Bar Status Logic
## What is shown
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- We surface the current agent work state in the menu bar icon and in the first status row of the menu.
- Health status is hidden while work is active; it returns when all sessions are idle.
2026-01-22 23:07:58 +00:00
- The “Nodes” block in the menu lists **devices** only (paired nodes via `node.list` ), not client/presence entries.
2026-01-07 11:42:41 +01:00
- A “Usage” section appears under Context when provider usage snapshots are available.
2025-12-09 01:28:16 +01:00
## State model
2026-01-31 21:13:13 +09:00
2026-01-04 02:10:22 +01:00
- Sessions: events arrive with `runId` (per-run) plus `sessionKey` in the payload. The “main” session is the key `main` ; if absent, we fall back to the most recently updated session.
2025-12-09 01:28:16 +01:00
- Priority: main always wins. If main is active, its state is shown immediately. If main is idle, the most recently active non‑ main session is shown. We do not flip‑ flop mid‑ activity; we only switch 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 `toolName` and `meta/args` .
## IconState enum (Swift)
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- `idle`
- `workingMain(ActivityKind)`
- `workingOther(ActivityKind)`
- `overridden(ActivityKind)` (debug override)
### ActivityKind → glyph
2026-01-31 21:13:13 +09:00
2026-01-12 02:49:55 +00:00
- `exec` → 💻
2025-12-09 01:28:16 +01:00
- `read` → 📄
- `write` → ✍️
- `edit` → 📝
- `attach` → 📎
- default → 🛠️
### Visual mapping
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- `idle` : normal critter.
- `workingMain` : badge with glyph, full tint, leg “working” animation.
- `workingOther` : badge with glyph, muted tint, no scurry.
- `overridden` : uses the chosen glyph/tint regardless of activity.
## Status row text (menu)
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- While work is active: `<Session role> · <activity label>`
2026-01-30 03:15:10 +01:00
- Examples: `Main · exec: pnpm test` , `Other · read: apps/macos/Sources/OpenClaw/AppState.swift` .
2025-12-09 01:28:16 +01:00
- When idle: falls back to the health summary.
## Event ingestion
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- Source: control‑ channel `agent` events (`ControlChannel.handleAgentEvent` ).
- Parsed fields:
- `stream: "job"` with `data.state` for start/stop.
- `stream: "tool"` with `data.phase` , `name` , optional `meta` /`args` .
- Labels:
2026-01-12 02:49:55 +00:00
- `exec` : first line of `args.command` .
2025-12-09 01:28:16 +01:00
- `read` /`write` : shortened path.
- `edit` : path plus inferred change kind from `meta` /diff counts.
- fallback: tool name.
## Debug override
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- Settings ▸ Debug ▸ “Icon override” picker:
- `System (auto)` (default)
- `Working: main` (per tool kind)
- `Working: other` (per tool kind)
- `Idle`
- Stored via `@AppStorage("iconOverride")` ; mapped to `IconState.overridden` .
## Testing checklist
2026-01-31 21:13:13 +09:00
2025-12-09 01:28:16 +01:00
- Trigger main session job: verify icon switches immediately and status row shows main label.
- Trigger non‑ main session job while main idle: icon/status shows non‑ main; stays stable until it finishes.
- Start main while other active: icon flips to main instantly.
- Rapid tool bursts: ensure badge does not flicker (TTL grace on tool results).
- Health row reappears once all sessions idle.