Skip to content

feat: AI feature toggles in menubar dropdown - #34

Open
mattthewong wants to merge 5 commits into
mainfrom
moonshots/vox-2.0/mattthewong/menubar-ai-toggles
Open

feat: AI feature toggles in menubar dropdown#34
mattthewong wants to merge 5 commits into
mainfrom
moonshots/vox-2.0/mattthewong/menubar-ai-toggles

Conversation

@mattthewong

Copy link
Copy Markdown
Owner

Summary

  • Add 4 checkbox menu items under "AI Features" section in the menubar
  • AI post-processing -- toggle Claude grammar cleanup
  • Prompt mode -- toggle "summarize my clipboard" etc.
  • Voice commands -- toggle "create PR", "git status" etc.
  • Context-aware formatting -- toggle app-specific output
  • Follows exact same pattern as existing Play sounds / Auto-paste toggles
  • Each sends a bool on a Go channel for the settings watcher to consume

Menubar Layout (after this PR)

Status: Idle
---
Pause Vox
---
Hotkey: Option+Space
Change Hotkey       >
Mode                >
---
Play sounds         [x]
Auto-paste          [x]
---
AI Features
AI post-processing  [ ]
Prompt mode         [ ]
Voice commands      [ ]
Context-aware       [ ]
---
Show Log...
---
Quit Vox

Moonshot

Part of Moonshots XXIII: Vox 2.0 -- P2: AI Feature Toggles in Menubar

Note: AI-generated via Claude Code. Review the Obj-C menu item lifecycle and Go channel wiring.

Test plan

  • make build + make lint + make test-short all pass
  • Manual: make start, verify AI Features section appears in menubar dropdown
  • Manual: Toggle each checkbox, verify state persists across menu open/close

🤖 Generated with Claude Code

@mattthewong
mattthewong requested a review from alohaninja May 13, 2026 17:34
mattthewong and others added 2 commits May 13, 2026 10:34
Add four checkbox menu items under an "AI Features" section in the
menubar: AI post-processing, Prompt mode, Voice commands, and
Context-aware formatting. Each toggle sends a bool on a Go channel
following the same pattern as Play sounds and Auto-paste.

Users can now enable/disable AI features at runtime from the menubar
without restarting vox or editing config files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The menubar AI feature checkboxes (AI post-processing, prompt mode,
voice commands, context-aware) were not connected to any consumer.
Clicks silently dropped after filling the buffer-1 channels, checkboxes
never visually toggled, and the toggles had no effect on runtime behavior.

Changes:
- Add AIPostProcess/PromptMode/VoiceCommands/ContextAware atomic.Bool
  fields to runtimeSettings
- Seed them from flagClient at startup and sync checkbox UI state
- Add 4 case arms in settingsWatcher: store atomic, update UI, persist
  to preferences.json via config.SavePref
- Update pipeline stages (classifyStage, postProcessStage,
  promptModeStage, commandStage) to read settings.* instead of
  flagClient.* so menubar toggles control behavior at runtime
- Add corresponding *bool fields to config.Prefs for persistence
- Fix aiHeader NSMenuItem alloc without autorelease
alohaninja
alohaninja previously approved these changes May 13, 2026

@alohaninja alohaninja left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

What we fixed

  • Dead channels / non-functional checkboxes — Added 4 case arms in settingsWatcher (cmd/vox/main.go) so the Go side actually drains aiPostProcessCh, promptModeCh, voiceCommandsCh, and contextAwareCh. Clicks now flow through to runtime settings and persist to preferences.json.
  • Checkboxes never visually toggled — Because settingsWatcher now calls ui.SetAIPostProcess(on) etc. on each toggle, the Obj-C round-trip completes and setState: fires. Checkboxes reflect the actual state.
  • No startup sync — Added ui.SetAIPostProcess(settings.AIPostProcess.Load()) etc. after ui.Init(), seeded from flagClient.*(). Checkboxes now show the correct initial state from LD flags / env vars / config.
  • No persistence — Added AIPostProcess, PromptMode, VoiceCommands, ContextAware *bool fields to config.Prefs. Each toggle persists via config.SavePref on click, survives restarts.
  • No runtime effect — Updated all 4 pipeline stages (classifyStage, postProcessStage, promptModeStage, commandStage) to read settings.* atomic bools instead of flagClient.*(). Menubar toggles now actually enable/disable AI features at runtime.
  • aiHeader memory nit — Added autorelease to the NSMenuItem alloc for the "AI Features" section header, matching the pattern used by showLogItem and quitItem.

What we didn't fix

  • send() drops events on rapid toggling — The existing send() helper uses a non-blocking default branch on buffer-1 channels. If the user clicks faster than settingsWatcher can process (e.g., disk I/O in SavePref), intermediate clicks are silently dropped. This is a pre-existing design decision shared by all toggles (sounds, auto-paste, etc.) — not introduced by this PR. The last-written value is always correct; only intermediate transitions are lost.
  • Repetitive boilerplate — 4 identical channel/setter/callback/handler patterns across Go and Obj-C. A table-driven or generic approach could reduce this but would be a refactor beyond this PR's scope.
  • No unit tests for internal/ui/ — The cgo/AppKit nature of this code makes it impractical to unit test without mocking the Cocoa runtime. Pre-existing gap, not worsened by this PR.

Merge main into menubar-ai-toggles branch. Conflicts in prefs.go
(Model field from #37) and ui_darwin.go (modelCh from #37) resolved
by keeping both sides: our AI toggle fields/channels plus main's
model picker additions.
alohaninja and others added 2 commits May 14, 2026 17:32
Merge main into menubar-ai-toggles branch. Conflicts in ui_darwin.go
(deleteModelCh from #39) and ui_darwin.m (modelRemoveClicked delegate
from #39) resolved by keeping both sides: our AI toggle channels/handlers
plus main's model cleanup additions.
…tthewong/menubar-ai-toggles

* origin/main:
  docs: align README with go auto-install
  fix: check for go in setup and install via Homebrew if missing
  readme: refresh with icon, pipeline flow diagram, and badges
  fix: prevent multiple vox instances with file lock
  fix: address review feedback — trigger lowercasing, per-token validation, duplicate detection
  feat: show command name and status in menubar Last: row
  fix(classify): treat punctuation as word boundary for Whisper transcription
  docs: add commands.yaml.example for user-configurable voice commands
  refactor(classify): remove deprecated package-level Classify function
  feat: wire user-configurable commands into pipeline
  feat(commandconfig): add ToCommand conversion and Merge logic
  feat(commandconfig): add YAML loading and validation for user-defined commands
  refactor(classify): add Classifier struct with configurable command prefixes
  refactor(classify): export PrefixEntry type and DefaultCommandPrefixes()

# Conflicts:
#	cmd/vox/main.go
@mattthewong
mattthewong requested a review from alohaninja August 21, 2026 19:11
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