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-1642GitHub issuePublicFixed

AppLibrary icon index ignores the active icon theme: first filesystem hit wins, so app icons come from hicolor and change between rescans

Reported by assada · filed Aug 19, 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

AppLibrary icon index ignores the active icon theme: first filesystem hit wins, so app icons come from hicolor and change between rescansrevision 1 · captured 2026-09-28 21:29 UTC via poll

System details

Omarchy 4.0.0-1, Hyprland 0.56.2, quickshell-git 0.3.0.r20.g28771c7-1, Arch Linux, kernel 7.1.8-arch1-3, Intel i5-8350U / UHD 620. /usr/share on btrfs. Icon theme set to Tela-circle (tela-circle-icon-theme-all 2026_07_07-1).

What is wrong?

shell/services/AppLibrary.qml builds its own icon index and consults it before the themed lookup, so the icon theme selected in org.gnome.desktop.interface icon-theme is largely ignored for application icons in the menu/launcher.

The scan (iconIndexScanCommand()) walks every XDG icon directory and takes every */apps/* and */devices/* file:

dirs="$HOME/.icons $HOME/.local/share/icons";
IFS=":"; for d in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do dirs="$dirs $d/icons"; done; unset IFS;
for ext in svg png; do
  for base in $dirs; do
    [[ -d $base ]] && find "$base" \( -path "*/apps/*" -o -path "*/devices/*" \) -name "*.$ext" 2>/dev/null;
  done
  find /usr/share/pixmaps -maxdepth 1 -name "*.$ext" 2>/dev/null;
done

indexIconLine() keys purely on the file's basename and keeps the first hit:

if (name.length > 0 && root.pendingIconIndex[name] === undefined)
  root.pendingIconIndex[name] = value

and iconSource() gives that index precedence over Quickshell.iconPath():

var found = root.iconIndex[value]
if (found) return Util.fileUrl(found)
var themed = Quickshell.iconPath(value, true)
if (themed.length > 0) return themed

Nothing in this path knows which icon theme is active. Whichever theme on disk find happens to reach first wins.

Consequence 1 — the selected theme loses to whatever is found first. With icon-theme set to Tela-circle, only 20 of the 67 non-absolute Icon= names across my installed desktop entries resolved into Tela-circle; 42 came from hicolor/breeze/Adwaita, including names Tela-circle does provide:

NAME               IN-THEME INDEX PICKS (first hit wins)
foot               yes      /usr/share/icons/hicolor/scalable/apps/foot.svg
mpv                yes      /usr/share/icons/hicolor/scalable/apps/mpv.svg
btop               yes      /usr/share/icons/hicolor/scalable/apps/btop.svg
kdenlive           yes      /usr/share/icons/hicolor/scalable/apps/kdenlive.svg
libreoffice-calc   yes      /usr/share/icons/hicolor/scalable/apps/libreoffice-calc.svg

Since hicolor holds each application's own upstream icon, the practical effect is that installing an icon theme changes little in the launcher, and which icons do change is arbitrary.

Consequence 2 — the winner is not stable across rescans. find output order is not guaranteed. On btrfs here, five consecutive identical scans produced identical content in five different orders (diff <(sort a) <(sort b) is empty; diff a b is not). So the same name can resolve to a different theme on the next scan. Because refreshIcons() re-runs the scan whenever a consumer opens — and per #6806 it can fire roughly once a second — icons visibly change with no user action. That is how I noticed this: icons flipped between themed and stock while I was doing nothing.

Note that the code comment describes the index as a fallback for icons Qt's themed lookup misses (newly installed apps), but it is currently the primary resolver.

Steps to recreate

# 1. Install any icon theme that overlaps hicolor, e.g.
sudo pacman -S tela-circle-icon-theme
gsettings set org.gnome.desktop.interface icon-theme Tela-circle
omarchy restart shell

# 2. Replay the scan exactly as AppLibrary.qml runs it
scan() {
  local dirs="$HOME/.icons $HOME/.local/share/icons"
  IFS=":"; for d in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do dirs="$dirs $d/icons"; done; unset IFS
  for ext in svg png; do
    for base in $dirs; do
      [[ -d $base ]] && find "$base" \( -path "*/apps/*" -o -path "*/devices/*" \) -name "*.$ext" 2>/dev/null
    done
    find /usr/share/pixmaps -maxdepth 1 -name "*.$ext" 2>/dev/null
  done
}
scan > /tmp/s1; scan > /tmp/s2

# 3. The active theme loses to hicolor even though it ships the icon
ls /usr/share/icons/Tela-circle/scalable/apps/foot.svg   # exists
grep -m1 '/foot\.' /tmp/s1                               # -> hicolor/scalable/apps/foot.svg

# 4. Same content, different order on every run
diff <(sort /tmp/s1) <(sort /tmp/s2) | wc -l   # 0
diff /tmp/s1 /tmp/s2 | wc -l                   # non-zero

Then open the Apps menu: icons come from a mix of themes, and change between openings.

Expected

Application icons should come from the icon theme the user selected, and should not change on their own.

Suggested fix

Either restrict the scan to the active theme plus its Inherits chain (then hicolor), or — probably simpler — restore the index to the fallback role its comment describes: try Quickshell.iconPath() first, since it already honours the icon theme, and fall back to the index only for names the themed lookup misses. Sorting each find (find ... | sort) would additionally make the outcome deterministic regardless of filesystem traversal order.

Workaround (verified)

Force the wanted theme to the front of the scan by putting its app/device icons in $HOME/.icons, which the scan reads first:

mkdir -p ~/.icons/tela-priority/scalable/{apps,devices}
find /usr/share/icons/Tela-circle/scalable/apps    -maxdepth 1 -name '*.svg' -exec ln -sf {} ~/.icons/tela-priority/scalable/apps/    \;
find /usr/share/icons/Tela-circle/scalable/devices -maxdepth 1 -name '*.svg' -exec ln -sf {} ~/.icons/tela-priority/scalable/devices/ \;
omarchy restart shell

This raised the count from 20 to 46 of 67, deterministically. Two details matter: the scan's find has no -L, so a symlink to the theme directory is invisible to it and the links must be per-file; and the directory deliberately has no index.theme, so GTK/Qt do not treat it as a theme.

View raw text
### System details

Omarchy 4.0.0-1, Hyprland 0.56.2, `quickshell-git 0.3.0.r20.g28771c7-1`, Arch Linux, kernel 7.1.8-arch1-3, Intel i5-8350U / UHD 620. `/usr/share` on btrfs. Icon theme set to `Tela-circle` (`tela-circle-icon-theme-all 2026_07_07-1`).

### What is wrong?

`shell/services/AppLibrary.qml` builds its own icon index and consults it **before** the themed lookup, so the icon theme selected in `org.gnome.desktop.interface icon-theme` is largely ignored for application icons in the menu/launcher.

The scan (`iconIndexScanCommand()`) walks every XDG icon directory and takes every `*/apps/*` and `*/devices/*` file:

```bash
dirs="$HOME/.icons $HOME/.local/share/icons";
IFS=":"; for d in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do dirs="$dirs $d/icons"; done; unset IFS;
for ext in svg png; do
  for base in $dirs; do
    [[ -d $base ]] && find "$base" \( -path "*/apps/*" -o -path "*/devices/*" \) -name "*.$ext" 2>/dev/null;
  done
  find /usr/share/pixmaps -maxdepth 1 -name "*.$ext" 2>/dev/null;
done
```

`indexIconLine()` keys purely on the file's basename and keeps the first hit:

```js
if (name.length > 0 && root.pendingIconIndex[name] === undefined)
  root.pendingIconIndex[name] = value
```

and `iconSource()` gives that index precedence over `Quickshell.iconPath()`:

```js
var found = root.iconIndex[value]
if (found) return Util.fileUrl(found)
var themed = Quickshell.iconPath(value, true)
if (themed.length > 0) return themed
```

Nothing in this path knows which icon theme is active. Whichever theme on disk `find` happens to reach first wins.

**Consequence 1 — the selected theme loses to whatever is found first.** With `icon-theme` set to `Tela-circle`, only 20 of the 67 non-absolute `Icon=` names across my installed desktop entries resolved into `Tela-circle`; 42 came from `hicolor`/`breeze`/`Adwaita`, including names `Tela-circle` does provide:

```
NAME               IN-THEME INDEX PICKS (first hit wins)
foot               yes      /usr/share/icons/hicolor/scalable/apps/foot.svg
mpv                yes      /usr/share/icons/hicolor/scalable/apps/mpv.svg
btop               yes      /usr/share/icons/hicolor/scalable/apps/btop.svg
kdenlive           yes      /usr/share/icons/hicolor/scalable/apps/kdenlive.svg
libreoffice-calc   yes      /usr/share/icons/hicolor/scalable/apps/libreoffice-calc.svg
```

Since `hicolor` holds each application's own upstream icon, the practical effect is that installing an icon theme changes little in the launcher, and which icons *do* change is arbitrary.

**Consequence 2 — the winner is not stable across rescans.** `find` output order is not guaranteed. On btrfs here, five consecutive identical scans produced identical *content* in five different *orders* (`diff <(sort a) <(sort b)` is empty; `diff a b` is not). So the same name can resolve to a different theme on the next scan. Because `refreshIcons()` re-runs the scan whenever a consumer opens — and per #6806 it can fire roughly once a second — icons visibly change with no user action. That is how I noticed this: icons flipped between themed and stock while I was doing nothing.

Note that the code comment describes the index as a *fallback* for icons Qt's themed lookup misses (newly installed apps), but it is currently the primary resolver.

### Steps to recreate

```bash
# 1. Install any icon theme that overlaps hicolor, e.g.
sudo pacman -S tela-circle-icon-theme
gsettings set org.gnome.desktop.interface icon-theme Tela-circle
omarchy restart shell

# 2. Replay the scan exactly as AppLibrary.qml runs it
scan() {
  local dirs="$HOME/.icons $HOME/.local/share/icons"
  IFS=":"; for d in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do dirs="$dirs $d/icons"; done; unset IFS
  for ext in svg png; do
    for base in $dirs; do
      [[ -d $base ]] && find "$base" \( -path "*/apps/*" -o -path "*/devices/*" \) -name "*.$ext" 2>/dev/null
    done
    find /usr/share/pixmaps -maxdepth 1 -name "*.$ext" 2>/dev/null
  done
}
scan > /tmp/s1; scan > /tmp/s2

# 3. The active theme loses to hicolor even though it ships the icon
ls /usr/share/icons/Tela-circle/scalable/apps/foot.svg   # exists
grep -m1 '/foot\.' /tmp/s1                               # -> hicolor/scalable/apps/foot.svg

# 4. Same content, different order on every run
diff <(sort /tmp/s1) <(sort /tmp/s2) | wc -l   # 0
diff /tmp/s1 /tmp/s2 | wc -l                   # non-zero
```

Then open the Apps menu: icons come from a mix of themes, and change between openings.

### Expected

Application icons should come from the icon theme the user selected, and should not change on their own.

### Suggested fix

Either restrict the scan to the active theme plus its `Inherits` chain (then `hicolor`), or — probably simpler — restore the index to the fallback role its comment describes: try `Quickshell.iconPath()` first, since it already honours the icon theme, and fall back to the index only for names the themed lookup misses. Sorting each `find` (`find ... | sort`) would additionally make the outcome deterministic regardless of filesystem traversal order.

### Workaround (verified)

Force the wanted theme to the front of the scan by putting its app/device icons in `$HOME/.icons`, which the scan reads first:

```bash
mkdir -p ~/.icons/tela-priority/scalable/{apps,devices}
find /usr/share/icons/Tela-circle/scalable/apps    -maxdepth 1 -name '*.svg' -exec ln -sf {} ~/.icons/tela-priority/scalable/apps/    \;
find /usr/share/icons/Tela-circle/scalable/devices -maxdepth 1 -name '*.svg' -exec ln -sf {} ~/.icons/tela-priority/scalable/devices/ \;
omarchy restart shell
```

This raised the count from 20 to 46 of 67, deterministically. Two details matter: the scan's `find` has no `-L`, so a symlink to the theme *directory* is invisible to it and the links must be per-file; and the directory deliberately has no `index.theme`, so GTK/Qt do not treat it as a theme.

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/9408· 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.

  • Out of scopeDecided by agents · verified · 2026-10-09 08:43 UTC