How to Debug the FluidVoice Application: A Complete Guide for macOS Developers
Enable debug logs via Settings or the command line, instrument key subsystems like AppDelegate and TranscriptionProvider with DebugLogger.shared calls, and monitor real-time output through the menu bar Debug Log panel to isolate audio, transcription, or AI processing failures.
FluidVoice is a macOS-only SwiftUI application that orchestrates complex subsystems including audio capture, speech transcription, AI post-processing, and global hotkey management. Learning how to debug FluidVoice application issues effectively requires understanding its centralized logging infrastructure and the specific entry points where failures typically occur.
Understanding FluidVoice Architecture
Before placing breakpoints, identify which subsystem is failing. FluidVoice separates concerns into distinct services that communicate through shared state objects and a centralized DebugLogger.
Application Lifecycle Entry Points
The application bootstrap sequence begins in Sources/Fluid/AppDelegate.swift. The applicationDidFinishLaunching method initializes the updateCheckTimer, configures permissions, and calls openMainWindowOnLaunch.
If the UI fails to appear, verify that MenuBarManager and AppServices are correctly injected in Sources/Fluid/fluidApp.swift. The FluidApp struct declares the top-level @main entry point and provides shared objects to the view hierarchy using @StateObject.
Logging Infrastructure
The DebugLogger class in Sources/Fluid/Services/DebugLogger.swift provides a thread-safe, in-app log collector with a file backup. It supports four levels: info, warning, error, and debug.
Enable the UI debug panel via Settings → Enable Debug Logs or programmatically:
defaults write com.altic.FluidVoice EnableDebugLogs -bool true
Once enabled, the log UI appears in the menu bar (🪵 Debug Log), displaying the last 1,000 entries with filtering capabilities.
Enabling Debug Logging
Start every debugging session by activating the log stream. This captures subsystem initialization order and reveals permission or loading failures that occur before the UI renders.
Run this in Terminal before launching the app:
defaults write com.altic.FluidVoice EnableDebugLogs -bool true
Alternatively, enable programmatically:
import Fluid
func enableDebugLogging() {
DebugLogger.shared.info("Enabling debug logging")
UserDefaults.standard.set(true, forKey: "EnableDebugLogs")
DebugLogger.shared.refreshLoggingEnabled()
}
After launching, open the Debug Log panel from the menu bar to watch live entries. Look for [ERROR] tags indicating model loading failures or audio permission denials.
Debugging Specific Subsystems
Launch and Window Issues
If FluidVoice launches but shows no window, place breakpoints in AppDelegate.applicationDidFinishLaunching and check the openMainWindowOnLaunch boolean.
Insert temporary log statements to confirm execution order:
DebugLogger.shared.info("Reached post-launch window check")
Verify that DebugLogger.shared is initialized before other services to capture early failures.
Audio Capture Problems
Audio issues manifest as silent transcripts or "microphone not available" errors. The TranscriptionProvider in Sources/Fluid/Services/TranscriptionProvider.swift manages audio buffers and forwards them to concrete implementations like ParakeetRealtimeProvider.swift.
Insert debug logging inside the audio pipeline:
// Inside TranscriptionProvider.processAudio(buffer:)
DebugLogger.shared.debug("Processing buffer of size \(buffer.count)", source: "TranscriptionProvider")
Check for Mic permission granted entries in the logs. If missing, verify macOS microphone permissions in System Settings.
Transcription and AI Failures
When transcription works but output is malformed or missing, inspect the AI post-processing layer. DictationPostProcessingService sends raw transcripts to local or remote LLMs for cleanup.
Add a breakpoint on renderDictationUserMessage in Sources/Fluid/Persistence/SettingsStore.swift to inspect the exact prompt sent to the model. Verify model files exist at ~/Library/Application Support/FluidVoice/Models if using local inference.
Settings and Hotkey Malfunctions
Settings-related bugs usually stem from stale UserDefaults values. The SettingsStore in Sources/Fluid/Persistence/SettingsStore.swift persists preferences, hotkey slots, and AI prompt profiles.
If hotkeys fail to register, check GlobalHotkeyManager in Sources/Fluid/Services/GlobalHotkeyManager.swift. Ensure the app has accessibility permissions (AXIsProcessTrusted()) and that the hotkey is registered:
import Fluid
func verifyHotkey() {
let manager = GlobalHotkeyManager.shared
DebugLogger.shared.info("Hotkey is registered: \(manager.isHotkeyRegistered())")
}
For corrupted settings, delete specific keys from ~/Library/Preferences/com.altic.FluidVoice.plist or call SettingsStore.shared.refreshLoggingEnabled() after making changes.
Practical Debugging Workflow
Follow this systematic approach to isolate issues:
- Enable logging using the command line or Settings panel.
- Reproduce the issue while watching the live log for
[ERROR]or[DEBUG]entries. - Add targeted log statements using
DebugLogger.shared.info()orDebugLogger.shared.debug()in suspicious methods. - Run from Xcode (
⌘R) and place breakpoints inAppDelegate.applicationDidFinishLaunching,ContentView.onAppear, or providerstart()methods. - Inspect UserDefaults by dumping all keys when settings appear incorrect:
for (key, value) in UserDefaults.standard.dictionaryRepresentation() {
print("\(key) = \(value)")
}
- Check file logs at
~/Library/Logs/FluidVoice.logfor crashes occurring before UI initialization. - Export logs for bug reports using the Debug menu or programmatically:
let logText = DebugLogger.shared.exportLogs()
try? logText.write(to: URL(fileURLWithPath: "/tmp/FluidVoiceDebug.log"), atomically: true, encoding: .utf8)
- Verify update checks by looking for
SimpleUpdaterlog entries (🔎 Manual update check …) if the update dialog fails to appear.
Summary
- Activate debug logging immediately via
defaults writeor the Settings panel to capture subsystem initialization. - Monitor audio flow by instrumenting
TranscriptionProviderwithDebugLogger.shared.debug()calls to verify buffer sizes. - Inspect AI prompts by setting breakpoints on
renderDictationUserMessageinSettingsStore.swift. - Validate hotkeys through
GlobalHotkeyManagerand confirm accessibility permissions. - Export logs from the Debug menu or programmatically using
DebugLogger.shared.exportLogs()for external analysis.
Frequently Asked Questions
How do I enable debug logging if FluidVoice crashes on launch?
Use the command line before launching: defaults write com.altic.FluidVoice EnableDebugLogs -bool true. Then check the file log at ~/Library/Logs/FluidVoice.log using Console.app or Terminal, as the in-app UI may not be accessible if the crash occurs during initialization.
Why is my transcription provider showing "Failed to load model" errors?
Verify the model files exist in ~/Library/Application Support/FluidVoice/Models. Add DebugLogger.shared.debug() calls inside TranscriptionProvider to confirm the exact path being accessed, and check that the model format matches what the concrete provider expects (e.g., Parakeet vs. Whisper).
How can I see the exact prompt sent to the AI post-processing service?
Set a breakpoint on renderDictationUserMessage in Sources/Fluid/Persistence/SettingsStore.swift. This method constructs the prompt immediately before sending it to DictationPostProcessingService, allowing you to inspect the string content in the Xcode Debug console using po variableName.
What should I check if the global hotkey stops working?
First, verify accessibility permissions are granted using AXIsProcessTrusted(). Then check GlobalHotkeyManager registration status by calling GlobalHotkeyManager.shared.isHotkeyRegistered() and logging the result. Finally, inspect UserDefaults for corrupted hotkey bindings using the dictionary dump method described in the debugging workflow.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →