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.
hyprland.md skill: document force-quitting apps on window close (close vs terminate)
Reported by BSTail · filed Sep 19, 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
Request
Add a section to default/agents/skills/omarchy/hyprland.md covering closing a window vs terminating a program, with a verified recipe for force-quitting an app when its window is closed (e.g. flatpak apps like Keet that keep running in the background after their window closes).
Why
The purpose of this is to allow the user to select particular applications, and be able to close them or terminate them. The default being close the window is good for most programs, but some programs definitely need to be shut down manually or as needed.
Some apps ignore the compositor's close request and survive as background processes. Users who want "closing this app's window must quit it" currently have to figure out the wiring themselves. This was implemented and verified end-to-end on a live system (Hyprland 0.56.2, Omarchy Lua config API) and is worth documenting so agents can do it in one shot for any app.
Verified findings (Hyprland 0.56)
- `hyprctl dispatch <legacy-name>` no longer works. Names like
closewindoworkillactivefail: hyprctl wraps the argument into a Lua call that expects anHL.Dispatcherobject and errors withexpected a dispatcher (e.g. hl.dsp.window.close()). The working form is:
hyprctl dispatch 'hl.dsp.window.close()'- The WM class is not always the flatpak app ID. Keet's window reports
class: keetwhile its app ID isio.keet.Keet. The class must be verified live before matching (hyprctl activewindow -j). - Order matters: read the active window's class first, dispatch close second, kill third. Killing first moves focus, and a later close could hit the wrong window.
flatpak kill <app-id>terminates every process of the app; its windows disappear when the socket dies.- Script edits need no reload (the binding re-executes the file each press); binding changes do (
hyprctl reload+hyprctl configerrors).
Proposed section text
Ready to paste after "Window Rules" in default/agents/skills/omarchy/hyprland.md:
## Closing Windows vs Terminating Programs
Closing a window sends a close request; some apps ignore it and keep running in the background. When a user wants closing an app's window to fully quit it, wire that into the close keybinding — the compositor will not force-quit clients.
**Verified on Hyprland 0.56:**
- `hyprctl dispatch <legacy-name>` no longer works (`closewindow`, `killactive`). hyprctl wraps the argument in a Lua call that expects an `HL.Dispatcher` object and fails with "expected a dispatcher (e.g. hl.dsp.window.close())". Use:hyprctl dispatch 'hl.dsp.window.close()'
- The WM class is not always the flatpak app ID (Keet reports `class: keet`, app ID `io.keet.Keet`). Verify live before matching:hyprctl activewindow -j | jq '{class, initialClass, title, pid}'
- `flatpak kill <app-id>` terminates every process of the app; its windows disappear when the socket dies.
**Recipe — force-quit an app when its window is closed (SUPER+W):**
~/.config/hypr/scripts/close-window.sh (chmod +x)
#!/usr/bin/env bash
class="$(hyprctl activewindow -j 2>/dev/null | jq -r '.class // empty')"
hyprctl dispatch 'hl.dsp.window.close()'
case "$class" in
keet) flatpak kill io.keet.Keet ;;
esac
-- ~/.config/hypr/bindings.lua (replaces the default close binding)
o.rebind("SUPER + W", "Close window", "/home/omarchy/.config/hypr/scripts/close-window.sh")
Order matters: read the active class first, dispatch close second, kill third — killing first moves focus and a later close could hit the wrong window. Script edits need no reload; binding changes do (`hyprctl reload` + `hyprctl configerrors`). Extend to more apps by adding `case` branches (match on the WM class, not the app ID).
**Safe live test without touching user windows:** spawn a disposable terminal, identify it by pid, and dispatch close only when it is confirmed active:
setsid foot >/dev/null 2>&1 < /dev/null & sleep 3
PID=$(hyprctl clients -j | jq '[.[] | select(.class == "foot") .pid] | max')
ACTIVE=$(hyprctl activewindow -j | jq .pid)
[ "$PID" = "$ACTIVE" ] && hyprctl dispatch 'hl.dsp.window.close()'
Never dispatch close against an unverified focus target.Notes
- Tested live: the recipe closed a normal window correctly and fully terminated Keet (window + all processes) on SUPER+W.
- Happy to submit this as a PR instead if maintainers prefer — the section text above is final and paste-ready.
View raw text
## Request
Add a section to `default/agents/skills/omarchy/hyprland.md` covering **closing a window vs terminating a program**, with a verified recipe for force-quitting an app when its window is closed (e.g. flatpak apps like Keet that keep running in the background after their window closes).
## Why
The **purpose of this is to allow the user to select particular applications, and be able to close them or terminate them**. The default being close the window is good for most programs, but some programs definitely need to be shut down manually or as needed.
Some apps ignore the compositor's close request and survive as background processes. Users who want "closing this app's window must quit it" currently have to figure out the wiring themselves. This was implemented and verified end-to-end on a live system (Hyprland 0.56.2, Omarchy Lua config API) and is worth documenting so agents can do it in one shot for any app.
## Verified findings (Hyprland 0.56)
1. **`hyprctl dispatch <legacy-name>` no longer works.** Names like `closewindow` or `killactive` fail: hyprctl wraps the argument into a Lua call that expects an `HL.Dispatcher` object and errors with `expected a dispatcher (e.g. hl.dsp.window.close())`. The working form is:
```bash
hyprctl dispatch 'hl.dsp.window.close()'
```
2. **The WM class is not always the flatpak app ID.** Keet's window reports `class: keet` while its app ID is `io.keet.Keet`. The class must be verified live before matching (`hyprctl activewindow -j`).
3. **Order matters:** read the active window's class first, dispatch close second, kill third. Killing first moves focus, and a later close could hit the wrong window.
4. `flatpak kill <app-id>` terminates every process of the app; its windows disappear when the socket dies.
5. Script edits need no reload (the binding re-executes the file each press); binding changes do (`hyprctl reload` + `hyprctl configerrors`).
## Proposed section text
Ready to paste after "Window Rules" in `default/agents/skills/omarchy/hyprland.md`:
````markdown
## Closing Windows vs Terminating Programs
Closing a window sends a close request; some apps ignore it and keep running in the background. When a user wants closing an app's window to fully quit it, wire that into the close keybinding — the compositor will not force-quit clients.
**Verified on Hyprland 0.56:**
- `hyprctl dispatch <legacy-name>` no longer works (`closewindow`, `killactive`). hyprctl wraps the argument in a Lua call that expects an `HL.Dispatcher` object and fails with "expected a dispatcher (e.g. hl.dsp.window.close())". Use:
```bash
hyprctl dispatch 'hl.dsp.window.close()'
```
- The WM class is not always the flatpak app ID (Keet reports `class: keet`, app ID `io.keet.Keet`). Verify live before matching:
```bash
hyprctl activewindow -j | jq '{class, initialClass, title, pid}'
```
- `flatpak kill <app-id>` terminates every process of the app; its windows disappear when the socket dies.
**Recipe — force-quit an app when its window is closed (SUPER+W):**
```bash
# ~/.config/hypr/scripts/close-window.sh (chmod +x)
#!/usr/bin/env bash
class="$(hyprctl activewindow -j 2>/dev/null | jq -r '.class // empty')"
hyprctl dispatch 'hl.dsp.window.close()'
case "$class" in
keet) flatpak kill io.keet.Keet ;;
esac
```
```lua
-- ~/.config/hypr/bindings.lua (replaces the default close binding)
o.rebind("SUPER + W", "Close window", "/home/omarchy/.config/hypr/scripts/close-window.sh")
```
Order matters: read the active class first, dispatch close second, kill third — killing first moves focus and a later close could hit the wrong window. Script edits need no reload; binding changes do (`hyprctl reload` + `hyprctl configerrors`). Extend to more apps by adding `case` branches (match on the WM class, not the app ID).
**Safe live test without touching user windows:** spawn a disposable terminal, identify it by pid, and dispatch close only when it is confirmed active:
```bash
setsid foot >/dev/null 2>&1 < /dev/null & sleep 3
PID=$(hyprctl clients -j | jq '[.[] | select(.class == "foot") .pid] | max')
ACTIVE=$(hyprctl activewindow -j | jq .pid)
[ "$PID" = "$ACTIVE" ] && hyprctl dispatch 'hl.dsp.window.close()'
```
Never dispatch close against an unverified focus target.
````
## Notes
- Tested live: the recipe closed a normal window correctly and fully terminated Keet (window + all processes) on SUPER+W.
- Happy to submit this as a PR instead if maintainers prefer — the section text above is final and paste-ready.
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 15:51 UTC