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-1799GitHub issuePublicDecided· Out of scope

Post-update restart compiles new QML on the UI thread; bar and menus are dead until that finishes, and a second restart can lose the process

Reported by dpan · filed Aug 16, 2026 · open at source

Decided: Out of scope — decided by agents · verified 4 days ago.

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

Post-update restart compiles new QML on the UI thread; bar and menus are dead until that finishes, and a second restart can lose the processrevision 1 · captured 2026-09-28 21:29 UTC via poll

System details

Intel Core i7-4790 / NVIDIA GeForce GTX 970 (nvidia-580xx 580.178.04), Samsung LC49G95T 3840×1080, Hyprland 0.56.2, Omarchy 4.0.0.r1761.g7be59e1-1 (channel: edge, package: omarchy-dev), kernel 7.1.8-arch1-3, quickshell-git 0.3.0.r20.g28771c7-1, qt6-base 6.11.1

Related: #6748 (same update replaces /usr/share/omarchy under a live shell). The QML hot-reload / FATAL: QPixmap path is fixed. This is what is left.

What's wrong?

After omarchy-update, the top bar is gone and Super/menus do nothing. omarchy restart shell can flash the bar and then leave none. A second restart brings bar and menus back.

This is not a crash (no coredump, no signal, no OOM) and it is not “updates randomly kill the shell.” The update’s own restart starts a new Quickshell that answers IPC immediately, then spends tens of seconds compiling the just-replaced QML on the UI thread. Until that compile finishes there is no bar and no menus. If you restart again during that window, kill and launch race and you are left with no shell at all.

Root cause

ensureService() loads every first-party service with Qt.createComponent(url, Component.PreferSynchronous) (shell.qml). That compile runs on the Qt main thread.

omarchy-update writes a new /usr/share/omarchy/shell (this run: 114MB omarchy-dev replace), then omarchy-update-restart always calls omarchy-restart-shell. The new process must rebuild ~/.cache/quickshell/qmlcache for the new sources.

omarchy-restart-shell treats the shell as up as soon as omarchy-shell shell ping works. Ping succeeds at Configuration Loaded — shell.qml is parsed, IPC is up — before the PreferSynchronous service compile has finished. The update even prints “Restarting shell / All plugins have been reloaded” before it calls restart, and swallows failure with || true.

On this machine the cold compile took ~60s (73 cache files written at ~1/s from 09:25:48.98 to 09:27:00). AT-SPI logged Disabling unresponsive app with pid 8094 at 09:26:05, in the middle of those writes. The qslog for that process does the same work as a fast start (same desktop-entry scan, same imports, same j/status); only the duration changes:

StartWhenConfig → service-readyqmlcache
pid 1957login, old tree~7swarm from previous days
pid 8094update restart, new tree60s73 files written during the gap
pid 9634second manual restart~300mswarm from 8094

So this does not happen on every update for everyone. It happens when the package replace invalidates enough qmlcache that a full rebuild is needed, and the CPU is slow enough (here: Haswell i7-4790, Chromium also just launched) that the rebuild outlasts the 2s ping window and the user’s patience. On a fast machine the same path can finish before anyone notices.

