Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-2151GitHub issuePublicFixed

Super + K hangs and spawns CPU-bound Lua processes when config iterates hl.get_workspaces()

Reported by jermartinz · filed Oct 1, 2026Closed upstream on 2026-10-13 by the bot omarchybot, as a duplicate (target not recorded).

Decided: Duplicate — decided by agents · verified 4 days ago.

R-1816 is the earliest report of this defect — filed Aug 15, 2026, open upstream. This report (filed Oct 1, 2026) describes the same defect, so it is folded under it in the inbox.

Decided by agents · verified· Oct 8, 2026

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?
AreaIn the audited areamenu· 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

Super + K hangs and spawns CPU-bound Lua processes when config iterates hl.get_workspaces()revision 1 · captured 2026-10-01 19:13 UTC via poll

System details

  • Omarchy: 4.0.4-1
  • Hyprland: 0.56.2-2
  • Lua: 5.5.1-1
  • Kernel: 7.2.5-3-omarchy (x86_64)
  • CPU: AMD Ryzen 5 5600X (6 cores / 12 threads)
  • GPU: NVIDIA GeForce RTX 3060

What's wrong?

Opening the keybindings menu with Super + K hangs while scanning a custom Lua Hyprland configuration containing a top-level ipairs(hl.get_workspaces()) loop. Each invocation leaves a Lua process consuming approximately 100% of one CPU core. Four concurrent processes were observed at 98–99% CPU each, with only about 3 MB RSS per process.

The configuration uses this loop to apply workspace-to-monitor rules to existing workspaces. The failure occurs in the menu's standalone Lua scanner, rather than in the compositor's execution of the configuration.

Steps to reproduce

  1. In a Lua-based Hyprland configuration, add a top-level iteration over workspaces. This minimal loop is enough to exercise the scanner problem:
   for _, ws in ipairs(hl.get_workspaces()) do
     -- Even an empty body never terminates under the menu's mock.
   end
  1. Trigger a cache miss and run the menu. To test without changing the normal cache or leaving another runaway process, use a temporary cache and a bounded command:
   task_cache_dir=$(mktemp -d)
   XDG_CACHE_HOME="$task_cache_dir" timeout 5s omarchy menu keybindings --print
  1. The command emits no keybindings and times out with exit status 124. On a cache miss, pressing Super + K without a timeout leaves the scanner spinning; repeated attempts accumulate CPU-bound Lua processes.

Expected: The keybindings scan terminates and the menu opens. Runtime workspace queries should not cause an unbounded scan.

Actual: The scanner loops indefinitely and the menu cannot finish building its cache.

Confirmed cause

In build_lua_bind_cache(), the scanner executes the user's configuration with pcall(dofile, config), using a mocked hl API. Unimplemented methods resolve to the noop table. Its __call returns that same table, and its __index returns that same table for every key:

local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})

Consequently, hl.get_workspaces() returns noop; ipairs keeps indexing positive integers, receiving a non-nil value forever. pcall does not help because no error is raised.

The same mock is present in the official source checked at commit `c05d90196fc0dd5c21e2e797d80ffcc60d5e39fa`. The runtime reproduction below was performed with the installed 4.0.4-1 script.

Diagnostic evidence and candidate fix

An instruction-limited copy of the extracted scanner aborts with a traceback pointing to the top-level workspace loop in the user's hyprland.lua:

SCAN INSTRUCTION LIMIT
stack traceback:
    ...diagnostic.lua:5: in hook '?'
    .../hyprland.lua:63: in main chunk
    [C]: in function 'dofile'
    [C]: in global 'pcall'
    ...diagnostic.lua:158: in main chunk

Adding an explicit stub to the mocked hl table fixes this specific reproduction:

get_workspaces = function()
  return {}
end,

Verified using the full menu script, a temporary cache, and a five-second timeout:

Original installed script: exit 124, 0 output lines
Patched temporary copy:    exit 0,   224 output lines

The patched extracted Lua scanner also terminates successfully and emits 223 binding records. No installed scripts or user configuration were modified for these tests.

