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-808GitHub issuePublicReceived

Regression (4.0.2→4.0.3): publicPluginManifest() strips __sourceDir, breaking third-party plugins that locate their own files

Reported by redglover · filed Sep 8, 2026Closed upstream on 2026-10-03 by the merge of PR #11925 (closed by spencerbull). GitHub close reason: completed.

Received and recorded verbatim. Nothing has been checked yet.

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?
Not yet mapped to any requirement or component.
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?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.

Original report

Regression (4.0.2→4.0.3): publicPluginManifest() strips __sourceDir, breaking third-party plugins that locate their own filesrevision 1 · captured 2026-09-28 21:23 UTC via poll

What happened

Upgrading from Omarchy 4.0.2 to 4.0.3 broke the third-party Omarchy Spotify
plugin (quickshell.spotify). Every helper script the plugin spawns now runs
with a broken path, e.g.:

omarchy-shell[1314]: WARN: Process failed to start, likely because the binary
could not be found. Command: QList("/scripts/keyring-store.sh", "d420a117…")

The path should have been
/home/<user>/.config/omarchy/plugins/quickshell.spotify/scripts/keyring-store.sh.
The /…plugins/quickshell.spotify prefix is gone — the plugin resolved it from
manifest.__sourceDir, which is now empty.

User-visible effects for that plugin: fresh login broken (pkce.sh), OAuth
refresh-token persistence broken (keyring-store.sh — silently drops the
rotated token, so the session dies on next restart), local playback broken
(configure-spotifyd.sh, playback-runtime.sh), and Spotify Connect device
control broken (spotify-connect-device.py).

Root cause

4.0.3 added publicPluginManifest() in /usr/share/omarchy/shell/shell.qml
and routed the plugin-facing manifest through it:

// shell.qml (4.0.3-1), lines 316-324
function publicPluginManifest(manifest) {
  if (!manifest) return null
  if (manifest.__isFirstParty) return manifest
  var copy = JSON.parse(JSON.stringify(manifest))
  delete copy.__sourceDir          // <-- line 320
  delete copy.__isFirstParty
  delete copy.__hostCapabilities
  return copy
}

It is now applied at every point where a third-party plugin receives its
manifest — services (line 930), scoped registry API (754), bar config (222),
panels (1343), rescans (977, 983), etc.

In 4.0.2 the raw manifest, including __sourceDir, was handed straight to the
plugin:

// shell.qml (4.0.2-1), line 307
if ("manifest" in inst) inst.manifest = manifest

So under 4.0.2 a third-party plugin could read manifest.__sourceDir to find
its own directory (needed to exec bundled scripts, read bundled assets, etc.).
Under 4.0.3 there is no supported way for a non-first-party plugin to learn
its own install path:

  • manifest.__sourceDir — deleted by publicPluginManifest()
  • pluginRegistry.installedPlugins[id] (via PluginRegistryApi.qml) — returns

the same sanitized manifest
- entryPointUrl() — only resolves declared entry points, and
PluginRegistryApi.entryPointUrl() requires passing back a manifest whose
id matches, but gives no directory

Note shell.qml:1410 still stamps the real __sourceDir into the **bar
widget** metadata (meta.sourceDir), so the information is available to the
host — it is just withheld from the plugin's service/panel components, which is
where scripts actually get spawned.

Expected

A plugin should have a supported, documented way to resolve its own install
directory. Options:

  1. Keep exposing __sourceDir (or a renamed sourceDir) on the plugin-facing

manifest — it is not sensitive; it is always
~/.config/omarchy/plugins/<id> (or the first-party dir), which the plugin
can already guess.
2. Or add it to the shell API handed to plugins (e.g. shell.pluginDir /
shell.sourceDir), the way meta.sourceDir is already passed to widgets.
3. Or document Qt.resolvedUrl(".") from a component file as the blessed
approach and note the manifest no longer carries a path.

If the removal was a deliberate security boundary, a note in the 4.0.3
migration/changelog plus a plugin-API doc update would have caught this before
release. Third-party plugins other than Omarchy Spotify that bundle scripts or
assets are likely affected too.

Related: #10661 is the same class of bug — third-party plugin manifests being
mangled before the plugin sees them (there, array types lost through the panel
Instantiator).

Steps to reproduce

  1. On Omarchy 4.0.2, install a third-party plugin that reads

manifest.__sourceDir (e.g. `omarchy plugin add
https://github.com/stappmus/Omarchy-Spotify.git --enable`) and confirm it
works.
2. omarchy update to 4.0.3, omarchy restart shell.
3. Open the plugin. Its bundled scripts fail with "binary could not be found"
and paths like /scripts/foo.sh.

Workaround (plugin side)

Patch the plugin to fall back to Qt.resolvedUrl(".") when __sourceDir is
absent. Filed separately against the plugin:
https://github.com/stappmus/Omarchy-Spotify/issues/69

System details

  • Omarchy: 4.0.2-1 → 4.0.3-1 (regression introduced by the upgrade)
  • Kernel: 6.x (Arch), x86_64
  • CPU: Intel Core i7-9750H
  • GPU: Intel UHD 630 + NVIDIA GTX 1660 Ti Mobile
  • quickshell 0.3.1-1, hyprland 0.56.2-2
  • Plugin: stappmus/Omarchy-Spotify @ e6c9f9f (manifest version 1.0.4)