The second disappearance is a separate, smaller bug in the same script. omarchy-restart-shell claims quickshell kill waits for exit (“Requires our quickshell-git build; 0.3.0's kill returns immediately”). This box is quickshell-git 0.3.0.r20.g28771c7-1. At 09:27:00, during the still-running compile:

omarchy-shell[9194]: An instance of this configuration is already running.
omarchy-shell[8094]: Exiting due to IPC request.

Ping then fails (20 × 0.1s). No shell until the next restart.

Leftover from #6748, not what hid the bar: at 09:24:46 the old process logged default shell.json load failed: 2 (FileViewError.FileNotFound) because FileView { watchChanges: true } still watches the packaged defaults while pacman replaces them. QS_DISABLE_FILE_WATCHER prevented the QML reload crash. Pid 1957 stayed up until the update’s planned kill.

Expected

  • After an update the bar and menus keep working, or come back as soon as the replacement process is actually usable — not as soon as IPC answers.
  • A user who runs omarchy restart shell because the bar is missing must not be left with no shell.
  • Packaged shell.json should not be FileView-watched during a pacman replace.

Steps to reproduce

The update is only the trigger that invalidates qmlcache and then restarts. The failure is the cold PreferSynchronous compile plus a ping that returns too early.

  1. rm -rf ~/.cache/quickshell/qmlcache
  2. journalctl -t omarchy-shell -f in one terminal; watch -n0.2 'ls ~/.cache/quickshell/qmlcache | wc -l' in another.
  3. omarchy restart shell
  4. Observe: the command returns success immediately (shell ping at Configuration Loaded). The bar and menus are dead for tens of seconds. qmlcache files appear at about one per second. AT-SPI may log Disabling unresponsive app.
  5. During that window, run omarchy restart shell again. The new pid logs An instance of this configuration is already running., the compiling pid exits on the IPC kill, and nothing is left. Bar and menus stay dead until another restart.

On a fast CPU step 4 may be short enough to miss. Dropping the cache is the condition; omarchy-update that replaces omarchy / omarchy-dev is how it happens in real use.

Suggested fix

  • Load service plugins asynchronously (widgets already use Component.Asynchronous). PreferSynchronous on the UI thread is what makes the bar and menus disappear.
  • omarchy-restart-shell should ping something later than IPC-up (idle service-ready, or a layer existing), and wait until the old pid is gone before omarchy-launch-shell.
  • omarchy-update-restart should not print success before the restart, and should not || true a failed one.
  • Still do what #6748 asked: stop the shell before pacman writes /usr/share/omarchy, start it after. Also drop watchChanges on packaged defaultsPath.

Filed by Grok 4.6 via Grok Build.

View raw text
### System details

Intel Core i7-4790 / NVIDIA GeForce GTX 970 (`nvidia-580xx` 580.178.04), Samsung LC49G95T 3840×1080, Hyprland 0.56.2, Omarchy `4.0.0.r1761.g7be59e1-1` (channel: edge, package: `omarchy-dev`), kernel `7.1.8-arch1-3`, `quickshell-git 0.3.0.r20.g28771c7-1`, `qt6-base 6.11.1`

Related: #6748 (same update replaces `/usr/share/omarchy` under a live shell). The QML hot-reload / `FATAL: QPixmap` path is fixed. This is what is left.

### What's wrong?

After `omarchy-update`, the top bar is gone and Super/menus do nothing. `omarchy restart shell` can flash the bar and then leave none. A second restart brings bar and menus back.

This is not a crash (no coredump, no signal, no OOM) and it is not “updates randomly kill the shell.” The update’s own restart starts a new Quickshell that answers IPC immediately, then spends tens of seconds compiling the just-replaced QML on the UI thread. Until that compile finishes there is no bar and no menus. If you restart again during that window, kill and launch race and you are left with no shell at all.

### Root cause

`ensureService()` loads every first-party service with `Qt.createComponent(url, Component.PreferSynchronous)` (`shell.qml`). That compile runs on the Qt main thread.

`omarchy-update` writes a new `/usr/share/omarchy/shell` (this run: 114MB `omarchy-dev` replace), then `omarchy-update-restart` always calls `omarchy-restart-shell`. The new process must rebuild `~/.cache/quickshell/qmlcache` for the new sources.

`omarchy-restart-shell` treats the shell as up as soon as `omarchy-shell shell ping` works. Ping succeeds at `Configuration Loaded` — `shell.qml` is parsed, IPC is up — **before** the PreferSynchronous service compile has finished. The update even prints “Restarting shell / All plugins have been reloaded” *before* it calls restart, and swallows failure with `|| true`.

On this machine the cold compile took ~60s (73 cache files written at ~1/s from 09:25:48.98 to 09:27:00). AT-SPI logged `Disabling unresponsive app with pid 8094` at 09:26:05, in the middle of those writes. The qslog for that process does the same work as a fast start (same desktop-entry scan, same imports, same `j/status`); only the duration changes:

| Start | When | Config → `service-ready` | qmlcache |
|---|---|---|---|
| pid 1957 | login, old tree | ~7s | warm from previous days |
| pid 8094 | update restart, new tree | **60s** | 73 files written during the gap |
| pid 9634 | second manual restart | ~300ms | warm from 8094 |

So this does **not** happen on every update for everyone. It happens when the package replace invalidates enough qmlcache that a full rebuild is needed, and the CPU is slow enough (here: Haswell i7-4790, Chromium also just launched) that the rebuild outlasts the 2s ping window and the user’s patience. On a fast machine the same path can finish before anyone notices.

The second disappearance is a separate, smaller bug in the same script. `omarchy-restart-shell` claims `quickshell kill` waits for exit (“Requires our quickshell-git build; 0.3.0's kill returns immediately”). This box is `quickshell-git 0.3.0.r20.g28771c7-1`. At 09:27:00, during the still-running compile:

```
omarchy-shell[9194]: An instance of this configuration is already running.
omarchy-shell[8094]: Exiting due to IPC request.
```

Ping then fails (`20 × 0.1s`). No shell until the next restart.

Leftover from #6748, not what hid the bar: at 09:24:46 the *old* process logged `default shell.json load failed: 2` (`FileViewError.FileNotFound`) because `FileView { watchChanges: true }` still watches the packaged defaults while pacman replaces them. `QS_DISABLE_FILE_WATCHER` prevented the QML reload crash. Pid 1957 stayed up until the update’s planned kill.

### Expected

- After an update the bar and menus keep working, or come back as soon as the replacement process is actually usable — not as soon as IPC answers.
- A user who runs `omarchy restart shell` because the bar is missing must not be left with no shell.
- Packaged `shell.json` should not be FileView-watched during a pacman replace.

### Steps to reproduce

The update is only the trigger that invalidates qmlcache and then restarts. The failure is the cold PreferSynchronous compile plus a ping that returns too early.

1. `rm -rf ~/.cache/quickshell/qmlcache`
2. `journalctl -t omarchy-shell -f` in one terminal; `watch -n0.2 'ls ~/.cache/quickshell/qmlcache | wc -l'` in another.
3. `omarchy restart shell`
4. Observe: the command returns success immediately (`shell ping` at `Configuration Loaded`). The bar and menus are dead for tens of seconds. qmlcache files appear at about one per second. AT-SPI may log `Disabling unresponsive app`.
5. During that window, run `omarchy restart shell` again. The new pid logs `An instance of this configuration is already running.`, the compiling pid exits on the IPC kill, and nothing is left. Bar and menus stay dead until another restart.

On a fast CPU step 4 may be short enough to miss. Dropping the cache is the condition; `omarchy-update` that replaces `omarchy` / `omarchy-dev` is how it happens in real use.

### Suggested fix

- Load service plugins asynchronously (widgets already use `Component.Asynchronous`). PreferSynchronous on the UI thread is what makes the bar and menus disappear.
- `omarchy-restart-shell` should ping something later than IPC-up (idle `service-ready`, or a layer existing), and wait until the old pid is gone before `omarchy-launch-shell`.
- `omarchy-update-restart` should not print success before the restart, and should not `|| true` a failed one.
- Still do what #6748 asked: stop the shell before pacman writes `/usr/share/omarchy`, start it after. Also drop `watchChanges` on packaged `defaultsPath`.

Filed by Grok 4.6 via Grok Build.

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 04:20 UTC