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-331GitHub issuePublicDecided· Out of scope

hyprland.md skill: document force-quitting apps on window close (close vs terminate)

Reported by BSTail · filed Sep 19, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

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

hyprland.md skill: document force-quitting apps on window close (close vs terminate)revision 1 · captured 2026-09-28 21:23 UTC via poll

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:
   hyprctl dispatch 'hl.dsp.window.close()'
  1. 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).
  2. 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.
  3. flatpak kill <app-id> terminates every process of the app; its windows disappear when the socket dies.
  4. 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