View raw text
## What happened

Upgrading from Omarchy 4.0.2 to 4.0.3 broke the third-party **Omarchy Spotify**
plugin (`quickshell.spotify`). Every helper script the plugin spawns now runs
with a broken path, e.g.:

```
omarchy-shell[1314]: WARN: Process failed to start, likely because the binary
could not be found. Command: QList("/scripts/keyring-store.sh", "d420a117…")
```

The path should have been
`/home/<user>/.config/omarchy/plugins/quickshell.spotify/scripts/keyring-store.sh`.
The `/…plugins/quickshell.spotify` prefix is gone — the plugin resolved it from
`manifest.__sourceDir`, which is now empty.

User-visible effects for that plugin: fresh login broken (`pkce.sh`), OAuth
refresh-token persistence broken (`keyring-store.sh` — silently drops the
rotated token, so the session dies on next restart), local playback broken
(`configure-spotifyd.sh`, `playback-runtime.sh`), and Spotify Connect device
control broken (`spotify-connect-device.py`).

## Root cause

4.0.3 added `publicPluginManifest()` in `/usr/share/omarchy/shell/shell.qml`
and routed the plugin-facing manifest through it:

```qml
// shell.qml (4.0.3-1), lines 316-324
function publicPluginManifest(manifest) {
  if (!manifest) return null
  if (manifest.__isFirstParty) return manifest
  var copy = JSON.parse(JSON.stringify(manifest))
  delete copy.__sourceDir          // <-- line 320
  delete copy.__isFirstParty
  delete copy.__hostCapabilities
  return copy
}
```

It is now applied at every point where a third-party plugin receives its
manifest — services (line 930), scoped registry API (754), bar config (222),
panels (1343), rescans (977, 983), etc.

In 4.0.2 the raw manifest, including `__sourceDir`, was handed straight to the
plugin:

```qml
// shell.qml (4.0.2-1), line 307
if ("manifest" in inst) inst.manifest = manifest
```

So under 4.0.2 a third-party plugin could read `manifest.__sourceDir` to find
its own directory (needed to exec bundled scripts, read bundled assets, etc.).
Under 4.0.3 there is **no supported way** for a non-first-party plugin to learn
its own install path:

- `manifest.__sourceDir` — deleted by `publicPluginManifest()`
- `pluginRegistry.installedPlugins[id]` (via `PluginRegistryApi.qml`) — returns
  the same sanitized manifest
- `entryPointUrl()` — only resolves declared entry points, and
  `PluginRegistryApi.entryPointUrl()` requires passing back a manifest whose
  `id` matches, but gives no directory

Note `shell.qml:1410` still stamps the real `__sourceDir` into the **bar
widget** metadata (`meta.sourceDir`), so the information is available to the
host — it is just withheld from the plugin's service/panel components, which is
where scripts actually get spawned.

## Expected

A plugin should have a supported, documented way to resolve its own install
directory. Options:

1. Keep exposing `__sourceDir` (or a renamed `sourceDir`) on the plugin-facing
   manifest — it is not sensitive; it is always
   `~/.config/omarchy/plugins/<id>` (or the first-party dir), which the plugin
   can already guess.
2. Or add it to the `shell` API handed to plugins (e.g. `shell.pluginDir` /
   `shell.sourceDir`), the way `meta.sourceDir` is already passed to widgets.
3. Or document `Qt.resolvedUrl(".")` from a component file as the blessed
   approach and note the manifest no longer carries a path.

If the removal was a deliberate security boundary, a note in the 4.0.3
migration/changelog plus a plugin-API doc update would have caught this before
release. Third-party plugins other than Omarchy Spotify that bundle scripts or
assets are likely affected too.

Related: #10661 is the same class of bug — third-party plugin manifests being
mangled before the plugin sees them (there, array types lost through the panel
Instantiator).

## Steps to reproduce

1. On Omarchy 4.0.2, install a third-party plugin that reads
   `manifest.__sourceDir` (e.g. `omarchy plugin add
   https://github.com/stappmus/Omarchy-Spotify.git --enable`) and confirm it
   works.
2. `omarchy update` to 4.0.3, `omarchy restart shell`.
3. Open the plugin. Its bundled scripts fail with "binary could not be found"
   and paths like `/scripts/foo.sh`.

## Workaround (plugin side)

Patch the plugin to fall back to `Qt.resolvedUrl(".")` when `__sourceDir` is
absent. Filed separately against the plugin:
https://github.com/stappmus/Omarchy-Spotify/issues/69

## System details

- Omarchy: 4.0.2-1 → **4.0.3-1** (regression introduced by the upgrade)
- Kernel: 6.x (Arch), x86_64
- CPU: Intel Core i7-9750H
- GPU: Intel UHD 630 + NVIDIA GTX 1660 Ti Mobile
- quickshell 0.3.1-1, hyprland 0.56.2-2
- Plugin: stappmus/Omarchy-Spotify @ e6c9f9f (manifest version 1.0.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.

No decision has been recorded yet.