An explicit empty collection stub addresses get_workspaces(). A time or instruction budget around configuration scanning would additionally prevent other custom configuration code from leaving unbounded CPU-bound scanners.

View raw text
### System details

- Omarchy: `4.0.4-1`
- Hyprland: `0.56.2-2`
- Lua: `5.5.1-1`
- Kernel: `7.2.5-3-omarchy` (x86_64)
- CPU: AMD Ryzen 5 5600X (6 cores / 12 threads)
- GPU: NVIDIA GeForce RTX 3060

### What's wrong?

Opening the keybindings menu with **Super + K** hangs while scanning a custom Lua Hyprland configuration containing a top-level `ipairs(hl.get_workspaces())` loop. Each invocation leaves a Lua process consuming approximately 100% of one CPU core. Four concurrent processes were observed at 98–99% CPU each, with only about 3 MB RSS per process.

The configuration uses this loop to apply workspace-to-monitor rules to existing workspaces. The failure occurs in the menu's standalone Lua scanner, rather than in the compositor's execution of the configuration.

### Steps to reproduce

1. In a Lua-based Hyprland configuration, add a top-level iteration over workspaces. This minimal loop is enough to exercise the scanner problem:

   ```lua
   for _, ws in ipairs(hl.get_workspaces()) do
     -- Even an empty body never terminates under the menu's mock.
   end
   ```

2. Trigger a cache miss and run the menu. To test without changing the normal cache or leaving another runaway process, use a temporary cache and a bounded command:

   ```bash
   task_cache_dir=$(mktemp -d)
   XDG_CACHE_HOME="$task_cache_dir" timeout 5s omarchy menu keybindings --print
   ```

3. The command emits no keybindings and times out with exit status `124`. On a cache miss, pressing Super + K without a timeout leaves the scanner spinning; repeated attempts accumulate CPU-bound Lua processes.

**Expected:** The keybindings scan terminates and the menu opens. Runtime workspace queries should not cause an unbounded scan.

**Actual:** The scanner loops indefinitely and the menu cannot finish building its cache.

### Confirmed cause

In `build_lua_bind_cache()`, the scanner executes the user's configuration with `pcall(dofile, config)`, using a mocked `hl` API. Unimplemented methods resolve to the `noop` table. Its `__call` returns that same table, and its `__index` returns that same table for every key:

```lua
local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})
```

Consequently, `hl.get_workspaces()` returns `noop`; `ipairs` keeps indexing positive integers, receiving a non-nil value forever. `pcall` does not help because no error is raised.

The same mock is present in the official source checked at commit [`c05d90196fc0dd5c21e2e797d80ffcc60d5e39fa`](https://github.com/basecamp/omarchy/blob/c05d90196fc0dd5c21e2e797d80ffcc60d5e39fa/bin/omarchy-menu-keybindings#L187-L230). The runtime reproduction below was performed with the installed `4.0.4-1` script.

### Diagnostic evidence and candidate fix

An instruction-limited copy of the extracted scanner aborts with a traceback pointing to the top-level workspace loop in the user's `hyprland.lua`:

```text
SCAN INSTRUCTION LIMIT
stack traceback:
    ...diagnostic.lua:5: in hook '?'
    .../hyprland.lua:63: in main chunk
    [C]: in function 'dofile'
    [C]: in global 'pcall'
    ...diagnostic.lua:158: in main chunk
```

Adding an explicit stub to the mocked `hl` table fixes this specific reproduction:

```lua
get_workspaces = function()
  return {}
end,
```

Verified using the full menu script, a temporary cache, and a five-second timeout:

```text
Original installed script: exit 124, 0 output lines
Patched temporary copy:    exit 0,   224 output lines
```

The patched extracted Lua scanner also terminates successfully and emits 223 binding records. No installed scripts or user configuration were modified for these tests.

An explicit empty collection stub addresses `get_workspaces()`. A time or instruction budget around configuration scanning would additionally prevent other custom configuration code from leaving unbounded CPU-bound scanners.

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

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.

  • DuplicateR-1816Decided by agents · verified · 2026-10-08 22:31 UTC