Skip to content

Releases: jettoai/cleat

Cleat 0.3.3

Choose a tag to compare

@dreamerhyde dreamerhyde released this 15 Sep 01:23

The daemon now comes back on its own

Cleat died twice this month and stayed dead for two days each time: it had been started with open -g from a supervised shell, inherited that shell's session mark, and was ended by the supervisor's cleanup at the next account handoff. A login item only starts at login, so nothing brought it back.

  • The bundle ships a LaunchAgent and launchAtLogin registers it (SMAppService.agent) instead of a login item. KeepAlive{SuccessfulExit:false}: a killed or crashed daemon is back within seconds, a clean quit stays down. launchd starts the binary with a clean environment.
  • cleat restart registers the agent if needed and has launchd replace the running process. cleat status gains a supervision: line.
  • A daemon that LaunchServices started hands over to the launchd one instead of running beside it.
  • The 0.3.2 login item is unregistered on first run.
  • Cask: uninstall launchctl:, and a postflight that kickstarts the agent so brew upgrade leaves a running daemon.

After upgrading, cleat status should show supervision: launchd agent (registered); if it does not, run cleat restart once.

Cleat 0.3.2

Choose a tag to compare

@dreamerhyde dreamerhyde released this 05 Sep 10:25

Hotfix: 0.3.0 wedged on its first reconcile when reclaim was set

+[IOBluetoothDevice pairedDevices] never returns in a process that holds no Bluetooth privacy decision, which is every launch of Cleat as an app; the engine queue stopped draining on the first beat and every rule went quiet. The paired-headset list now comes from system_profiler, read with a five second limit, only while the Mac is playing, and cached for thirty seconds.

  • CLEAT_CONFIG overrides the config path, so a Debug build can run against its own config.

Cleat 0.3.0

Choose a tag to compare

@dreamerhyde dreamerhyde released this 05 Sep 09:18

The Mac asks its headphones back from an idle iPhone

AirPods that wandered to the phone used to stay there: macOS only re-routes a headset when its own Smart Routing decides to, and a third-party app had no documented way to ask. Rule 7 uses the same routing request the system itself sends.

  • reclaim — a list of Bluetooth headsets Cleat is allowed to pull back. When one of them is connected to this Mac but missing from CoreAudio's device list, and the Mac's default output is playing, Cleat sends a routing request at the system's "the computer is playing" priority. An idle phone hands the headset over; a phone that is actually playing keeps it, and Cleat backs off for 60 seconds before asking again. Phone first, Mac only when the phone is quiet.
  • cleat reclaim "AirPods Max" — the same request on demand, printing the routing daemon's answer.
  • cleat status gains a reclaim line; the log records reclaim: <device> <- remote device on success and held by remote device when the phone wins.

Also in this release:

  • Output pinning no longer stops evicting a blocked output when every entry in output is a Bluetooth device and headphonesTakeOver is on.
  • Input volume locks now hold every device that shares a name, not just the first one.
  • cleat status and the README no longer overstate what a blocked list does without a priority list, or claim an unedited example config changes nothing (balance and launchAtLogin apply immediately).

v0.2.0

Choose a tag to compare

@dreamerhyde dreamerhyde released this 03 Sep 12:06

Bluetooth headphones take over the output when they connect

macOS switches the output to wired headphones the moment you plug them in, and iOS does the same for AirPods. A Bluetooth headset reconnecting to a Mac after a spell on the phone gets neither: the sound stays on whatever was playing before. Rule 6 closes that gap.

  • headphonesTakeOver: true — a Bluetooth output device that appears becomes the default output. It is edge triggered: picking another device by hand while the headphones stay connected is respected until they leave and come back. Headphones already connected when Cleat starts do not count as arriving.
  • blockedOutput — devices that must never be the default output. A USB microphone's speaker end is what macOS falls back to when the headphones go; listing it here sends the output to the top of your output list instead.
  • output now only decides what plays when no headphones are around, so the headset does not have to be listed.
  • config.example.json and the README example mirror the shipped setup.

cleat status gains a headphones line and shows the blocked outputs next to outputPin.

Upgrade: brew upgrade --cask cleat. Existing configs keep working; both new keys default to off.

Cleat 0.1.1

Choose a tag to compare

@dreamerhyde dreamerhyde released this 03 Sep 09:31

What's new

  • inputVolume accepts "*" as a default gain for every input device present; a named entry (name or UID) overrides it for that device. Without a wildcard, unlisted devices are left alone as before.
  • Volume listeners are registered on every device the rule holds, so a wildcard-covered device that a conferencing app turns down is pulled back on the change itself.
  • cleat status lists the default first, then each held device; a device that is present but whose gain could not be read shows (unreadable) instead of (absent).

Universal binary, Developer ID signed, notarized.

brew tap jettoai/tap && brew trust jettoai/tap && brew install --cask cleat

Cleat 0.1.0

Choose a tag to compare

@dreamerhyde dreamerhyde released this 03 Sep 05:54

First release. macOS audio device keeper: input priority and blocklist, wireless-mic liveness detection, balance lock, output priority, input volume lock, hot-reloaded config, cleat status / cleat log. Signed and notarized universal build.

Install: brew tap jettoai/tap && brew install --cask cleat