Releases: thisisgm/omarchy-pods
Release list
v1.3.6
v1.3.6
- The shipped user unit now runs under
UMask=0077inside aProtectSystem=strictplus
ProtectHome=read-onlysandbox whose only writable paths are the two service directories
and the runtime dir, sostatus.jsonand the control socket stop being world-readable.
systemd-analyze --user security librepods.servicegoes from 9.4 UNSAFE to 3.6 OK. - The daemon sets both modes itself, on the open temporary rather than on the final path,
so a manual launch under the default umask is covered too, and it refuses to publish the
state file rather than leaving the AirPods identity at the wrong mode. Fixes #37, reported
by @lbonvarl.
v1.3.5
Collects every change since v1.2.0. The v1.3.x tags were pushed without a GitHub
release, so their notes are gathered here.
v1.3.5
- The volume snap is disabled before the early return rather than below the idempotence
guard, so a teardown that returns early no longer leaves the snap armed. - A failed BlueZ sweep logs a new error instead of deduping on a bool, so a different
failure is no longer swallowed.
v1.3.4
- The BlueZ sweep is bounded to two seconds with a direct D-Bus call instead of an
unbounded introspection round trip. - The watchdog sweeps on a cold start where no address was ever learned, so a daemon that
started before the Bluetooth adapter finds a device that connects later. Fixes the
connected half of #24, contributed by @utsavsingh899 in #25.
v1.3.3
- The card is released once rather than on every ear-detection packet, measured at 17
releases in 20 minutes before and 1 in 2 minutes after. Fixes #31. - Every PulseAudio callback wakes the waiter on a negative eol, so an error no longer
leaveswaitForOperationblocked. Fixes #32.
v1.3.2
- The activation ladder defers while a live capture holds the AirPods microphone, so a
call is no longer switched off the headset profile mid-capture. Fixes #23. - The daemon stops overriding the output profile by name and ranks the offered codecs by
bitrate instead, so the highest-bitrate profile the device advertises is the one
selected. Fixes #27.
v1.3.1
- BLE discovery pauses on every controller rather than only Apple ones, which clears the
A2DP stutter reported on Intel controllers. Fixes #26.
v1.3.0
- A2DP activation is re-armed after a control-link recovery. Fixes #18, contributed by
@lbonvarl in #20. - Control-link recovery retries after its budget is exhausted, gated on BlueZ still
holding the device so the watchdog cannot restart the ladder indefinitely. Fixes #19,
contributed by @lbonvarl in #21. - MPRIS
PlaybackStatusis read without an introspection round trip, contributed by
@harisb2012 in #22.
Contributors
Thanks to everyone who reported, diagnosed or fixed something in this line:
- @lbonvarl, who reported #18 and #19 and sent the fixes for both in #20 and #21.
- @harisb2012, who removed the MPRIS introspection round trip in #22.
- @utsavsingh899, who reported #24 with a reproduction that counts BlueZ sweeps, and sent
the cold-start fix in #25. - @msegoviadev, who reported #26 and confirmed the fix on the affected Intel controller.
v1.2.0
The bar and hero mark now draw the AirPods you actually own, one of three product outlines picked from the model the daemon reports.
Listening modes, Adaptive, Conversation Awareness and One-Bud ANC are gated on four new per-model capability keys instead of is_pro_series, which stood in for H2 and got both AirPods 4 with ANC and the 2026 Max 2 wrong in opposite directions. AirPods 1, 2, 3 and the plain AirPods 4 now get no listening section at all, an AirPods Pro 1 stops being offered Adaptive it does not have, and an AirPods Max 2 gets Conversation Awareness without One-Bud ANC, which needs a second bud. A panel running against an older daemon keeps its previous behaviour, because an absent key is not a false one.
Four AirPods Pro 3 model codes Apple never published were dropped, so a device reporting one now reads as unknown rather than as a Pro 3.
v1.1.3
The control link no longer gives up while BlueZ still reports the device connected. BlueZ raises Connected once and never again for a device it already holds, so a spent retry ladder left the link down for good, not just for the 12 to 26 seconds issue #14 reported; only the retries taken while BlueZ says the device is absent count against bluetooth/retryAttempts now, and the give-up line says which of the two happened instead of reading as a failure on every ordinary disconnect.
The BLE scan pause reaches the Apple controllers behind UART, where the modalias is an ACPI id with no vendor field, so the machines that fix was written for stop stuttering through A2DP playback.
AirPods Max 2 (A3454) is recognised as a headset, so the panel shows one battery instead of three empty pod rows.
v1.1.2
v1.1.1
Two fixes to what the daemon writes.
The autostart entry was written through a predictable <name>.desktop.tmp, which a symlink could redirect. QSaveFile writes it now, matching how the status file was already written, and a test plants a symlink at the old path.
The settings file holding magicAccIRK and magicAccEncKey was 0644 inside a 0755 directory and survived removal. Both are owner only now, and ~/.config/AirPodsTrayApp and ~/.local/state/librepods go with the plugin.
v1.1.0
Six community contributions and one fix of my own, plus the first written contributing guide.
Audio and connection
- Stops BLE discovery only on an Apple made Bluetooth controller, which is the one that drops A2DP packets under continuous scanning. Every other machine keeps discovery running, so case and lid battery stay live while connected. Thanks Loic Bonvarlet.
- Retries A2DP profile activation until PipeWire has published the bluez5 card, instead of giving up on the first attempt after a connect. Thanks Thomas Vezyropoulos.
- Recovers the AAP control socket after a transient loss, backing off and probing BlueZ, rather than tearing down a healthy audio session. Thanks Loic Bonvarlet.
- Never reapplies the profile WirePlumber already set, which used to tear down a live sink under a playing stream.
Battery and identity
- Publishes the AirPods Max battery. Thanks Nicolai Dalsgaard.
- Fixes an out of bounds read in the BLE proximity packet parser. Thanks Thomas Vezyropoulos.
- Decodes the AirPods Pro 3 from its BLE model id, which used to read Unknown on every BLE sourced surface while AAP identified the same buds correctly.
Install
- First install is now two commands:
omarchy plugin add ... --enablethensetup, which installs the build dependencies, compiles the daemon into~/.localand enables the service. Re-running it after an update restarts the daemon onto the new binary. Thanks Gardiner Allen. CONTRIBUTING.mdandAGENTS.mddescribe the build, what review asks you to prove, and the house style.
v1.0.3
v1.0.2
Fixed
- The case no longer reads 0% when nothing is docked to read it. Only a docked pod can read the case level, so the payload's
0is treated as unknown and the last real reading survives. This is what fired a "Case AirPod Low Battery" notification on every fresh start.
Docs
- Every panel screenshot reshot against the current build. The old set drew an Off row that AirPods Pro 3 does not have.
Installing or updating:
omarchy plugin update io.github.thisisgm.omapodsThe daemon is rebuilt from daemon/ the same way as in the README. The bar widget is MIT; daemon/ is a modified copy of librepods by Kavish Devar and stays GPL-3.0.