Keyboard-driven terminal utilities for macOS: manage WiFi, Bluetooth, Tailscale and audio devices from the terminal, using native system frameworks (CoreWLAN, IOBluetooth and CoreAudio) rather than wrapping flaky command-line tools.
| Command | What it does |
|---|---|
macutil |
Menu that opens the tools below |
macutil-wifi |
Scan, connect (including hidden networks), disconnect, power |
macutil-bt |
Paired and nearby devices, connect, disconnect, pair, forget |
macutil-ts |
Peers, exit nodes (listed by city), ping, up/down, copy IP |
macutil-audio |
Output and input devices: default device, volume, mute, sample rate |
Requires macOS 14 (Sonoma) or newer. Apple silicon is the tested platform.
Every option below installs the same tools. They differ in one thing: whether they include
the Location helper, a small app that lets macutil-wifi show network names (macOS hides
them otherwise; see Permissions).
| Method | Location helper | WiFi network names |
|---|---|---|
| Homebrew cask | included | shown |
| Install script | included | shown |
Build the app bundle (scripts/bundle.sh) |
included | shown |
| Homebrew formula | not included | blank |
Plain cargo build |
not included | blank |
If you use WiFi, pick one of the first three.
Installs Macutil.app and puts the five commands on your PATH. The cask comes from a
personal tap, so it needs no Apple notarization.
brew install --cask l-castel/tap/macutilBuilds only the command-line tools from source with Homebrew's Rust toolchain. WiFi network names will be blank. Use the cask if you need them.
brew install l-castel/tap/macutilThe formula and the cask install the same commands, so install one or the other, not both.
Builds from a checkout, installs Macutil.app (with the Location helper) into
/Applications and links the commands into ~/.local/bin.
git clone https://github.com/l-castel/macutil.git
cd macutil
./install.shRemove it again with ./install.sh --uninstall. Override locations with APPS_DIR
and BIN_DIR.
You need macOS and a recent stable Rust toolchain.
git clone https://github.com/l-castel/macutil.git
cd macutil
cargo build --releaseThe binaries land in target/release/ (macutil, macutil-wifi, macutil-bt,
macutil-ts, macutil-audio). Keep them in the same directory: the menu launches its siblings.
This gives you the tools without the Location helper, so WiFi network names are
blank. To get the helper, run scripts/bundle.sh instead. It builds dist/Macutil.app,
which you can copy to /Applications.
Run macutil for the menu, or any tool directly. Movement is ↑/↓ or j/k, and
q quits.
macutil-wifi: ⏎ connect · s scan · d disconnect · h hidden network · o power
macutil-bt: ⏎ connect, disconnect or pair · tab paired/nearby · s scan ·
f forget (press twice) · r refresh
macutil-ts: tab peers/exit nodes · u up/down · e set or clear exit node ·
p ping · y copy IP · / filter · r refresh
Exit nodes are labelled by city and numbered within it, for example Los Angeles, CA 2.
The filter matches city, country name, two-letter country code and hostname.
macutil-ts needs the tailscale command line tool, either from the Tailscale app or
Homebrew.
macutil-audio: ⏎ make default · ←/→ or h/l volume (hold shift for 1%) ·
1–9, 0 volume 10–100% · m mute · tab output/input · a play alerts here ·
s next sample rate · r refresh. Devices without software volume (most HDMI and
DisplayPort outputs) show "fixed volume".
Macutil.app opens the menu in a small panel in Ghostty, kitty, Alacritty or WezTerm,
whichever it finds first (set MACUTIL_TERMINAL=/Applications/Name.app to choose). The
panel has no titlebar or window buttons. q quits and closes it. Terminal.app, the last
fallback, opens a normal window.
The window is titled macutil. Tiling window managers may float it because it has no
window buttons. To tile it in AeroSpace, add this rule above any rule that matches your
terminal, because AeroSpace stops at the first match:
[[on-window-detected]]
if.app-id = 'com.mitchellh.ghostty'
if.window-title-regex-substring = '^macutil$'
run = 'layout tiling'- Bluetooth: macOS may ask your terminal for Bluetooth access the first time.
- Location: macOS hides WiFi network names from any process without Location access,
and command-line tools cannot be granted it. The app bundle includes a small helper
(
MacutilLocation.app) that holds this permission. Runmacutil-wifi, presss, and answer the prompt once. Without the helper (formula or plaincargo build), scans still work but network names are blank.
macutil works on its own: with no theme file it uses a built-in Tokyo Night palette.
To change it, edit ~/.config/macutil/theme.toml (or the path in $MACUTIL_THEME).
Changes apply live. All keys are optional #rrggbb values:
fg = "#c0caf5"
dim = "#565f89"
accent = "#7aa2f7"
on_accent = "#000000"
good = "#9ece6a"
warn = "#e0af68"
bad = "#f7768e"
# bg = "#1a1b26" # unset keeps your terminal's backgroundIf matugen is installed, macutil can follow your matugen theme. It asks first, once:
Allow macutil to add its template to <matugen config> so its colours follow your matugen theme? [y/N]
You'll see this during ./install.sh, or on the first launch of any macutil tool if you
installed with Homebrew (Homebrew installs can't prompt or write to your home directory).
Your answer is saved in ~/.config/macutil/matugen-consent. To change it, delete that
file, or run macutil setup-matugen (add --yes or --no to skip the question).
If you answer yes, macutil:
- writes its template to
~/.config/macutil/matugen-template.toml. An existing file is kept, so you can edit it to pick other Material You roles. - appends this block to your matugen config, unless it's already there:
[templates.macutil] input_path = '~/.config/macutil/matugen-template.toml' output_path = '~/.config/macutil/theme.toml'
- renders the theme once from your current wallpaper, so it matches straight away. Only macutil's template is rendered, so other apps and matugen hooks aren't run.
From then on, every matugen run rewrites theme.toml, and macutil picks it up.
No macOS permission is involved. The matugen config is a regular file in your home
directory. The config used is $MATUGEN_CONFIG if set. Otherwise it's matugen's macOS
default, ~/Library/Application Support/com.InioX.matugen/config.toml, or
~/.config/matugen/config.toml if only that one exists (for setups that call
matugen -c). To undo, remove the [templates.macutil] block.
- Cask:
brew uninstall --cask macutil(add--zapto remove config) - Formula:
brew uninstall macutil - Install script:
./install.sh --uninstall
MIT. See LICENSE.