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.
Screensaver busy-loops and cannot be dismissed when branding/screensaver.txt is missing
Reported by hhammarstrand · filed Sep 10, 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
What happened
If ~/.config/omarchy/branding/screensaver.txt is missing, the screensaver
turns into an unclosable fullscreen window spewing an error message as fast as
the terminal can render it:
Error reading input file: No such file or directory (os error 2)Escape and every other key are ignored. The only way out is Ctrl+C. To a user
who has just been idle for 150 seconds, this looks exactly like a system crash.
Root cause
omarchy-screensaver (omarchy 4.0.2) has three issues that compound:
while true; do
ttfx -i ~/.config/omarchy/branding/screensaver.txt ... & # exits 1 immediately
while pgrep -t "${tty#/dev/}" -x ttfx >/dev/null; do # never entered
if read -n1 -t 1 || ! screensaver_in_focus; then # keyboard poll
exit_screensaver
fi
done
done- No existence check on the input file, and no fallback — even though
Omarchy ships an identical file at /usr/share/omarchy/logo.txt.
2. `ttfx` failure is not detected. It exits 1 instantly, so the inner
while pgrep loop never runs a single iteration and while true
relaunches it immediately. This busy-loops at full CPU.
3. The keyboard poll is unreachable. read -n1 lives inside that inner
loop, so nothing reads input. Only trap exit_screensaver SIGINT survives,
which is why Ctrl+C is the sole escape.
Point 3 is the serious one: any failure of ttfx makes the screensaver
impossible to dismiss by normal means.
Measured
I replicated the loop structure against a real pty, counting outer iterations
and entries into the inner while pgrep loop over 3 seconds:
| Input file | Outer iterations | Inner iterations (keyboard poll) |
|---|---|---|
| valid | 1 | 27 |
| missing (run 1) | 173 | 0 |
| missing (run 2) | 131 | 0 |
| missing (run 3) | 184 | 0 |
With a valid file the keyboard poll runs ~9x/second and Escape dismisses the
screensaver. With the file missing the inner loop is never entered even once,
across three independent runs, while ttfx is relaunched ~55 times per second.
ttfx fails on file open before it does any terminal setup, so it is reliably
dead before pgrep is spawned. This is not a narrow race that sometimes goes
the other way.
Steps to reproduce
mv ~/.config/omarchy/branding/screensaver.txt{,.bak}
omarchy-launch-screensaver forceThe screen fills with the repeated error. Escape does nothing. Ctrl+C exits.
Expected
The screensaver should fall back to /usr/share/omarchy/logo.txt when the user
file is absent, and should exit rather than loop if ttfx fails to start.
Dismissing it with a keypress should work regardless.
Suggested fix
Any one of these closes the trap; the first two together would be ideal:
- Fall back to
/usr/share/omarchy/logo.txtif the user file does not exist. - Break out of the outer loop when
ttfxexits non-zero, instead of relaunching. - Move the keyboard poll so it runs even when
ttfxis not alive.
How we hit it
Not a hand-crafted repro. ~/.config/omarchy/branding was a symlink into a
dotfiles repo; the repo dropped that directory because its contents were
byte-identical to Omarchy's own logo.txt and icon.txt, on the assumption
that Omarchy would fall back to its own defaults. It does not.
System details
| Omarchy | 4.0.2-1 |
| ttfx | 0.3.2-1 |
| Kernel | 6.18.46-1-lts |
| CPU | Intel i7-4770HQ (Haswell) |
| GPU | Intel Iris Pro 5200 (Gen7.5, crocus) |
| Hardware | MacBookPro11,4 |
View raw text
### What happened
If `~/.config/omarchy/branding/screensaver.txt` is missing, the screensaver
turns into an unclosable fullscreen window spewing an error message as fast as
the terminal can render it:
```
Error reading input file: No such file or directory (os error 2)
```
Escape and every other key are ignored. The only way out is `Ctrl+C`. To a user
who has just been idle for 150 seconds, this looks exactly like a system crash.
### Root cause
`omarchy-screensaver` (omarchy 4.0.2) has three issues that compound:
```bash
while true; do
ttfx -i ~/.config/omarchy/branding/screensaver.txt ... & # exits 1 immediately
while pgrep -t "${tty#/dev/}" -x ttfx >/dev/null; do # never entered
if read -n1 -t 1 || ! screensaver_in_focus; then # keyboard poll
exit_screensaver
fi
done
done
```
1. **No existence check** on the input file, and no fallback — even though
Omarchy ships an identical file at `/usr/share/omarchy/logo.txt`.
2. **`ttfx` failure is not detected.** It exits 1 instantly, so the inner
`while pgrep` loop never runs a single iteration and `while true`
relaunches it immediately. This busy-loops at full CPU.
3. **The keyboard poll is unreachable.** `read -n1` lives inside that inner
loop, so nothing reads input. Only `trap exit_screensaver SIGINT` survives,
which is why `Ctrl+C` is the sole escape.
Point 3 is the serious one: any failure of `ttfx` makes the screensaver
impossible to dismiss by normal means.
### Measured
I replicated the loop structure against a real pty, counting outer iterations
and entries into the inner `while pgrep` loop over 3 seconds:
| Input file | Outer iterations | Inner iterations (keyboard poll) |
|---|---|---|
| valid | 1 | **27** |
| missing (run 1) | 173 | **0** |
| missing (run 2) | 131 | **0** |
| missing (run 3) | 184 | **0** |
With a valid file the keyboard poll runs ~9x/second and Escape dismisses the
screensaver. With the file missing the inner loop is never entered even once,
across three independent runs, while `ttfx` is relaunched ~55 times per second.
`ttfx` fails on file open before it does any terminal setup, so it is reliably
dead before `pgrep` is spawned. This is not a narrow race that sometimes goes
the other way.
### Steps to reproduce
```bash
mv ~/.config/omarchy/branding/screensaver.txt{,.bak}
omarchy-launch-screensaver force
```
The screen fills with the repeated error. Escape does nothing. `Ctrl+C` exits.
### Expected
The screensaver should fall back to `/usr/share/omarchy/logo.txt` when the user
file is absent, and should exit rather than loop if `ttfx` fails to start.
Dismissing it with a keypress should work regardless.
### Suggested fix
Any one of these closes the trap; the first two together would be ideal:
- Fall back to `/usr/share/omarchy/logo.txt` if the user file does not exist.
- Break out of the outer loop when `ttfx` exits non-zero, instead of relaunching.
- Move the keyboard poll so it runs even when `ttfx` is not alive.
### How we hit it
Not a hand-crafted repro. `~/.config/omarchy/branding` was a symlink into a
dotfiles repo; the repo dropped that directory because its contents were
byte-identical to Omarchy's own `logo.txt` and `icon.txt`, on the assumption
that Omarchy would fall back to its own defaults. It does not.
### System details
| | |
|---|---|
| Omarchy | 4.0.2-1 |
| ttfx | 0.3.2-1 |
| Kernel | 6.18.46-1-lts |
| CPU | Intel i7-4770HQ (Haswell) |
| GPU | Intel Iris Pro 5200 (Gen7.5, crocus) |
| Hardware | MacBookPro11,4 |
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 11:25 UTC