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

omarchy theme set reports success when post-theme hooks fail (run_parallel discards wait status)

Reported by Brams-s · filed Sep 7, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 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

omarchy theme set reports success when post-theme hooks fail (run_parallel discards wait status)revision 1 · captured 2026-09-28 21:23 UTC via poll

What happened

omarchy theme set reports success even when its post-theme hooks fail. run_parallel (bin/omarchy-theme-set:33-45) waits on each hook and throws the status away:

for pid in "${pids[@]}"; do
  wait "$pid"
done

There is no set -e and no trap in the script, so nothing else catches it either. All fourteen entries in post_theme_commands — browser, vscode, obsidian, tmux, gnome, keyboard, the restart-* hooks — are unconditionally treated as having worked.

Reproducing with the function verbatim:

run_parallel() {
  local pid
  local pids=()
  for command in "$@"; do
    bash -lc "$command" &
    pids+=("$!")
  done
  for pid in "${pids[@]}"; do
    wait "$pid"
  done
}

run_parallel "true" "exit 42" "nonexistent-command-xyz" "true"
echo "run_parallel returned: $?"
bash: line 1: nonexistent-command-xyz: command not found
run_parallel returned: 0

Why it stays invisible

The exit status is discarded here, and on the normal interactive path the hook's stderr is discarded too — shell/plugins/background/Background.qml:119:

command: ["bash", "-c", "theme=$(omarchy-theme-switcher); [[ -n $theme ]] && omarchy-theme-set \"$theme\" >/dev/null 2>&1 &"]

So when a theme is changed from the picker, a broken hook produces no exit code, no message, and no notification. Nothing distinguishes it from a clean run, and the next theme change fails identically.

How I hit it

On this machine omarchy-theme-set-browser had been failing on every theme change for 17 days and I never saw it. It exits 1 with:

Error accessing /usr/bin/omarchy-theme-set-browser-policy: No such file or directory

omarchy-theme-set-browser-policy re-execs its own packaged path (correctly — etc/sudoers.d/omarchy-theme-browser names /usr/bin/omarchy-theme-set-browser-policy, so the rule only matches from there), and on this install that path did not exist. The visible symptom was unrelated-looking: Chromium was stuck showing the BrowserThemeColor of a theme I had stopped using, because /etc/chromium/policies/managed/color.json was simply never rewritten. Chasing it back to a failing theme hook took a while precisely because omarchy theme set kept reporting success.

The specific reason the path was missing is my own (a dev-linked checkout whose package predates commit bafc9a10, which added that helper) and is not what I am reporting. The point is that a hook exiting nonzero is currently unobservable, whatever the cause — the same applies to a hook that fails for any of the ordinary reasons.

This is also the mechanism that lets #10636's hang sit in a migration unnoticed until someone watches the log go quiet.

Expected

A failing hook should not abort the theme change — one broken retint should still leave the rest of the desktop themed, and I don't think that best-effort behaviour should change. But it should not pass for a clean run either.

Suggested fix

Collect the failures and name them on stderr, still returning zero. PR follows this issue.

Version

$ omarchy version
4.0.2

Present identically on omacom/omarchy@quattro (verified at e848f1df) and omacom/omarchy-mac@quattro.

View raw text
## What happened

`omarchy theme set` reports success even when its post-theme hooks fail. `run_parallel` (`bin/omarchy-theme-set:33-45`) waits on each hook and throws the status away:

```bash
for pid in "${pids[@]}"; do
  wait "$pid"
done
```

There is no `set -e` and no trap in the script, so nothing else catches it either. All fourteen entries in `post_theme_commands` — browser, vscode, obsidian, tmux, gnome, keyboard, the `restart-*` hooks — are unconditionally treated as having worked.

Reproducing with the function verbatim:

```bash
run_parallel() {
  local pid
  local pids=()
  for command in "$@"; do
    bash -lc "$command" &
    pids+=("$!")
  done
  for pid in "${pids[@]}"; do
    wait "$pid"
  done
}

run_parallel "true" "exit 42" "nonexistent-command-xyz" "true"
echo "run_parallel returned: $?"
```

```
bash: line 1: nonexistent-command-xyz: command not found
run_parallel returned: 0
```

## Why it stays invisible

The exit status is discarded here, and on the normal interactive path the hook's stderr is discarded too — `shell/plugins/background/Background.qml:119`:

```qml
command: ["bash", "-c", "theme=$(omarchy-theme-switcher); [[ -n $theme ]] && omarchy-theme-set \"$theme\" >/dev/null 2>&1 &"]
```

So when a theme is changed from the picker, a broken hook produces no exit code, no message, and no notification. Nothing distinguishes it from a clean run, and the next theme change fails identically.

## How I hit it

On this machine `omarchy-theme-set-browser` had been failing on **every** theme change for 17 days and I never saw it. It exits 1 with:

```
Error accessing /usr/bin/omarchy-theme-set-browser-policy: No such file or directory
```

`omarchy-theme-set-browser-policy` re-execs its own packaged path (correctly — `etc/sudoers.d/omarchy-theme-browser` names `/usr/bin/omarchy-theme-set-browser-policy`, so the rule only matches from there), and on this install that path did not exist. The visible symptom was unrelated-looking: Chromium was stuck showing the `BrowserThemeColor` of a theme I had stopped using, because `/etc/chromium/policies/managed/color.json` was simply never rewritten. Chasing it back to a failing theme hook took a while precisely because `omarchy theme set` kept reporting success.

The specific reason the path was missing is my own (a dev-linked checkout whose package predates commit bafc9a10, which added that helper) and is not what I am reporting. The point is that a hook exiting nonzero is currently unobservable, whatever the cause — the same applies to a hook that fails for any of the ordinary reasons.

This is also the mechanism that lets #10636's hang sit in a migration unnoticed until someone watches the log go quiet.

## Expected

A failing hook should not abort the theme change — one broken retint should still leave the rest of the desktop themed, and I don't think that best-effort behaviour should change. But it should not pass for a clean run either.

## Suggested fix

Collect the failures and name them on stderr, still returning zero. PR follows this issue.

## Version

```
$ omarchy version
4.0.2
```

Present identically on `omacom/omarchy@quattro` (verified at e848f1df) and `omacom/omarchy-mac@quattro`.

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:06 UTC