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

Orphan inotifywait processes accumulate watching ~/.config/omarchy/plugins

Reported by zhainan99 · filed Sep 7, 2026Closed upstream on 2026-09-21 by bjarneo via an automated message, as a duplicate of #7150 (R-1759). 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

Orphan inotifywait processes accumulate watching ~/.config/omarchy/pluginsrevision 1 · captured 2026-10-04 12:10 UTC via poll

Orphan inotifywait processes accumulate watching ~/.config/omarchy/plugins

Summary

Quickshell's PluginRegistry.qml spawns an inotifywait -m -r watcher on
~/.config/omarchy/plugins to hot-reload local plugins. Over time the number
of such watcher processes grows unbounded, and stale ones become orphans
reparented to systemd --user, never terminating.

Steps to reproduce

On an installed Omarchy system, over a session (especially after
omarchy restart shell / re-login, or plugin file changes that trigger the
watcher restart path), count the watchers:

ps -eo pid,ppid,cmd | grep "inotifywait.*omarchy/plugins"

Observed: 19-20 concurrent `inotifywait -m -r -q -e close_write,create,delete,move
--format %w%f /home/zhainan/.config/omarchy/plugins` processes, all but one with
PPID = systemd --user (orphaned, original parent gone).

Expected behavior

Exactly one live watcher per running Quickshell instance; it should be
terminated together with the shell, and never accumulate across restarts.

Evidence / Root cause

/usr/share/omarchy/shell/services/PluginRegistry.qml

property Process localPluginWatcher: Process {
  command: ["inotifywait", "-m", "-r", "-q", "-e",
            "close_write,create,delete,move", "--format", "%w%f",
            registry.pluginsDir]
  onExited: localPluginWatcherRestart.restart()
}
property Timer localPluginWatcherRestart: Timer {
  interval: 1000
  onTriggered: localPluginWatcher.running = true
}

The running = true re-assert path (and shell restart) starts a new
inotifywait without stopping the previous one. On Quickshell exit the child
inotifywait is not reaped (it becomes a systemd --user orphan), so each
shell lifecycle leaks one watcher. With restarts triggered by file events, the
leak is much faster (observed ~1/minute while plugin dir was being touched).

Impact

  • 20 resident processes, each holding an inotify watch on the whole

~/.config/omarchy/plugins tree (recursive), consuming inotify watch slots
and file descriptors.
- With fs.inotify.max_user_watches tuning, exhaustion of watch slots can
break other inotify-dependent tools (editors, file watchers, vim, tmux).
- Terminating the orphan watchers does NOT stop the leak; the underlying
process lifecycle is the bug.

Workaround

# kill only orphans (parent = systemd --user)
pkill -P $(pgrep -f "systemd --user" | head -1) -f "inotifywait.*omarchy/plugins"

Note: pkill -P <systemd-user-pid> is fragile; safer is to match PPID.

System

  • Omarchy: 4.0.2-1 (pacman omarchy)
  • Kernel: Linux 7.1.9-arch1-2
  • CPU: Intel(R) N100 (4 cores)
  • GPU: Intel Alder Lake-N UHD Graphics
  • Compositor: Hyprland (Wayland)

Suggested fix

  • Use a single long-lived watcher and stop it (running = false) before

re-asserting, or bind the watcher lifetime to the Process/shell lifecycle
so Quickshell kills it on exit (e.g. a Process that is part of the shell
process group / KillMode).
- Stop prior inotifywait (via the Process handle's running = false) in
onExited, or use a singleInstance/dedupe guard so only one process per
plugin dir exists.

View raw text
# Orphan `inotifywait` processes accumulate watching ~/.config/omarchy/plugins

## Summary
Quickshell's `PluginRegistry.qml` spawns an `inotifywait -m -r` watcher on
`~/.config/omarchy/plugins` to hot-reload local plugins. Over time the number
of such watcher processes grows unbounded, and stale ones become orphans
reparented to `systemd --user`, never terminating.

## Steps to reproduce
On an installed Omarchy system, over a session (especially after
`omarchy restart shell` / re-login, or plugin file changes that trigger the
watcher restart path), count the watchers:

```bash
ps -eo pid,ppid,cmd | grep "inotifywait.*omarchy/plugins"
```

Observed: 19-20 concurrent `inotifywait -m -r -q -e close_write,create,delete,move
--format %w%f /home/zhainan/.config/omarchy/plugins` processes, all but one with
PPID = `systemd --user` (orphaned, original parent gone).

## Expected behavior
Exactly one live watcher per running Quickshell instance; it should be
terminated together with the shell, and never accumulate across restarts.

## Evidence / Root cause
`/usr/share/omarchy/shell/services/PluginRegistry.qml`
```qml
property Process localPluginWatcher: Process {
  command: ["inotifywait", "-m", "-r", "-q", "-e",
            "close_write,create,delete,move", "--format", "%w%f",
            registry.pluginsDir]
  onExited: localPluginWatcherRestart.restart()
}
property Timer localPluginWatcherRestart: Timer {
  interval: 1000
  onTriggered: localPluginWatcher.running = true
}
```
The `running = true` re-assert path (and shell restart) starts a new
`inotifywait` without stopping the previous one. On Quickshell exit the child
`inotifywait` is not reaped (it becomes a `systemd --user` orphan), so each
shell lifecycle leaks one watcher. With restarts triggered by file events, the
leak is much faster (observed ~1/minute while plugin dir was being touched).

## Impact
- 20 resident processes, each holding an inotify watch on the whole
  `~/.config/omarchy/plugins` tree (recursive), consuming inotify watch slots
  and file descriptors.
- With `fs.inotify.max_user_watches` tuning, exhaustion of watch slots can
  break other inotify-dependent tools (editors, file watchers, `vim`, `tmux`).
- Terminating the orphan watchers does NOT stop the leak; the underlying
  process lifecycle is the bug.

## Workaround
```bash
# kill only orphans (parent = systemd --user)
pkill -P $(pgrep -f "systemd --user" | head -1) -f "inotifywait.*omarchy/plugins"
```
Note: `pkill -P <systemd-user-pid>` is fragile; safer is to match PPID.

## System
- Omarchy: 4.0.2-1 (pacman `omarchy`)
- Kernel: Linux 7.1.9-arch1-2
- CPU: Intel(R) N100 (4 cores)
- GPU: Intel Alder Lake-N UHD Graphics
- Compositor: Hyprland (Wayland)

## Suggested fix
- Use a single long-lived watcher and stop it (`running = false`) before
  re-asserting, or bind the watcher lifetime to the `Process`/shell lifecycle
  so Quickshell kills it on exit (e.g. a `Process` that is part of the shell
  process group / `KillMode`).
- Stop prior `inotifywait` (via the `Process` handle's `running = false`) in
  `onExited`, or use a `singleInstance`/dedupe guard so only one process per
  plugin dir exists.

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.