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.
omarchy update aborts after the Quattro upgrade: six scripts string-compare OMARCHY_PATH against /usr/share/omarchy, defeating the upgrader's own compat symlink
Reported by Xpond · filed Aug 18, 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
After upgrading to Quattro (4.0.0-1, package-backed install), omarchy update aborted at the very first step:
Create system snapshot
Snapshots can be selected during boot.
Error: OMARCHY_PATH is not a git checkout: /home/<user>/.local/share/omarchy
Something went wrong during the update!The install is entirely healthy — omarchy and omarchy-settings 4.0.0-1 are installed from pacman, /usr/share/omarchy is intact, and ~/.local/share/omarchy is the compat symlink pointing at `/usr/share/omarchy` that omarchy-upgrade-to-quattro itself creates. The only problem is that OMARCHY_PATH still holds the legacy path string.
Root cause
Six scripts decide "is this a dev checkout?" by comparing $OMARCHY_PATH as a string against /usr/share/omarchy, without resolving symlinks:
| Script | Line |
|---|---|
omarchy-update-dev | 7 |
omarchy-version | 8 |
omarchy-channel-current | 10 |
omarchy-channel-set | 75 |
omarchy-version-branch | 9 |
omarchy-update-available | 9 |
# omarchy-update-dev:7
[[ $OMARCHY_PATH != "/usr/share/omarchy" ]] || exit 0This directly defeats a shim the upgrader installs on purpose. From omarchy-upgrade-to-quattro:1017:
Existing terminals still haveOMARCHY_PATH=$HOME/.local/share/omarchyand often have$OMARCHY_PATH/binearly in PATH. Make that stale path resolve to the package-backed tree for the rest of the live session.
The upgrader anticipates this exact stale-env condition and neutralizes it by making the old path resolve to the new tree. The string comparison ignores that resolution, so ~/.local/share/omarchy is misclassified as a dev checkout, the git check runs, and a pacman-installed tree has no .git.
Nothing in the codebase canonicalizes OMARCHY_PATH — the only readlink -f applied to it is in omarchy-dns:32, for an unrelated purpose.
Impact
The session environment is not affected: /usr/share/uwsm/env.d/10-omarchy sources default/bash/env-bootstrap, which forces OMARCHY_PATH=/usr/share/omarchy when /etc/omarchy.conf is absent. I confirmed via /proc/<pid>/environ that both Hyprland and the Quickshell process hold the correct value, so the bar, the menu's channel display (shell/plugins/menu/MenuModel.js), and anything launched from the session are all fine.
The bug is reachable only from a shell whose environment predates that session env or overrides it afterwards:
- A terminal opened before the upgrade, in any shell — precisely the case the
:1017comment describes. Persists until it is closed. - A shell whose own config re-exports the legacy path (a non-bash config carrying the 3.x-era
OMARCHY_PATH).env-bootstrapcovers the bash rc chain and uwsm, so this survives re-login there.
Inside such a shell, verified on this machine with identical binaries and only the env var differing:
| Command | stale OMARCHY_PATH | resolved | Consequence |
|---|---|---|---|
omarchy-update-dev | `Error: ... is not a git checkout`, exit 1 | exit 0 | `omarchy update` aborts entirely |
omarchy version | dev | 4.0.0-1 | version unreportable from that shell |
omarchy-channel-current | dev | stable | wrong channel from that shell |
omarchy-update-available | up to date | up to date | benign, degrades gracefully |
The aborted update is the consequence that matters; the misreports are confined to the affected shell and never reach the UI. omarchy-update-dev runs after omarchy-update-pkg-prune and omarchy-snapshot create, so the failure lands after the cache has been pruned and a snapshot taken — the update dies mid-flight rather than refusing to start.
Steps to reproduce
No unusual configuration required — a stale exported value is enough:
env OMARCHY_PATH="$HOME/.local/share/omarchy" bash -c 'omarchy-update-dev; echo "exit=$?"'
# Error: OMARCHY_PATH is not a git checkout: /home/<user>/.local/share/omarchy
# exit=1
env OMARCHY_PATH="$HOME/.local/share/omarchy" bash -c 'omarchy version'
# dev (expected: 4.0.0-1)
readlink -f ~/.local/share/omarchy
# /usr/share/omarchy <- the shim is working; the comparison ignores itThis is not shell-specific — it reproduces under plain bash, as above, in any terminal still carrying the pre-upgrade export.
In my case the login shell is fish, and a config.fish export carried the 3.x path, which is what made it persist past a re-login rather than clearing with the terminal. To be clear, the upgrader migrating ~/.bashrc and not third-party shell configs is entirely reasonable and is not what I am reporting, and env-bootstrap already handles the bash side correctly. The report is that the compat symlink the upgrader deliberately creates does not actually protect these six scripts against a stale value from any source.
What was expected
OMARCHY_PATH pointing at a symlink that resolves to /usr/share/omarchy should be treated as the package-backed install it is, honoring the upgrader's shim.
Suggested fix
Resolve before comparing:
[[ $(readlink -f "$OMARCHY_PATH") != /usr/share/omarchy ]] || exit 0Costs nothing for genuine dev checkouts, which are not symlinked to the package tree. Given six call sites, a shared helper (or canonicalizing once in default/bash/env-bootstrap, which already centralizes OMARCHY_PATH) would keep the rule in one place.
System
- Omarchy 4.0.0-1 (
omarchyandomarchy-settings), upgraded from 3.8.2 viaomarchy-upgrade-to-quattro - Channel: stable
- Hyprland 0.56.2
- Kernel 7.1.8-arch1-3
Filed by Claude Opus 5 via Claude Code.
View raw text
## What happened After upgrading to Quattro (4.0.0-1, package-backed install), `omarchy update` aborted at the very first step: ``` Create system snapshot Snapshots can be selected during boot. Error: OMARCHY_PATH is not a git checkout: /home/<user>/.local/share/omarchy Something went wrong during the update! ``` The install is entirely healthy — `omarchy` and `omarchy-settings` 4.0.0-1 are installed from pacman, `/usr/share/omarchy` is intact, and `~/.local/share/omarchy` is the compat **symlink pointing at `/usr/share/omarchy`** that `omarchy-upgrade-to-quattro` itself creates. The only problem is that `OMARCHY_PATH` still holds the legacy path string. ## Root cause Six scripts decide "is this a dev checkout?" by comparing `$OMARCHY_PATH` as a **string** against `/usr/share/omarchy`, without resolving symlinks: | Script | Line | |---|---| | `omarchy-update-dev` | 7 | | `omarchy-version` | 8 | | `omarchy-channel-current` | 10 | | `omarchy-channel-set` | 75 | | `omarchy-version-branch` | 9 | | `omarchy-update-available` | 9 | ```bash # omarchy-update-dev:7 [[ $OMARCHY_PATH != "/usr/share/omarchy" ]] || exit 0 ``` This directly defeats a shim the upgrader installs on purpose. From `omarchy-upgrade-to-quattro:1017`: > Existing terminals still have `OMARCHY_PATH=$HOME/.local/share/omarchy` and often have `$OMARCHY_PATH/bin` early in PATH. Make that stale path resolve to the package-backed tree for the rest of the live session. The upgrader anticipates this exact stale-env condition and neutralizes it by making the old path resolve to the new tree. The string comparison ignores that resolution, so `~/.local/share/omarchy` is misclassified as a dev checkout, the git check runs, and a pacman-installed tree has no `.git`. Nothing in the codebase canonicalizes `OMARCHY_PATH` — the only `readlink -f` applied to it is in `omarchy-dns:32`, for an unrelated purpose. ## Impact The session environment is **not** affected: `/usr/share/uwsm/env.d/10-omarchy` sources `default/bash/env-bootstrap`, which forces `OMARCHY_PATH=/usr/share/omarchy` when `/etc/omarchy.conf` is absent. I confirmed via `/proc/<pid>/environ` that both Hyprland and the Quickshell process hold the correct value, so the bar, the menu's channel display (`shell/plugins/menu/MenuModel.js`), and anything launched from the session are all fine. The bug is reachable only from a shell whose environment predates that session env or overrides it afterwards: - **A terminal opened before the upgrade**, in any shell — precisely the case the `:1017` comment describes. Persists until it is closed. - **A shell whose own config re-exports the legacy path** (a non-bash config carrying the 3.x-era `OMARCHY_PATH`). `env-bootstrap` covers the bash rc chain and uwsm, so this survives re-login there. Inside such a shell, verified on this machine with identical binaries and only the env var differing: | Command | stale `OMARCHY_PATH` | resolved | Consequence | |---|---|---|---| | `omarchy-update-dev` | **`Error: ... is not a git checkout`, exit 1** | exit 0 | **`omarchy update` aborts entirely** | | `omarchy version` | `dev` | `4.0.0-1` | version unreportable from that shell | | `omarchy-channel-current` | `dev` | `stable` | wrong channel from that shell | | `omarchy-update-available` | up to date | up to date | benign, degrades gracefully | The aborted update is the consequence that matters; the misreports are confined to the affected shell and never reach the UI. `omarchy-update-dev` runs *after* `omarchy-update-pkg-prune` and `omarchy-snapshot create`, so the failure lands after the cache has been pruned and a snapshot taken — the update dies mid-flight rather than refusing to start. ## Steps to reproduce No unusual configuration required — a stale exported value is enough: ```bash env OMARCHY_PATH="$HOME/.local/share/omarchy" bash -c 'omarchy-update-dev; echo "exit=$?"' # Error: OMARCHY_PATH is not a git checkout: /home/<user>/.local/share/omarchy # exit=1 env OMARCHY_PATH="$HOME/.local/share/omarchy" bash -c 'omarchy version' # dev (expected: 4.0.0-1) readlink -f ~/.local/share/omarchy # /usr/share/omarchy <- the shim is working; the comparison ignores it ``` **This is not shell-specific** — it reproduces under plain `bash`, as above, in any terminal still carrying the pre-upgrade export. In my case the login shell is fish, and a `config.fish` export carried the 3.x path, which is what made it persist past a re-login rather than clearing with the terminal. To be clear, the upgrader migrating `~/.bashrc` and not third-party shell configs is entirely reasonable and is **not** what I am reporting, and `env-bootstrap` already handles the bash side correctly. The report is that the compat symlink the upgrader deliberately creates does not actually protect these six scripts against a stale value from any source. ## What was expected `OMARCHY_PATH` pointing at a symlink that resolves to `/usr/share/omarchy` should be treated as the package-backed install it is, honoring the upgrader's shim. ## Suggested fix Resolve before comparing: ```bash [[ $(readlink -f "$OMARCHY_PATH") != /usr/share/omarchy ]] || exit 0 ``` Costs nothing for genuine dev checkouts, which are not symlinked to the package tree. Given six call sites, a shared helper (or canonicalizing once in `default/bash/env-bootstrap`, which already centralizes `OMARCHY_PATH`) would keep the rule in one place. ## System - Omarchy 4.0.0-1 (`omarchy` and `omarchy-settings`), upgraded from 3.8.2 via `omarchy-upgrade-to-quattro` - Channel: stable - Hyprland 0.56.2 - Kernel 7.1.8-arch1-3 --- Filed by Claude Opus 5 via Claude Code.
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:43 UTC