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.
mise wrappers still exec-loop when mise x falls back to a PATH lookup (residual case of #6349)
Reported by pedrosekine · filed Aug 17, 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
Context / prior art
#6349 reported that the generated wrappers exec-loop, and #6350 fixed the
PATH-ordering case by moving the template to exec mise x "$package" -- "$bin" "$@".
@padyfec then documented a residual loop in a follow-up comment on that
(now closed) issue: when a tool's mise install dir exists but holds no binary,mise x has no bin dir to prepend, falls back to a plain PATH lookup, finds the
wrapper in ~/.local/bin, and re-enters it forever.
That residual case doesn't appear to be tracked anywhere open, so this issue is
to track it — and to add a second, distinct trigger for the same structural
flaw.
What's different here
padyfec's trigger is a broken/empty install. Mine isn't: every install dir is
fully populated and every tool runs correctly from an interactive shell.
$ opencode --version
1.18.18
$ mise which opencode
/home/pms/.local/share/mise/installs/opencode/latest/opencodeYet every wrapper exec-loops when the tool is spawned by a GUI application —
in my case T3 Code (Electron), whose server sidecar shells out toopencode --version as a provider health check.
Symptom
Not a crash, and not obviously a loop — exec keeps it inside a single PID, so
it presents as one wedged process pinning a core:
$ ps -o pid,%cpu,etime,cmd -p 2692953
PID %CPU ELAPSED CMD
2692953 42.2 12:57 /bin/bash /home/pms/.local/bin/opencode --versionThat is a single opencode --version still running 13 minutes later, `wchan:
do_wait, continuously re-spawning mise use`. Every provider in the app's UI
reported "provider status has not been checked in this session yet", because no
health check ever returned. Host accounting showed the app consuming **1h 4min of
CPU over 54min of wall clock**.
Confirmation
The bin name resolves back to the wrapper rather than the installed binary:
$ mise x opencode -- sh -c 'command -v opencode'
/home/pms/.local/bin/opencode # the wrapper, not the installed binaryA depth-counted replica of the stock wrapper, run under the app's environment
with the wrapper's directory first on PATH. Note the constant PID — this is
the exec loop, not repeated forking:
depth=1 pid=3705214
depth=2 pid=3705214
depth=3 pid=3705214
depth=4 pid=3705214 <- hard stop I added; would otherwise continueReproduced identically with codex, claude, gh, gemini and grok — every
wrapped tool, since they share the template.
Honest scoping
I could not reduce this to a minimal repro. It reproduces reliably under the
spawning app's full environment (191 vars, captured from /proc/<pid>/environ)
with the wrapper directory first on PATH, but not in a bare env -i shell
with the same PATH ordering. So something in that environment decides whethermise x prepends the install bin dir — consistent with both #6349's "mise PATH
hook isn't active" analysis and @padyfec's "no bin dirs to prepend" analysis.
The common factor across all three triggers is structural: the wrapper execs a
bare name that it itself shadows on PATH, so any condition that makes mise x
fall back to a PATH lookup turns into an infinite loop rather than an error.
Suggested fix
@padyfec's hardening in #6349 addresses this directly — resolve the real binary
up front, exec the absolute path, and never fall back to a bare-name lookup:
BIN=$(mise which "$bin" 2>/dev/null)
[ -x "$BIN" ] || { mise install -f "$package@latest" >/dev/null 2>&1 || true; BIN=$(mise which "$bin" 2>/dev/null); }
[ -x "$BIN" ] || { echo "$command: mise package '$package' provides no executable '$bin'" >&2; exit 1; }
exec "$BIN" "$@"If a PATH-based fallback is kept for any reason, dropping the wrapper's own
directory from PATH first makes re-entry structurally impossible:
__self_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
PATH=$(printf '%s' "$PATH" | tr ':' '\n' | grep -vxF "$__self_dir" | paste -sd: -)I'm running the mise which form locally across all 13 wrappers. Under the same
environment that previously hung forever, the checks now complete in 66–416 ms
with clean stdout.
Environment
Omarchy 4.0.0-1 · mise 2026.8.3 · opencode 1.18.18 · codex 0.147.0 ·
claude 2.1.233 · gh 2.97.0 · T3 Code 0.0.33 (Electron) · Linux 7.1.8-arch1-3
View raw text
### Context / prior art
#6349 reported that the generated wrappers exec-loop, and #6350 fixed the
PATH-ordering case by moving the template to `exec mise x "$package" -- "$bin" "$@"`.
@padyfec then documented a **residual** loop in a follow-up comment on that
(now closed) issue: when a tool's mise install dir exists but holds no binary,
`mise x` has no bin dir to prepend, falls back to a plain PATH lookup, finds the
wrapper in `~/.local/bin`, and re-enters it forever.
That residual case doesn't appear to be tracked anywhere open, so this issue is
to track it — and to add a **second, distinct trigger** for the same structural
flaw.
### What's different here
padyfec's trigger is a broken/empty install. Mine isn't: every install dir is
fully populated and every tool runs correctly from an interactive shell.
```console
$ opencode --version
1.18.18
$ mise which opencode
/home/pms/.local/share/mise/installs/opencode/latest/opencode
```
Yet **every** wrapper exec-loops when the tool is spawned by a GUI application —
in my case T3 Code (Electron), whose server sidecar shells out to
`opencode --version` as a provider health check.
### Symptom
Not a crash, and not obviously a loop — `exec` keeps it inside a single PID, so
it presents as one wedged process pinning a core:
```console
$ ps -o pid,%cpu,etime,cmd -p 2692953
PID %CPU ELAPSED CMD
2692953 42.2 12:57 /bin/bash /home/pms/.local/bin/opencode --version
```
That is a single `opencode --version` still running 13 minutes later, `wchan:
do_wait`, continuously re-spawning `mise use`. Every provider in the app's UI
reported *"provider status has not been checked in this session yet"*, because no
health check ever returned. Host accounting showed the app consuming **1h 4min of
CPU over 54min of wall clock**.
### Confirmation
The bin name resolves back to the wrapper rather than the installed binary:
```console
$ mise x opencode -- sh -c 'command -v opencode'
/home/pms/.local/bin/opencode # the wrapper, not the installed binary
```
A depth-counted replica of the stock wrapper, run under the app's environment
with the wrapper's directory first on PATH. Note the **constant PID** — this is
the `exec` loop, not repeated forking:
```
depth=1 pid=3705214
depth=2 pid=3705214
depth=3 pid=3705214
depth=4 pid=3705214 <- hard stop I added; would otherwise continue
```
Reproduced identically with `codex`, `claude`, `gh`, `gemini` and `grok` — every
wrapped tool, since they share the template.
### Honest scoping
I could not reduce this to a minimal repro. It reproduces reliably under the
spawning app's full environment (191 vars, captured from `/proc/<pid>/environ`)
with the wrapper directory first on PATH, but **not** in a bare `env -i` shell
with the same PATH ordering. So something in that environment decides whether
`mise x` prepends the install bin dir — consistent with both #6349's "mise PATH
hook isn't active" analysis and @padyfec's "no bin dirs to prepend" analysis.
The common factor across all three triggers is structural: the wrapper execs a
**bare name that it itself shadows on PATH**, so any condition that makes `mise x`
fall back to a PATH lookup turns into an infinite loop rather than an error.
### Suggested fix
@padyfec's hardening in #6349 addresses this directly — resolve the real binary
up front, exec the absolute path, and never fall back to a bare-name lookup:
```bash
BIN=$(mise which "$bin" 2>/dev/null)
[ -x "$BIN" ] || { mise install -f "$package@latest" >/dev/null 2>&1 || true; BIN=$(mise which "$bin" 2>/dev/null); }
[ -x "$BIN" ] || { echo "$command: mise package '$package' provides no executable '$bin'" >&2; exit 1; }
exec "$BIN" "$@"
```
If a PATH-based fallback is kept for any reason, dropping the wrapper's own
directory from PATH first makes re-entry structurally impossible:
```bash
__self_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
PATH=$(printf '%s' "$PATH" | tr ':' '\n' | grep -vxF "$__self_dir" | paste -sd: -)
```
I'm running the `mise which` form locally across all 13 wrappers. Under the same
environment that previously hung forever, the checks now complete in 66–416 ms
with clean stdout.
### Environment
Omarchy 4.0.0-1 · mise 2026.8.3 · opencode 1.18.18 · codex 0.147.0 ·
claude 2.1.233 · gh 2.97.0 · T3 Code 0.0.33 (Electron) · Linux 7.1.8-arch1-3
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:31 UTC