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.
Power panel only reads the first battery on dual-battery hardware (ignores real combined charge, no per-battery breakdown)
Reported by jadonfloyd · filed Aug 25, 2026Closed upstream on 2026-09-20 by bjarneo via an automated message, as a duplicate of #6885 (R-1856). GitHub close reason: completed.
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?
- Not yet mapped to any requirement or component.
- 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?
- Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.
Original report
Summary
On a dual-battery laptop (e.g. Lenovo ThinkPad T450 with an internal + hot-swap "Ultrabay" battery), the Power panel's detailed stats — the big percentage, battery size, cycle count, and time remaining — only reflect the first battery UPower enumerates. When that battery happens to be sitting full (held there by a charge threshold) while the other battery is the one actually being drawn down, the panel reports a misleadingly high percentage (up to a phantom "100%") and never shows the second battery at all.
The small bar icon itself is unaffected — it already reads UPower.displayDevice, which correctly aggregates across every battery — so this is specific to the expanded panel.
Root cause
omarchy-battery-status (/usr/share/omarchy/bin/omarchy-battery-status) picks a single device here:
battery=$(upower -e 2>/dev/null | grep BAT | head -n 1)Everything downstream (percentage, energy-full/"size", cycle count, thresholds, time-to-empty/full) is derived from that one device only. On a single-battery machine this is invisible, but on a dual-battery machine it silently reports whichever battery sorts first — which may not be the one actually discharging.
The panel's Panel.qml (/usr/share/omarchy/shell/plugins/panels/power/Panel.qml) calls this script for its batteryInfo, so the same limitation surfaces in the UI. There's also no concept anywhere in the power panel of "more than one battery" — even if the script reported the correct aggregate, there's no way to see each battery's individual charge/state/health.
Steps to reproduce
- On a laptop with two batteries exposed as separate UPower devices (
upower -elists twobattery_BAT*entries). - Let one battery sit at/near 100% (e.g. held there by a charge threshold) while the system draws down the other.
- Click the battery icon in the bar to open the Power panel.
- Observe: the panel shows the idle battery's percentage/size/cycles (e.g. "100%", size = that battery's capacity only) instead of the real combined charge, and there's no way to see the second battery.
Expected behavior
- The panel's percentage/size/time/rate should reflect the combined charge across every battery (as
UPower.displayDevicealready does for the bar icon). - Ideally, an expandable/listed breakdown of each individual battery's percentage, charging state, and health, since on this class of hardware they often charge/discharge independently (see below).
What I did to confirm and work around it
I cloned the built-in omarchy.power plugin (omarchy plugin clone omarchy.power) and:
1. Replaced the single-device upower -i "$battery" call with a read of upower -i /org/freedesktop/UPower/devices/DisplayDevice (UPower's own correct energy-weighted aggregate) for percentage/state/rate/time, keeping the per-battery sysfs loop only for cycle count and thresholds (which DisplayDevice doesn't carry).
2. Added a per-battery breakdown section to the panel, since watching it live surfaced something worth noting: on this hardware the system fully drains one battery before touching the second, rather than discharging both proportionally — so a combined-only percentage hides real, useful state (e.g. "the primary is nearly empty, about to fail over").
Screenshots attached:
- omarchy-battery-bug-before-stock-plugin.png — stock panel, single-battery data only (18Wh battery size = BAT0's capacity alone, no way to see BAT1).
<img width="378" height="226" alt="Image" src="https://github.com/user-attachments/assets/df22de83-28d7-4f56-9ee6-5292ee6fe6d5" />
omarchy-battery-bug-after-dual-battery-fix.png— patched panel: correct combined percentage/size, plus a "BATTERIES" section listing BAT0 and BAT1 individually with their own percentage, state, and health.
<img width="383" height="292" alt="Image" src="https://github.com/user-attachments/assets/3304b1af-ae3f-4b0e-a471-6b69a257d8c2" />
Secondary issue: Process command changes didn't hot-reload
While developing the fix locally, editing a cloned plugin's Process.command (in Panel.qml) did not take effect in the already-running shell, even though the shell's own log confirmed the file change was detected ("Local plugin changed, reloading: ..."). The old command kept running in the background until I ran omarchy restart shell. Plain QML/JS logic changes in the same file did seem to take effect via hot-reload; it was specifically the Process.command binding that stuck. Not sure if this is expected/known, but it cost real time to track down — might be worth a note in the plugin-authoring docs if it's a known limitation, or a fix if not.
System info
- Machine: Lenovo ThinkPad T450 (DMI product:
20BV000AUS) - CPU: Intel Core i5-5300U @ 2.30GHz
- GPU: Intel HD Graphics 5500 (Broadwell-U GT2)
- Kernel: 7.1.9-arch1-2
- Omarchy: 4.0.1-1
- quickshell: 0.3.1-1
- upower: 1.91.3-1
- Batteries:
BAT0(LGC 45N1113, internal) andBAT1(LGC 45N1127, Ultrabay/second bay) — both visibly degraded (77% and 65% of design capacity respectively after years of use), which is what makes the "which one is at 100%" confusion especially noticeable day to day.
View raw text
## Summary
On a dual-battery laptop (e.g. Lenovo ThinkPad T450 with an internal + hot-swap "Ultrabay" battery), the Power panel's detailed stats — the big percentage, battery size, cycle count, and time remaining — only reflect the *first* battery UPower enumerates. When that battery happens to be sitting full (held there by a charge threshold) while the *other* battery is the one actually being drawn down, the panel reports a misleadingly high percentage (up to a phantom "100%") and never shows the second battery at all.
The small bar icon itself is unaffected — it already reads `UPower.displayDevice`, which correctly aggregates across every battery — so this is specific to the expanded panel.
## Root cause
`omarchy-battery-status` (`/usr/share/omarchy/bin/omarchy-battery-status`) picks a single device here:
```bash
battery=$(upower -e 2>/dev/null | grep BAT | head -n 1)
```
Everything downstream (percentage, energy-full/"size", cycle count, thresholds, time-to-empty/full) is derived from that one device only. On a single-battery machine this is invisible, but on a dual-battery machine it silently reports whichever battery sorts first — which may not be the one actually discharging.
The panel's `Panel.qml` (`/usr/share/omarchy/shell/plugins/panels/power/Panel.qml`) calls this script for its `batteryInfo`, so the same limitation surfaces in the UI. There's also no concept anywhere in the power panel of "more than one battery" — even if the script reported the correct aggregate, there's no way to see each battery's individual charge/state/health.
## Steps to reproduce
1. On a laptop with two batteries exposed as separate UPower devices (`upower -e` lists two `battery_BAT*` entries).
2. Let one battery sit at/near 100% (e.g. held there by a charge threshold) while the system draws down the other.
3. Click the battery icon in the bar to open the Power panel.
4. Observe: the panel shows the idle battery's percentage/size/cycles (e.g. "100%", size = that battery's capacity only) instead of the real combined charge, and there's no way to see the second battery.
## Expected behavior
- The panel's percentage/size/time/rate should reflect the combined charge across every battery (as `UPower.displayDevice` already does for the bar icon).
- Ideally, an expandable/listed breakdown of each individual battery's percentage, charging state, and health, since on this class of hardware they often charge/discharge independently (see below).
## What I did to confirm and work around it
I cloned the built-in `omarchy.power` plugin (`omarchy plugin clone omarchy.power`) and:
1. Replaced the single-device `upower -i "$battery"` call with a read of `upower -i /org/freedesktop/UPower/devices/DisplayDevice` (UPower's own correct energy-weighted aggregate) for percentage/state/rate/time, keeping the per-battery sysfs loop only for cycle count and thresholds (which `DisplayDevice` doesn't carry).
2. Added a per-battery breakdown section to the panel, since watching it live surfaced something worth noting: on this hardware the system fully drains one battery before touching the second, rather than discharging both proportionally — so a combined-only percentage hides real, useful state (e.g. "the primary is nearly empty, about to fail over").
Screenshots attached:
- `omarchy-battery-bug-before-stock-plugin.png` — stock panel, single-battery data only (18Wh battery size = BAT0's capacity alone, no way to see BAT1).
<img width="378" height="226" alt="Image" src="https://github.com/user-attachments/assets/df22de83-28d7-4f56-9ee6-5292ee6fe6d5" />
- `omarchy-battery-bug-after-dual-battery-fix.png` — patched panel: correct combined percentage/size, plus a "BATTERIES" section listing BAT0 and BAT1 individually with their own percentage, state, and health.
<img width="383" height="292" alt="Image" src="https://github.com/user-attachments/assets/3304b1af-ae3f-4b0e-a471-6b69a257d8c2" />
## Secondary issue: Process command changes didn't hot-reload
While developing the fix locally, editing a cloned plugin's `Process.command` (in `Panel.qml`) did not take effect in the already-running shell, even though the shell's own log confirmed the file change was detected ("Local plugin changed, reloading: ..."). The old command kept running in the background until I ran `omarchy restart shell`. Plain QML/JS logic changes in the same file *did* seem to take effect via hot-reload; it was specifically the `Process.command` binding that stuck. Not sure if this is expected/known, but it cost real time to track down — might be worth a note in the plugin-authoring docs if it's a known limitation, or a fix if not.
## System info
- Machine: Lenovo ThinkPad T450 (DMI product: `20BV000AUS`)
- CPU: Intel Core i5-5300U @ 2.30GHz
- GPU: Intel HD Graphics 5500 (Broadwell-U GT2)
- Kernel: 7.1.9-arch1-2
- Omarchy: 4.0.1-1
- quickshell: 0.3.1-1
- upower: 1.91.3-1
- Batteries: `BAT0` (LGC 45N1113, internal) and `BAT1` (LGC 45N1127, Ultrabay/second bay) — both visibly degraded (77% and 65% of design capacity respectively after years of use), which is what makes the "which one is at 100%" confusion especially noticeable day to day.
- df22de83-28d7-4f56-9ee6-5292ee6fe6d5
- 3304b1af-ae3f-4b0e-a471-6b69a257d8c2
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.
No decision has been recorded yet.