Omahub
← All plugins
M

Keycap

by MaxMad75

Shows the Hyprland keybinding next to every app and setting in the Omarchy menu, so keybinds, keybindings, shortcuts and hotkeys are visible where you already look.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
61539b6
Scanned
1 month ago

No potentially dangerous behavior detected in the analyzed commit.

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
61539b6
Reviewed
1 month ago

The plugin is a fork of the Omarchy menu that adds keybinding hints. It reads local configuration and desktop entries, runs standard system tools, and writes only to a private cache with careful open flags. No malicious behavior, obfuscation, or destructive actions were found.

  • The plugin replaces the Omarchy menu, which is a significant change but clearly documented and expected.
  • The resolver extracts a shim from an installed script using awk, which could break if upstream changes, but this is not a security issue.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/MaxMad75/omarchy-keycap --enable
Productivity #Hyprland #quickshell #launcher

Keycap

Your keybindings, where you already look.

Omarchy ships a keybindings list behind Super+K, but that is a place you have to go. Keycap puts the answer in the menu you open anyway: press Super+Space, type three letters, and the shortcut is sitting next to the name.

Keycap showing keybinding hints in the Omarchy menu

Chromium              Super+Shift+B
Screenshot                    Print
Capture                Super+Ctrl+C
Apps                Super+Alt+Space

You stop looking things up, and you start noticing the shortcut for the thing you just clicked. That is how a keybinding gets learned.

What it covers

Applications, settings panels, submenus and one-shot actions — anything the Omarchy menu lists that a Hyprland binding actually reaches. Rows without a binding simply show nothing.

How it finds them

hyprctl binds reports every Omarchy binding as dispatcher __lua with an opaque argument, so the command behind a key is not visible there. Keycap recovers it the way omarchy-menu-keybindings does: bin/keycap-resolve replays ~/.config/hypr/hyprland.lua through a shim that records nothing but the bind calls. The shim is lifted out of the installed Omarchy script at run time rather than copied, so it keeps tracking upstream.

Each binding is then matched against the row it belongs to, most precise first:

Map Keyed on Reaches
byApp desktop entry id Chromium, Files, Docker, YouTube, WhatsApp, Google Maps
byCmd the exact command the row runs Screenshot, Transcode, Lock, Keybindings
byRoute the submenu a binding opens Apps, System, Capture, Theme, Share
byName the binding's own description everything else, by name

Web apps match on the URL their .desktop entry and their binding share. omarchy-launch-browser and omarchy-launch-terminal are resolved through xdg-settings and xdg-terminals.list, so the hint lands on Chromium and foot rather than on a row named "Browser".

Run the resolver on its own to see what Keycap will show:

~/.config/omarchy/plugins/io.github.maxmad75.keycap/bin/keycap-resolve | jq

First run takes about a second and a half. After that it answers in ~50 ms from a cache keyed on hyprctl binds plus your application directories, so a rebind shows up the next time you open the menu.

Install

omarchy plugin add https://github.com/MaxMad75/omarchy-keycap.git --enable
omarchy restart shell

The restart is required, not optional. Bar widgets hot-reload; a menu plugin does not — the shell logs "Local plugin changed, reloading" and keeps running the old code until it restarts.

What enabling changes

Keycap is a fork of Omarchy's own menu plugin and declares omarchy.clonedFrom: "omarchy.menu". Enabling it therefore does what any Omarchy clone does: omarchy.menu moves to disabledPlugins in ~/.config/omarchy/shell.json, and Super+Space routes here instead. Nothing else in your configuration is touched, and Keycap itself never writes to it.

Remove

omarchy plugin remove io.github.maxmad75.keycap
omarchy restart shell

That restores omarchy.menu and your original Super+Space. The only other thing Keycap leaves behind is its cache:

rm -f ~/.cache/omarchy/keycap-*.json

Know before you install

Keycap replaces the Omarchy menu with a fork of it. The menu is roughly 1,400 lines of Quickshell QML, and this repository carries a copy taken from Omarchy 4.0.0. Improvements Omarchy makes to its own menu will not reach you while Keycap is enabled, and after a large omarchy update the fork can drift. If the menu misbehaves after an update, diff it against /usr/share/omarchy/shell/plugins/menu/ before assuming Keycap is at fault — or remove Keycap, which restores the shipped menu in one command.

This is the honest cost of the feature: Omarchy's menu rows have no extension point for a trailing column, so there is no way to add one without forking.

How it handles its own inputs

Everything Keycap reads is local, but the shell process it runs inside is long-lived and shared, so local input is still treated as untrusted:

  • All cache I/O goes through bin/keycap-cache.py, because the guarantees needed here are open flags the shell cannot express. Reading opens with O_NOFOLLOW|O_NONBLOCK and decides everything from fstat on that one descriptor — regular file, owned by this user, within 1 MiB, parsing to the expected shape. Checking a pathname and opening it afterwards would leave a window in which the name can be swapped for a symlink; there is no window here, because the kernel refuses the symlink at open time. Writing creates its temporary with O_CREAT|O_EXCL|O_NOFOLLOW and holds that descriptor through write, verification and fsync without ever reopening the name, then publishes with os.replace, which swaps the directory entry atomically and replaces a symlink at the destination rather than following it.
  • The cache lives in ~/.cache/omarchy/keycap/, created 0700 and verified by lstat to be a directory this user owns with no group or other access. That is defence in depth; the open flags above are the actual control.
  • The whole resolve runs under a 20 s deadline and every external step under 8 s, so a wedged hyprctl cannot stall the menu.
  • Bindings, desktop entries, matches and total output are capped, and Menu.qml enforces its own 512 KiB ceiling on what it will accumulate from the resolver.

Any of these limits being hit yields an empty result, and the menu renders exactly as it did before.

Requirements

Omarchy 4 (Quattro) with omarchy-shell. The resolver uses hyprctl, lua, jq, xdg-settings and omarchy-menu-keybindings, and the cache helper uses python3 — all of which a stock Omarchy install already has (uwsm, which launches everything on the desktop, depends on python itself). No network access, no other external dependencies. If python3 is missing the cache is skipped and every menu open pays the full resolve; if anything else is missing, the resolver returns empty maps and the menu renders exactly as it did before.

License

MIT — see LICENSE. Menu.qml, MenuModel.js and BarWidget.qml are derived from the Omarchy menu plugin, Copyright (c) David Heinemeier Hansson, also MIT; see NOTICE.