Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
bt-agent.service is permanently skipped when its ExecCondition races bluetooth.service, leaving the session with no Bluetooth pairing agent
Reported by pathtoplot · filed Sep 25, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- AreaOutside the audited area· Decided by agents · verified
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
Summary
bt-agent.service can be left permanently dead for the whole session, so Omarchy has no Bluetooth pairing agent. Every pairing attempt then fails, and the bar Bluetooth panel can never pair anything — its "paired" list stays permanently empty.
The radio is fine. bluetoothctl scan on still finds devices; they just can't be paired.
Root cause
/usr/lib/systemd/user/bt-agent.service guards itself with an ExecCondition:
ExecCondition=/usr/bin/systemctl is-active --quiet bluetooth.service
Restart=on-failureand install/user/first-run/enable-user-units.sh starts it with no ordering against the system service:
systemctl --user enable --now \
bt-agent.service \
...When ExecCondition fails, systemd skips the unit. A skip is a terminal state for that activation — Restart=on-failure does not re-activate it, so the agent is not retried once bluetooth.service finishes coming up a moment later.
bluetooth.service is a system unit started in parallel with the graphical session, so this is a startup race that wins whenever bluez is slow (or on a cold boot / spinning disk). Nothing re-checks the condition for the remainder of the session.
The same thing happens on any later `systemctl restart bluetooth.service`: bt-agent loses its agent registration and exits non-zero, systemd schedules a restart, and if bluez isn't active within that window the unit is skipped for good.
Evidence
From the journal on a machine that hit this (journalctl --user -u bt-agent):
18:01:17 bt-agent[800]: Agent released
18:01:17 bt-agent[800]: unregistering agent...
18:01:17 bt-agent[800]: org.freedesktop.DBus.Error.ServiceUnknown: The name is not activatable
18:01:18 systemd[758]: bt-agent.service: Main process exited, code=exited, status=1/FAILURE
18:01:18 systemd[758]: bt-agent.service: Failed with result 'exit-code'.
18:01:20 systemd[758]: bt-agent.service: Scheduled restart job, restart counter is at 1.
18:01:20 systemd[758]: bt-agent.service: Skipped due to 'exec-condition'.
18:02:00 systemd[758]: bt-agent.service: Skipped due to 'exec-condition'.
... bluetooth.service becomes active at 18:02:07, agent never returnsNet effect, confirmed at the time:
$ bluetoothctl devices Paired # empty — nothing ever paired
$ systemctl --user show bt-agent -p Result -p ConditionResult
Result=exec-condition
ConditionResult=noManually starting it once bluez is up fixes it immediately:
$ systemctl --user start bt-agent
Sep 25 18:10:17 bt-agent[65278]: Agent registered
Sep 25 18:10:17 bt-agent[65278]: Default agent requestedReproduction
- Have
bluetooth.serviceenabled (Omarchy does this by default). - Start the graphical session such that
bluetooth.serviceis still activating — e.g.systemctl restart bluetooth.serviceshortly before login, or a boot where bluez is slow to come up. systemctl --user show bt-agent.service -p Result→Result=exec-condition.- Try to pair anything from the bar Bluetooth panel. Pairing never completes.
Reliable manual trigger on a running system:
sudo systemctl stop bluetooth.service
systemctl --user restart bt-agent.service # or let Restart=on-failure fire
sudo systemctl start bluetooth.service
systemctl --user show bt-agent.service -p Result # exec-conditionSuggested fix
Order the user unit behind the system service so bluez is active before the condition is evaluated, and let it recover if bluez goes away again later. A drop-in is enough:
# /etc/systemd/user/bt-agent.service.d/override.conf
[Unit]
After=bluetooth.service
Wants=bluetooth.service
[Service]
Restart=always
RestartSec=3
StartLimitIntervalSec=0This keeps the original intent of the guard (skip cleanly on machines with no usable adapter) without letting the race turn into a permanent skip. Alternatively, dropping ExecCondition in favour of a bounded wait in ExecStartPre would be more robust, since any non-adaptor machine would otherwise restart-loop.
I verified the drop-in on the affected machine: after sudo systemctl restart bluetooth.service the agent re-registered on the first retry, which is precisely where it previously died for the session.
System details
- Omarchy: 4.0.4-1
- Kernel: 7.2.5-3-omarchy
- CPU: Intel Core i5-7360U @ 2.30GHz
- GPU: Intel Kaby Lake-U GT3 (Iris Plus Graphics 640)
- Adapter: USB (
usb:v1D6Bp0246d0557), BlueZ 5.87 - Desktop: Hyprland
View raw text
## Summary
`bt-agent.service` can be left permanently dead for the whole session, so Omarchy has **no Bluetooth pairing agent**. Every pairing attempt then fails, and the bar Bluetooth panel can never pair anything — its "paired" list stays permanently empty.
The radio is fine. `bluetoothctl scan on` still finds devices; they just can't be paired.
## Root cause
`/usr/lib/systemd/user/bt-agent.service` guards itself with an `ExecCondition`:
```ini
ExecCondition=/usr/bin/systemctl is-active --quiet bluetooth.service
Restart=on-failure
```
and `install/user/first-run/enable-user-units.sh` starts it with no ordering against the system service:
```sh
systemctl --user enable --now \
bt-agent.service \
...
```
When `ExecCondition` fails, systemd **skips** the unit. A skip is a terminal state for that activation — `Restart=on-failure` does not re-activate it, so the agent is not retried once `bluetooth.service` finishes coming up a moment later.
`bluetooth.service` is a system unit started in parallel with the graphical session, so this is a startup race that wins whenever bluez is slow (or on a cold boot / spinning disk). Nothing re-checks the condition for the remainder of the session.
The same thing happens on **any later `systemctl restart bluetooth.service`**: `bt-agent` loses its agent registration and exits non-zero, systemd schedules a restart, and if bluez isn't active within that window the unit is skipped for good.
## Evidence
From the journal on a machine that hit this (`journalctl --user -u bt-agent`):
```
18:01:17 bt-agent[800]: Agent released
18:01:17 bt-agent[800]: unregistering agent...
18:01:17 bt-agent[800]: org.freedesktop.DBus.Error.ServiceUnknown: The name is not activatable
18:01:18 systemd[758]: bt-agent.service: Main process exited, code=exited, status=1/FAILURE
18:01:18 systemd[758]: bt-agent.service: Failed with result 'exit-code'.
18:01:20 systemd[758]: bt-agent.service: Scheduled restart job, restart counter is at 1.
18:01:20 systemd[758]: bt-agent.service: Skipped due to 'exec-condition'.
18:02:00 systemd[758]: bt-agent.service: Skipped due to 'exec-condition'.
... bluetooth.service becomes active at 18:02:07, agent never returns
```
Net effect, confirmed at the time:
```
$ bluetoothctl devices Paired # empty — nothing ever paired
$ systemctl --user show bt-agent -p Result -p ConditionResult
Result=exec-condition
ConditionResult=no
```
Manually starting it once bluez is up fixes it immediately:
```
$ systemctl --user start bt-agent
Sep 25 18:10:17 bt-agent[65278]: Agent registered
Sep 25 18:10:17 bt-agent[65278]: Default agent requested
```
## Reproduction
1. Have `bluetooth.service` enabled (Omarchy does this by default).
2. Start the graphical session such that `bluetooth.service` is still activating — e.g. `systemctl restart bluetooth.service` shortly before login, or a boot where bluez is slow to come up.
3. `systemctl --user show bt-agent.service -p Result` → `Result=exec-condition`.
4. Try to pair anything from the bar Bluetooth panel. Pairing never completes.
Reliable manual trigger on a running system:
```sh
sudo systemctl stop bluetooth.service
systemctl --user restart bt-agent.service # or let Restart=on-failure fire
sudo systemctl start bluetooth.service
systemctl --user show bt-agent.service -p Result # exec-condition
```
## Suggested fix
Order the user unit behind the system service so bluez is active before the condition is evaluated, and let it recover if bluez goes away again later. A drop-in is enough:
```ini
# /etc/systemd/user/bt-agent.service.d/override.conf
[Unit]
After=bluetooth.service
Wants=bluetooth.service
[Service]
Restart=always
RestartSec=3
StartLimitIntervalSec=0
```
This keeps the original intent of the guard (skip cleanly on machines with no usable adapter) without letting the race turn into a permanent skip. Alternatively, dropping `ExecCondition` in favour of a bounded wait in `ExecStartPre` would be more robust, since any non-adaptor machine would otherwise restart-loop.
I verified the drop-in on the affected machine: after `sudo systemctl restart bluetooth.service` the agent re-registered on the first retry, which is precisely where it previously died for the session.
## System details
- Omarchy: 4.0.4-1
- Kernel: 7.2.5-3-omarchy
- CPU: Intel Core i5-7360U @ 2.30GHz
- GPU: Intel Kaby Lake-U GT3 (Iris Plus Graphics 640)
- Adapter: USB (`usb:v1D6Bp0246d0557`), BlueZ 5.87
- Desktop: Hyprland
Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
Not linked to any known issue, other report or change yet.
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- Out of scopeDecided by agents · verified · 2026-10-09 18:24 UTC