Skip to content

macOS: add menu-bar status item to the resident agent#24

Closed
m31-galaxy wants to merge 2 commits into
macosfrom
claude/macos-menu-bar-icon
Closed

macOS: add menu-bar status item to the resident agent#24
m31-galaxy wants to merge 2 commits into
macosfrom
claude/macos-menu-bar-icon

Conversation

@m31-galaxy

Copy link
Copy Markdown
Owner

Summary

Stacked on top of #23 (base branch: macos). Adds a menu-bar status item to the macOS resident background agent.

The resident agent runs as an accessory app (NSApplicationActivationPolicyAccessory, LSUIElement), so it has no Dock icon and previously offered no visible UI — casting was only possible via the global hot key or by relaunching the app. This adds a status item in the menu bar so the agent is discoverable and controllable.

Changes

  • pkg/cocoa/cocoa.m
    • New HexStatusController with cast: (funnels through the existing request_show path — same as the hot key and relaunch) and quit: ([NSApp terminate:]) actions.
    • New cocoa_setup_menu_bar(): creates an NSStatusItem with a template SF Symbol glyph (wand.and.stars, matching the spell-casting metaphor; falls back to a title if unavailable) and a menu with Cast Gesture and Quit Hexecute. Idempotent; runs on the main thread.
    • cocoa_destroy() removes the status item.
  • pkg/cocoa/cocoa.h — declares cocoa_setup_menu_bar.
  • pkg/cocoa/cocoa.goCocoaWindow.SetupMenuBar() wrapper (macOS-only; intentionally not part of the platform.Window interface).
  • cmd/hexecute/run_darwin.go — calls window.SetupMenuBar() from runMain after the hot key registers.

Notes

  • SF Symbols require macOS 11+, which matches LSMinimumSystemVersion (11.0) in Info.plist.
  • The menu works under the agent's manually-pumped event loop: status-item clicks are dispatched via [NSApp sendEvent:] in cocoa_wait_for_show, which then drives the menu's own tracking loop.
  • This was developed on a Linux host; the Cgo/Objective-C path is build-tagged darwin and could not be compiled locally. gofmt and the non-darwin go build ./... are clean. The macOS CI job (added in Add macOS support with native Cocoa overlay window #23) will compile and link it.

Verification (on macOS)

  1. Build the .app and launch the resident agent (hexecute --background).
  2. Confirm a wand glyph appears in the menu bar (right side).
  3. Click it → Cast Gesture shows the overlay (same as the hot key); draw a gesture and confirm it executes.
  4. Click it → Quit Hexecute exits the agent and the glyph disappears.
  5. Confirm the global hot key and relaunch-to-cast still work unchanged.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits June 25, 2026 15:26
The resident background agent runs as an accessory (no Dock icon), so it
had no visible affordance — casting was only possible via the global hot
key or relaunch. Add an NSStatusItem to the menu bar with a template
SF Symbol glyph (wand.and.stars) and a menu offering "Cast Gesture"
(funnels through the same request_show path as the hot key) and
"Quit Hexecute".

cocoa_setup_menu_bar is idempotent, runs on the main thread, and is wired
in from runMain after the hot key registers. The status item is removed
in cocoa_destroy. Exposed to Go via CocoaWindow.SetupMenuBar (macOS-only,
not part of the platform.Window interface).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjKPHZaHPxMhLXGe55hMeW
cgo compiles the Objective-C backend without ARC (manual reference
counting). statusItemWithLength: returns an autoreleased item and the
system status bar does not keep a reliable strong reference, so storing
it in a global inside an @autoreleasepool left it to be deallocated when
the pool drained — the menu-bar icon could fail to appear or vanish
immediately. Retain it on creation and release it in cocoa_destroy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LjKPHZaHPxMhLXGe55hMeW
@m31-galaxy m31-galaxy closed this Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants