Status: ratified — task 1 (shell + menu bar + About) shipped 2026-04-26 via SwiftPM target rather than .xcodeproj (see implementation note below)
Owner: apps/OpenQuack/
Last updated: 2026-04-26
The minimum viable Xcode app target: a menu-bar app that owns the dictation lifecycle, consumes OpenQuackKit, and survives long-running sessions without leaks. Boots into a sane idle state on first launch.
apps/OpenQuack/OpenQuack.xcodeproj — hand-written; consumes the local SPM package via “Add Local Package”.apps/OpenQuack/Sources/App/OpenQuackApp.swift — @main, sets up AppDelegate.apps/OpenQuack/Sources/App/AppDelegate.swift — NSApplicationDelegate, owns the StatusItemController, wires HotkeyManager, AudioRecorder, Transcriber, AgentRouter, OverlayController together.Info.plist:
LSUIElement = YES (no Dock icon, just menu bar)NSMicrophoneUsageDescription = “OpenQuack transcribes your voice locally to dispatch commands to your AI agent.”NSAppleEventsUsageDescription (if we end up using AppleScript anywhere)com.apple.security.device.audio-inputstart recording → overlay.recording → audio.start
⋮
stop hotkey → audio.stop → overlay.transcribing → transcribe → overlay.dispatching → agent.dispatch → result
↓
PasteService.paste
↓
overlay.done → fade
cancelled overlay state.xcodebuild -project … build green in CI on macos-15 runner.Settled the Xcode-project question by going SwiftPM-only for the app target:
Sources/OpenQuackApp/ is a SwiftPM .executable target consuming OpenQuackKit.MenuBarExtra + AppDelegate.applicationDidFinishLaunching → NSApp.setActivationPolicy(.accessory) gives us a Dock-less menu-bar app.scripts/wrap_app.sh builds a release binary and assembles a minimal .app bundle (Info.plist with LSUIElement=YES + NSMicrophoneUsageDescription, ad-hoc codesigned). Output at build/OpenQuack.app..xcodeproj if/when a feature needs Xcode-specific tooling (Asset Catalog editor, storyboards, signing UI). None do today.Trade-off accepted: no SwiftUI Previews from the SwiftPM target (the #Preview macro requires the Xcode plugin). That’s a per-developer ergonomic loss; for the menu-bar surface, we use the running app to iterate.
LSUIElement menu-bar pattern.Sources/OpenQuackKit/ — the brain we wrap.