Skip to content

Commit c006980

Browse files
authored
Replace the demo with an SVG animation and cut the SketchyBar docs (#3)
* Replace the demo GIFs with an SVG animation A single looping SMIL animation shows the hijack side by side: without MicGuard the input stays on AirPods, with MicGuard it snaps back to the preferred mic. One small vector file replaces the GIF/MP4 media and renders in both the README and the docs site. * Remove the SketchyBar integration docs The step-by-step SketchyBar walkthrough drowned out the actual integration surface. The integrations page now documents just the building blocks (notifications, ping-on-start, CLI commands, health check); building a specific status-bar plugin is left to the reader. * Drop the screenshots section The animated demo covers what the static screenshots showed; the menubar and settings UI are simple enough to not need a gallery. --------- Co-authored-by: Przemysław Szypowicz <2733699+pszypowicz@users.noreply.github.com>
1 parent 6e768cb commit c006980

14 files changed

Lines changed: 236 additions & 451 deletions

README.md

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,18 @@ On first launch the current input device becomes your preferred mic. You can cha
3232

3333
### Features
3434

35-
- **Menubar daemon** — runs silently in the background with a shield+mic icon
36-
- **Auto-revert** — reverts unwanted input device switches caused by Bluetooth connections
37-
- **Mute / volume control** — toggle mute and set input volume via CLI
38-
- **CLI tool**`mic-guard` binary for scripting (`list`, `set`, `enable`, `toggle`, `mute`, `volume`, etc.)
39-
- **SketchyBar integration** — reference plugin with shield + mic items, device picker popup, and mute on click
40-
- **Distributed notifications** — real-time status broadcasts for custom integrations
35+
- **Menubar daemon** - runs silently in the background with a shield+mic icon
36+
- **Auto-revert** - reverts unwanted input device switches caused by Bluetooth connections
37+
- **Mute / volume control** - toggle mute and set input volume via CLI
38+
- **CLI tool** - `mic-guard` binary for scripting (`list`, `set`, `enable`, `toggle`, `mute`, `volume`, etc.)
39+
- **Distributed notifications** - real-time status broadcasts for custom integrations
4140

4241
## Demo
4342

4443
AirPods connecting hijacks your input device. MicGuard reverts it instantly.
4544

4645
<p align="center">
47-
<img src="docs/images/demo-micguard-disabled.gif" width="380" alt="MicGuard disabled: input device gets hijacked">
48-
&nbsp;&nbsp;
49-
<img src="docs/images/demo-micguard-enabled.gif" width="380" alt="MicGuard enabled: input device is preserved">
50-
</p>
51-
52-
## Screenshots
53-
54-
<p align="center">
55-
<img src="docs/images/menubar.png" width="240" alt="Menubar popup">
56-
&nbsp;&nbsp;
57-
<img src="docs/images/settings.png" width="360" alt="Settings view">
58-
&nbsp;&nbsp;
59-
<img src="docs/images/sketchybar.png" width="240" alt="SketchyBar device picker">
46+
<img src="docs/images/how-it-works.svg" width="830" alt="Side-by-side animation: without MicGuard the input stays hijacked by AirPods; with MicGuard it snaps back to the preferred microphone">
6047
</p>
6148

6249
## Modes
@@ -73,7 +60,7 @@ Always reverts to your chosen preferred device, no matter when or why the switch
7360

7461
## Documentation
7562

76-
See the full docs at **[pszypowicz.github.io/MicGuard](https://pszypowicz.github.io/MicGuard/)** covering [CLI reference](https://pszypowicz.github.io/MicGuard/cli.html), [debugging](https://pszypowicz.github.io/MicGuard/debugging.html), [integrations](https://pszypowicz.github.io/MicGuard/integrations.html), [notifications](https://pszypowicz.github.io/MicGuard/notifications.html), and [releasing](https://pszypowicz.github.io/MicGuard/releasing.html).
63+
See the full docs at **[pszypowicz.github.io/MicGuard](https://pszypowicz.github.io/MicGuard/)** - covering [CLI reference](https://pszypowicz.github.io/MicGuard/cli.html), [debugging](https://pszypowicz.github.io/MicGuard/debugging.html), [integrations](https://pszypowicz.github.io/MicGuard/integrations.html), [notifications](https://pszypowicz.github.io/MicGuard/notifications.html), and [releasing](https://pszypowicz.github.io/MicGuard/releasing.html).
7764

7865
## License
7966

docs/cli.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@ title: CLI Reference
66

77
MicGuard doubles as a CLI tool. The `mic-guard` binary is symlinked to `/usr/local/bin` on install.
88

9-
Commands perform direct work CoreAudio calls for volume/mute, config file writes for set/enable/disable/toggle and then post a `requestStatus` distributed notification so the daemon re-reads state and broadcasts `statusChanged`. The daemon is not required for the commands themselves to take effect, but without it no `statusChanged` notification will be broadcast to external integrations.
9+
Commands perform direct work - CoreAudio calls for volume/mute, config file writes for set/enable/disable/toggle - and then post a `requestStatus` distributed notification so the daemon re-reads state and broadcasts `statusChanged`. The daemon is not required for the commands themselves to take effect, but without it no `statusChanged` notification will be broadcast to external integrations.
1010

1111
[Home](index.md) · [Debugging](debugging.md) · [Integrations](integrations.md) · [Notifications](notifications.md) · [Releasing](releasing.md)
1212

1313
## Exit codes
1414

15-
| Code | Meaning |
16-
|------|---------|
17-
| `0` | Success |
18-
| `1` | Error (invalid arguments, device not found, etc.) |
15+
| Code | Meaning |
16+
| ---- | ------------------------------------------------- |
17+
| `0` | Success |
18+
| `1` | Error (invalid arguments, device not found, etc.) |
1919

2020
## Global flags
2121

22-
| Flag | Description |
23-
|------|-------------|
22+
| Flag | Description |
23+
| --------------- | ---------------------------- |
2424
| `-q`, `--quiet` | Suppress confirmation output |
2525

2626
## Commands
@@ -58,13 +58,13 @@ $ mic-guard list --output json
5858
]
5959
```
6060

61-
| Field | Type | Description |
62-
|-------|------|-------------|
63-
| `name` | String | Device name |
64-
| `current` | Boolean | `true` if this is the active input device |
61+
| Field | Type | Description |
62+
| ----------- | ------- | ------------------------------------------------- |
63+
| `name` | String | Device name |
64+
| `current` | Boolean | `true` if this is the active input device |
6565
| `preferred` | Boolean | `true` if this is the configured preferred device |
66-
| `volume` | Integer | Input volume 0–100 |
67-
| `muted` | Boolean | Mute state |
66+
| `volume` | Integer | Input volume 0–100 |
67+
| `muted` | Boolean | Mute state |
6868

6969
### `mic-guard current`
7070

@@ -141,7 +141,7 @@ disabled
141141

142142
### `mic-guard ping`
143143

144-
Ask the running MicGuard daemon to re-broadcast its current status via a `com.pszypowicz.MicGuard.statusChanged` distributed notification. Useful for forcing external integrations (e.g. SketchyBar) to refresh.
144+
Ask the running MicGuard daemon to re-broadcast its current status via a `com.pszypowicz.MicGuard.statusChanged` distributed notification. Useful for forcing external integrations to refresh.
145145

146146
```bash
147147
$ mic-guard ping

docs/debugging.md

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ title: Debugging
44

55
# Debugging
66

7-
MicGuard uses Apple's [unified logging system](https://developer.apple.com/documentation/os/logging) (`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.
7+
MicGuard uses Apple's [unified logging system](https://developer.apple.com/documentation/os/logging) (`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.
88

99
[Home](index.md) · [CLI Reference](cli.md) · [Integrations](integrations.md) · [Notifications](notifications.md) · [Releasing](releasing.md)
1010

11-
1211
## Viewing logs
1312

1413
### Stream logs in real time
@@ -17,7 +16,7 @@ MicGuard uses Apple's [unified logging system](https://developer.apple.com/docum
1716
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
1817
```
1918

20-
This streams all MicGuard messages (debug, info, and error) as they happen similar to `journalctl -f`. Press `Ctrl-C` to stop.
19+
This streams all MicGuard messages (debug, info, and error) as they happen - similar to `journalctl -f`. Press `Ctrl-C` to stop.
2120

2221
To see only important messages (info and error), omit `--level debug`:
2322

@@ -46,17 +45,17 @@ You can also use the built-in Console app:
4645

4746
MicGuard uses three log levels:
4847

49-
| Level | Persistence | Used for |
50-
|-------|-------------|----------|
48+
| Level | Persistence | Used for |
49+
| ------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------- |
5150
| `debug` | Memory only, near-zero cost when not observed | Volume/mute changes, listener register/unregister, status notifications, "no action" decisions |
52-
| `info` | Memory, persisted on error | Startup, config changes, device preference changes, enforcement actions |
53-
| `error` | Always persisted to disk | Failed listener registration, failed device set, failed config writes |
51+
| `info` | Memory, persisted on error | Startup, config changes, device preference changes, enforcement actions |
52+
| `error` | Always persisted to disk | Failed listener registration, failed device set, failed config writes |
5453

5554
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.
5655

5756
## Duplicate CoreAudio callbacks
5857

59-
When a Bluetooth device connects or disconnects, CoreAudio fires `DEVICE_LIST_CHANGED` and `DEFAULT_INPUT_CHANGED` notifications multiple times typically two or three times per event. This is normal macOS behavior (CoreAudio notifies once per internal phase of the Bluetooth negotiation) and not a MicGuard bug.
58+
When a Bluetooth device connects or disconnects, CoreAudio fires `DEVICE_LIST_CHANGED` and `DEFAULT_INPUT_CHANGED` notifications multiple times - typically two or three times per event. This is normal macOS behavior (CoreAudio notifies once per internal phase of the Bluetooth negotiation) and not a MicGuard bug.
6059

6160
You will see duplicate log lines like:
6261

@@ -65,7 +64,7 @@ DEVICE_LIST_CHANGED: added=["AirPods Pro 3 (Przemek)"] removed=[]
6564
DEVICE_LIST_CHANGED: added=["AirPods Pro 3 (Przemek)"] removed=[]
6665
```
6766

68-
The handlers are idempotent the second call is harmless since the device was already added to the tracked set on the first call.
67+
The handlers are idempotent - the second call is harmless since the device was already added to the tracked set on the first call.
6968

7069
## Running from the terminal
7170

@@ -76,7 +75,7 @@ To run MicGuard directly from a terminal (useful during development):
7675
/Applications/MicGuard.app/Contents/MacOS/MicGuard
7776
```
7877

79-
MicGuard acquires an `fcntl` advisory lock on `~/.config/mic-guard/lock` at startup. If another instance is already running, the new process logs the existing PID and exits immediately. The lock is kernel-managed it is released automatically when the process exits, crashes, or is killed (including `SIGKILL`). The lock file itself persists on disk but does not block the next launch; only an active file descriptor holding the lock does.
78+
MicGuard acquires an `fcntl` advisory lock on `~/.config/mic-guard/lock` at startup. If another instance is already running, the new process logs the existing PID and exits immediately. The lock is kernel-managed - it is released automatically when the process exits, crashes, or is killed (including `SIGKILL`). The lock file itself persists on disk but does not block the next launch; only an active file descriptor holding the lock does.
8079

8180
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.
8281

@@ -93,6 +92,7 @@ make dev
9392
```
9493

9594
This:
95+
9696
1. Builds a release `.app` bundle (`scripts/bundle.sh`)
9797
2. Adds `ProgramArguments` to the embedded LaunchAgent plist (launchd needs the absolute path; `SMAppService` resolves it automatically but raw `launchctl` doesn't)
9898
3. Registers the LaunchAgent via `launchctl bootstrap`
@@ -108,25 +108,25 @@ This kills the daemon and unregisters the LaunchAgent from launchd.
108108

109109
### Why not Xcode debug?
110110

111-
When Xcode launches MicGuard directly, the binary runs outside of launchd's context no LaunchAgent plist is loaded, so the Mach service isn't advertised. To test the daemon UI (menu bar, settings, CoreAudio listeners), Xcode debug works fine. To test XPC communication, use `make dev`.
111+
When Xcode launches MicGuard directly, the binary runs outside of launchd's context - no LaunchAgent plist is loaded, so the Mach service isn't advertised. To test the daemon UI (menu bar, settings, CoreAudio listeners), Xcode debug works fine. To test XPC communication, use `make dev`.
112112

113113
## Example debugging session
114114

115-
Terminal tab 1 start streaming logs:
115+
Terminal tab 1 - start streaming logs:
116116

117117
```bash
118118
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
119119
```
120120

121-
Terminal tab 2 start the dev daemon:
121+
Terminal tab 2 - start the dev daemon:
122122

123123
```bash
124124
make dev
125125
```
126126

127127
Tab 1 will show startup messages including device enforcement, volume changes, notification handling, and any errors as they occur.
128128

129-
Terminal tab 3 test CLI commands:
129+
Terminal tab 3 - test CLI commands:
130130

131131
```bash
132132
.build/bin/mic-guard list
@@ -152,22 +152,22 @@ If MicGuard cannot find the preferred device (e.g. it was disconnected), it will
152152

153153
MicGuard auto-enables "Launch at Login" on first install via `SMAppService.mainApp`. If it's not starting at login:
154154

155-
1. Check **System Settings → General → Login Items** ensure MicGuard is listed and enabled
155+
1. Check **System Settings → General → Login Items** - ensure MicGuard is listed and enabled
156156
2. Try removing and re-adding: toggle "Launch at Login" off in MicGuard Settings, then back on
157-
3. If MicGuard doesn't appear in the list, launch it manually the login item will be registered automatically on the next daemon start
157+
3. If MicGuard doesn't appear in the list, launch it manually - the login item will be registered automatically on the next daemon start
158158

159159
### Mute not working
160160

161-
If clicking mute in sketchybar (or running `mic-guard mute`) doesn't silence the mic:
161+
If running `mic-guard mute` doesn't silence the mic:
162162

163163
1. Check MicGuard is running: `pgrep -x MicGuard`
164164
2. Stream logs and trigger mute to trace the full flow:
165165

166166
```bash
167-
# Tab 1 stream logs
167+
# Tab 1 - stream logs
168168
log stream --predicate 'subsystem == "com.pszypowicz.MicGuard"' --level debug
169169

170-
# Tab 2 trigger mute
170+
# Tab 2 - trigger mute
171171
mic-guard mute
172172
```
173173

@@ -188,4 +188,3 @@ rm -rf ~/.config/mic-guard
188188
```
189189

190190
Then relaunch MicGuard. It will re-create the config directory and initialize with the current input device as the preferred mic.
191-
-123 KB
Binary file not shown.
-46.2 KB
Binary file not shown.
-65.7 KB
Binary file not shown.
-35.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)