Prevents Bluetooth audio devices from hijacking the default macOS microphone
MicGuard uses Apple’s unified logging system (os.Logger) with subsystem com.pszypowicz.MicGuard. This is the macOS equivalent of journalctl on Linux — all log messages go to a centralized system log store that you can query, stream, and filter.
Home · CLI Reference · Integrations · Notifications · Releasing
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
This streams all MicGuard messages (debug, info, and error) as they happen — similar to journalctl -f. Press Ctrl-C to stop.
To see only important messages (info and error), omit --level debug:
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"'
log show --predicate 'subsystem == "com.pszypowicz.MicGuard"' --last 1h --info --debug
Replace 1h with any duration: 5m, 30m, 2h, 1d, etc. Without --debug, debug-level messages are excluded (they are kept in memory only briefly).
You can also use the built-in Console app:
/Applications/Utilities/)com.pszypowicz.MicGuardMicGuard uses three log levels:
| Level | Persistence | Used for |
|---|---|---|
debug |
Memory only, near-zero cost when not observed | Volume/mute changes, listener register/unregister, status notifications, “no action” decisions |
info |
Memory, persisted on error | Startup, config changes, device preference changes, enforcement actions |
error |
Always persisted to disk | Failed listener registration, failed device set, failed config writes |
Debug messages are only captured when a consumer is attached (e.g. log stream --level debug or Console.app with debug enabled). This means high-frequency events like volume slider changes have near-zero overhead during normal operation.
To run MicGuard directly from a terminal (useful during development):
# Run the built app bundle
/Applications/MicGuard.app/Contents/MacOS/MicGuard
# Or if built from source via Xcode, run from the build directory
~/Library/Developer/Xcode/DerivedData/MicGuard-*/Build/Products/Debug/MicGuard.app/Contents/MacOS/MicGuard
Note that MicGuard enforces single-instance via a lock file (~/.config/mic-guard/lock). If another instance is already running, the new one exits immediately. Quit the existing instance first (via the menubar menu or killall MicGuard).
Since MicGuard uses os.Logger instead of stderr, you won’t see log output directly in the terminal. Use log stream in a separate terminal tab to observe the logs.
Terminal tab 1 — start streaming logs:
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
Terminal tab 2 — launch MicGuard:
/Applications/MicGuard.app/Contents/MacOS/MicGuard
Tab 1 will show startup messages, device enforcement, volume changes, and any errors as they occur.
If you use fish shell, log is a built-in command. Use the full path instead:
/usr/bin/log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
/usr/bin/log show --predicate 'subsystem == "com.pszypowicz.MicGuard"' --last 1h --info --debug
If MicGuard cannot find the preferred device (e.g. it was disconnected), it will keep monitoring but won’t enforce a switch. When the preferred device reconnects, MicGuard will automatically switch back to it. You can change the preferred device via the menubar menu or mic-guard set.
MicGuard registers as a login item via SMAppService. If it’s not starting at login:
If clicking mute in sketchybar (or running mic-guard mute) doesn’t silence the mic:
pgrep -x MicGuard# Tab 1 — stream logs
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
# Tab 2 — trigger mute
mic-guard mute
You should see three log entries in sequence:
toggleMute: muted (saved volume 100)
Volume changed to 0%
Posting status notification: enabled=1 device=… volume=0 muted=1
To reset all MicGuard configuration to defaults:
rm -rf ~/.config/mic-guard
Then relaunch MicGuard. It will re-create the config directory and initialize with the current input device as the preferred mic.
MicGuard uses a lock file (~/.config/mic-guard/lock) to enforce single-instance. If MicGuard exits abnormally, the lock file is automatically cleaned up on the next launch — no manual removal is needed.