A Hammerspoon Spoon that automatically switches audio devices based on a priority list. When devices are connected or disconnected, it selects the highest-priority available device for both input and output.
Repository: https://github.com/hugoh/AudioPilot.spoon
- Automatically selects the best available audio device based on your priority list
- Separate priority lists for output (speakers/headphones) and input (microphones)
- Detects when macOS auto-switches to a priority device on connect and sends a notification
- Tracks all devices you have ever connected for easy priority management
- Pre-discovers paired Bluetooth devices (even while disconnected) via a background scan at startup
- Shows a 🔊 menu bar icon with current device status and priority lists
- Sends a system notification whenever a device switch occurs; rapid changes are coalesced into one
- Config file is human-editable JSON, with menu items to edit priorities visually or open the raw file
If you're looking for other solutions in this space, consider:
- AudioSwitcher - Native macOS app
- Ears - Lightweight audio device switcher
AudioPilot aims to provide a Hammerspoon-powered, priority-driven, fully configurable option.
Ensure you have Hammerspoon installed, then choose a method:
- Download
AudioPilot.spoon.zipfrom the latest release - Unzip — this produces an
AudioPilot.spoonfolder - Move it to
~/.hammerspoon/Spoons/ - Reload Hammerspoon (menu bar icon → Reload Config, or run
hs.reload()in the console)
spoon.SpoonInstall:installSpoonFromZip(
"https://github.com/hugoh/AudioPilot.spoon/releases/latest/download/AudioPilot.spoon.zip"
)cd ~/.hammerspoon/Spoons
git clone https://github.com/hugoh/AudioPilot.spoon.gitAdd the following to your ~/.hammerspoon/init.lua:
hs.loadSpoon("AudioPilot")
spoon.AudioPilot:start()On first launch, a default config file is created at ~/.config/AudioPilot/config.json. The config is keyed by CoreAudio device UIDs (opaque strings assigned by macOS) rather than by name, so the priority lists are best managed through the Edit Priorities... menu item rather than edited by hand.
A typical config looks like this:
{
"outputPriority": ["5C-52-30-DB-6E-80:output", "AppleHAD:1:0"],
"inputPriority": ["5C-52-30-DB-6E-80:input", "AppleHAD:1:1"],
"knownDevices": {
"output": [
{ "uid": "5C-52-30-DB-6E-80:output", "name": "AirPods Pro" },
{ "uid": "AppleHAD:1:0", "name": "MacBook Pro Speakers" }
],
"input": [
{ "uid": "5C-52-30-DB-6E-80:input", "name": "AirPods Pro Microphone" },
{ "uid": "AppleHAD:1:1", "name": "Built-in Microphone" }
]
}
}outputPriority— ordered list of output device UIDs, most preferred firstinputPriority— ordered list of input device UIDs, most preferred firstknownDevices— all devices ever seen, stored as{uid, name}objects (auto-updated; used to show disconnected devices in the menu and editor)
To change the config file location:
spoon.AudioPilot.configPath = "/path/to/your/config.json"
spoon.AudioPilot:start()To change how long AudioPilot waits before emitting a coalesced notification (default 5 seconds):
spoon.AudioPilot.notifyDelay = 3
spoon.AudioPilot:start()Click the 🔊 icon to see:
- Current devices — the active output and input device
- Output Priority — your priority list with
*marking the active device and(disconnected)for unavailable ones - Input Priority — same for input
- Refresh — re-evaluates priorities and switches if needed
- Rescan Bluetooth Devices — re-runs the background Bluetooth scan to discover newly paired devices
- Edit Priorities... — opens a visual drag-and-drop editor to reorder device priorities and remove stale entries
- Edit Config File... — opens the raw JSON config file in your default editor
- On startup, AudioPilot loads your config, enforces your priorities immediately, and runs a background Bluetooth scan (
system_profiler SPBluetoothDataType) to pre-populateknownDeviceswith all paired audio devices — even ones that are not currently connected - Whenever a device is connected or disconnected, it walks the priority list and switches to the first available device
- If macOS auto-switches to a priority device before AudioPilot's watcher fires (common with Bluetooth headphones), AudioPilot detects this and sends a notification for the change
- Rapid connect/disconnect events within the coalesce window (
notifyDelay, default 5 s) are collapsed into a single notification showing the net change - Manual changes (via System Settings or another app) are respected until the next connect/disconnect event
- New devices are automatically added to
knownDevicesin the config so you can later add them to a priority list; the Edit Priorities... editor lets you remove stale entries you no longer need
This Spoon does not require Accessibility API access. It uses Hammerspoon's built-in hs.audiodevice API, which may require allowing Hammerspoon in System Settings → Privacy & Security → Microphone (for input device control).
Full API reference is available at https://hugoh.github.io/AudioPilot.spoon/.