Skip to content

Make the adapter pairable while pairing a Bluetooth device - #11198

Open
megamos wants to merge 1 commit into
omacom:quattrofrom
megamos:bluetooth-pair-bondable
Open

megamos wants to merge 1 commit into
omacom:quattrofrom
megamos:bluetooth-pair-bondable

Conversation

@megamos

@megamos megamos commented Sep 10, 2026

Copy link
Copy Markdown

Problem

Bluetooth headphones paired from the Omarchy panel work once, then have to be forgotten and paired again every time they are powered on. "Connect" reports connected but no audio output appears.

Root cause: BlueZ only flags the adapter Pairable while a default agent is registered, and the non-interactive bluetoothctl pair that omarchy-bluetooth-device runs does not register one. Against a non-pairable adapter the kernel forces the "no bonding" authentication requirement (hci_persistent_key returns false), so pairing succeeds and audio plays, but the link key is never written to /var/lib/bluetooth. bluetoothctl info shows Paired: yes / Bonded: no. On the next reconnect the headphones reject the session-only key, BlueZ wipes the pairing, and the user is back to forget-and-pair.

bt-agent.service is what normally holds Pairable, but it is skipped whenever /sys/class/bluetooth or bluetoothd shows up after the user session starts, which is the normal case for a USB dongle:

bt-agent.service: skipped, unmet condition check ConditionPathIsDirectory=/sys/class/bluetooth

Fix

omarchy-bluetooth-device pair raises Pairable around the pair handshake when nothing else holds it, and lowers it again afterwards. When the agent already holds it the script leaves it alone.

Verification

  • Reproduced on Omarchy 4.0.2, BlueZ 5.87, TP-Link UB500 (RTL8761BU), Bose QC35 II. With bt-agent stopped and Pairable: no, the stock script yields Bonded: no and no [LinkKey] on disk. The patched script yields Bonded: yes, a stored [LinkKey], the PipeWire sink up, and Pairable restored to no afterwards. Subsequent power-cycles reconnect without re-pairing.
  • test/shell.d/bluetooth-test.sh covers the ordering (pairable on before pair, off after) and the leave-alone case. ./test/cli green.

The bt-agent startup race is a separate issue worth its own fix; this change makes bonding independent of it.


From Marcus (megamos): regards and thanks to DHH and the team. Loving Omarchy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BntCyAvwXhANA1b4UH9tek

BlueZ only flags the adapter pairable while a default agent is registered,
and the non-interactive `bluetoothctl pair` the panel runs does not register
one. Whenever bt-agent is not running the kernel negotiates "no bonding":
pairing succeeds and audio plays, but the link key is never written to
/var/lib/bluetooth. On the next reconnect the device refuses the session key,
BlueZ drops the pairing, and the user has to forget and pair again every time.

bt-agent is skipped on any machine where /sys/class/bluetooth or bluetoothd
appears after the user session starts, which is the normal case for a USB
dongle, so this is easy to hit.

Raise Pairable around the pair handshake when nothing else holds it and put it
back afterwards, so bonding no longer depends on the agent's startup timing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BntCyAvwXhANA1b4UH9tek
@omarchybot omarchybot added the bug Something isn't working label Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants