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.
Menu: first item is clipped/scrolled off on initial display in scrollable lists (omarchy-menu-select / SUPER+K)
Reported by b-lov · filed Oct 3, 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?
- 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. So far: in the audited area (menu) — decided by agents · verified; matches no known issue — decided by agents · verified. The outcome (valid, duplicate, not a bug, …) is not decided yet. See the decision.
Original report
System details
AMD Ryzen 7 8845HS w/ Radeon 780M Graphics, Omarchy 4.0.0.r6713.ga85e29a-1 (Hyprland / Quickshell)
What's wrong?
When opening any list with more items than fit inside the initial view height (e.g. SUPER + K for omarchy-menu-keybindings, or any invocation of omarchy-menu-select with >8 items), the very first item (index 0) is scrolled up into negative space and clipped/obscured.
Steps to reproduce
- Press
SUPER + Kto open the keybindings menu. - Notice the top of the list: the topmost entry (
SUPER + K → Keybindings, priority 0) has scrolled up above the top border of the ListView and is clipped. Visually, the list appears to start with the second entry (SUPER + SPACE → Omarchy menu). - Alternatively, run:
omarchy-menu-select "Test" $(for i in {1..15}; do echo "Option $i"; done)Notice "Option 1" has its top half cut off.
Root cause
In shell/plugins/menu/Menu.qml inside revealCursor():
function revealCursor() {
if (displayModel.count === 0) return
resultList.positionViewAtIndex(root.selectedIndex, ListView.Contain)
var item = resultList.itemAtIndex(root.selectedIndex)
if (!item) return
var reach = root.rowPeek + root.rowSpacing
if (root.selectedIndex < displayModel.count - 1) {
var maxY = Math.max(resultList.originY, resultList.originY + resultList.contentHeight - resultList.height)
var overhang = item.y + item.height + reach - (resultList.contentY + resultList.height)
if (overhang > 0) resultList.contentY = Math.min(resultList.contentY + overhang, maxY)
}
if (root.selectedIndex > 0) {
var underhang = resultList.contentY - (item.y - reach)
if (underhang > 0) resultList.contentY = Math.max(resultList.contentY - underhang, resultList.originY)
}
}- On initial open,
revealCursor()is invoked viaQt.callLaterwhendisplayModelloads. - At this moment, before
resultList.heighthas settled to the final mapped window height,overhangevaluates to> 0becauseitem.y + item.height + reachexceeds the initial list height. - This sets
resultList.contentY = overhang(typically ~30–40px), scrolling item 0 partially out of view. - Because
root.selectedIndex === 0, the underhang logic (if (root.selectedIndex > 0)) never resets `contentY` back to `originY`. - As a result, item 0 remains permanently scrolled up and clipped.
Fix
When selectedIndex === 0, contentY should always remain flush at resultList.originY (0):
--- a/shell/plugins/menu/Menu.qml
+++ b/shell/plugins/menu/Menu.qml
@@ -690,6 +690,10 @@
function revealCursor() {
if (displayModel.count === 0) return
+ if (root.selectedIndex === 0) {
+ resultList.contentY = resultList.originY
+ return
+ }
resultList.positionViewAtIndex(root.selectedIndex, ListView.Contain)
var item = resultList.itemAtIndex(root.selectedIndex)View raw text
### System details
AMD Ryzen 7 8845HS w/ Radeon 780M Graphics, Omarchy 4.0.0.r6713.ga85e29a-1 (Hyprland / Quickshell)
### What's wrong?
When opening any list with more items than fit inside the initial view height (e.g. `SUPER + K` for `omarchy-menu-keybindings`, or any invocation of `omarchy-menu-select` with >8 items), the **very first item (index 0) is scrolled up into negative space and clipped/obscured**.
#### Steps to reproduce
1. Press `SUPER + K` to open the keybindings menu.
2. Notice the top of the list: the topmost entry (`SUPER + K → Keybindings`, priority 0) has scrolled up above the top border of the ListView and is clipped. Visually, the list appears to start with the second entry (`SUPER + SPACE → Omarchy menu`).
3. Alternatively, run:
```bash
omarchy-menu-select "Test" $(for i in {1..15}; do echo "Option $i"; done)
```
Notice "Option 1" has its top half cut off.
#### Root cause
In `shell/plugins/menu/Menu.qml` inside `revealCursor()`:
```javascript
function revealCursor() {
if (displayModel.count === 0) return
resultList.positionViewAtIndex(root.selectedIndex, ListView.Contain)
var item = resultList.itemAtIndex(root.selectedIndex)
if (!item) return
var reach = root.rowPeek + root.rowSpacing
if (root.selectedIndex < displayModel.count - 1) {
var maxY = Math.max(resultList.originY, resultList.originY + resultList.contentHeight - resultList.height)
var overhang = item.y + item.height + reach - (resultList.contentY + resultList.height)
if (overhang > 0) resultList.contentY = Math.min(resultList.contentY + overhang, maxY)
}
if (root.selectedIndex > 0) {
var underhang = resultList.contentY - (item.y - reach)
if (underhang > 0) resultList.contentY = Math.max(resultList.contentY - underhang, resultList.originY)
}
}
```
1. On initial open, `revealCursor()` is invoked via `Qt.callLater` when `displayModel` loads.
2. At this moment, before `resultList.height` has settled to the final mapped window height, `overhang` evaluates to `> 0` because `item.y + item.height + reach` exceeds the initial list height.
3. This sets `resultList.contentY = overhang` (typically ~30–40px), scrolling item 0 partially out of view.
4. Because `root.selectedIndex === 0`, the underhang logic (`if (root.selectedIndex > 0)`) **never resets `contentY` back to `originY`**.
5. As a result, item 0 remains permanently scrolled up and clipped.
#### Fix
When `selectedIndex === 0`, `contentY` should always remain flush at `resultList.originY` (0):
```diff
--- a/shell/plugins/menu/Menu.qml
+++ b/shell/plugins/menu/Menu.qml
@@ -690,6 +690,10 @@
function revealCursor() {
if (displayModel.count === 0) return
+ if (root.selectedIndex === 0) {
+ resultList.contentY = resultList.originY
+ return
+ }
resultList.positionViewAtIndex(root.selectedIndex, ListView.Contain)
var item = resultList.itemAtIndex(root.selectedIndex)
```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
- Fixed bypr/14190· confirmed
- Fixed bypr/14393· confirmed
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.
- Decided by agents · verified: in the audited area (menu)
- Decided by agents · verified: matches no known issue
The outcome (valid, duplicate, not a bug, …) is not decided yet.