Omahub
← All plugins
K

Omarchy Menu Calculator Plugin

by Koen Hendriks

Answers arithmetic typed into the Omarchy menu search field and copies the result on Enter

Security review

Review recommended · 2 findings

Deterministic scan — not a security guarantee

Medium
Risk level
Medium
Analyzed commit
2ffacdd
Scanned
3 weeks ago
  • medium eval Calculator.js:5

    Dynamic code execution via eval().

    eval(): the string comes straight from a
  • Docs eval README.md:86

    Dynamic code execution via eval().

    eval()`. The string comes straight out of a text field, and a parser that only

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
2ffacdd
Reviewed
3 weeks ago

The deterministic scan flagged eval() in the README and Calculator.js, but both are false positives: the README explicitly states the parser is not eval(), and Calculator.js is a hand-written tokenizer/parser with no eval call. The plugin replaces the stock menu with a transparent, well-documented implementation that only runs standard Omarchy commands (clipboard, notifications, gtk-launch) and read-only scans for icons and hidden entries. No obfuscation, persistence, or destructive behavior was found.

  • The plugin replaces the stock menu and uses a proxy shell object to inject an appLibrary; this is a hacky but transparent workaround for a host limitation, not a security issue.
  • The AppLibraryShim runs bash commands to scan icon directories and hidden entries; these are read-only and use shellQuote for any dynamic arguments, so they are safe.
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/koenhendriks/omarchy-menu-calculator-plugin --enable
Productivity #quickshell #launcher

Omarchy Menu Calculator Plugin

Type a calculation into the Omarchy menu and the answer appears as the top row. Enter copies it to the clipboard.

The Omarchy menu answering 4+4 with 8

Everything else about the menu stays exactly as Omarchy ships it. Anything that is not arithmetic — including a bare number like 42 — leaves the search results untouched, so theme, app names, and every existing route still behave the way you expect:

Searching for "theme" returns the usual menu rows

Install

omarchy plugin add https://github.com/koenhendriks/omarchy-menu-calculator-plugin.git --enable --yes

That clones the plugin to ~/.config/omarchy/plugins/io.github.koenhendriks.menu-calculator/ and enables it. Nothing else on your system is touched: no config file is rewritten, no keybinding is changed, and no file outside that directory is created.

Enabling the plugin makes it stand in for the built-in omarchy.menu, so the SUPER keybind, the Omarchy button on the bar, omarchy menu, and every script that summons the menu all reach it automatically — there is nothing to rebind.

Update later with omarchy plugin update io.github.koenhendriks.menu-calculator.

Remove

omarchy plugin disable io.github.koenhendriks.menu-calculator

Disabling restores the built-in Omarchy menu and puts its bar button back where it was. To delete the files as well:

omarchy plugin remove io.github.koenhendriks.menu-calculator --yes

Usage

Open the menu (SUPER), type an expression, read the answer. Enter copies the result and sends a notification confirming it; Escape closes the menu as usual.

The menu answering sqrt(144)+2^5 with 44

Type this Get this
4+4, 10-3, 6*7, 10/4 8, 7, 42, 2.5
1250*1.21 1512.5
2^10, 2**8 1024, 256
(2+3)*4 20
10%3 1 — a % with an operand after it is a remainder
20%, 50%*2 0.2, 1 — a % with nothing after it is a percentage
sqrt(144)+2^5 44
round(2.5), min(3,9,2) 3, 2
pi*2, ln(e) 6.28318530718, 1
0x1f+1, 0b1010*2, 1e3+1 32, 20, 1001
2×3, 10÷4 6, 2.5

Operators + - * / % ^ (or **), parentheses, unary minus, and the × ÷ − · symbols a calculator app puts on its keys.

Functions abs acos asin atan atan2 cbrt ceil cos exp floor hypot ln log log2 log10 max min mod pow round sign sin sqrt tan trunc.

Constants pi, π, tau, e.

Numbers decimals, exponents (1e3), hex (0x1f), binary (0b1010), and octal (0o17). Commas separate function arguments, so min(1,2) works but 1,000+5 does not.

Results carry twelve significant digits, which is enough that 0.1+0.2 reads as 0.3. Anything that is not a finite number — 1/0, 1e309*2 — produces no row at all rather than a row saying Infinity.

How it works

Calculator.js is a hand-written tokenizer and precedence-climbing parser, not eval(). The string comes straight out of a text field, and a parser that only knows numbers and math cannot be talked into running anything else.

Menu.qml is not a fork of the Omarchy menu. It instantiates the stock menu from $OMARCHY_PATH/shell/plugins/menu/Menu.qml and adds three things to it:

  • a watcher on the search text that injects a calculator row into the menu's item tree, the same way the built-in apps provider injects applications
  • an item order far below every real row, which is what keeps the answer on top
  • an override of parentPathFor(), so the row's second line shows the expression instead of the menu path a synthetic row hasn't got
  • an application list, because Omarchy does not give a third-party menu one

Because the row is a real menu item, search, keyboard, pointer, and theming all treat it like any other row. The calculator stays out of dmenu mode (omarchy-menu-select) entirely — those rows belong to whoever opened the list.

The application list

The stock menu reads its applications through shell.appLibrary, a capability the host hands to the plugin. Omarchy 4.0.3 builds that object for third-party plugins but leaves appLibrary null on it, and mergeAppRows() opens with if (!root.appLibrary) return — so a cloned menu has no applications at all: nothing in the Apps submenu, nothing in search, and nothing in the journal to say why. The stock menu is unaffected, because a first-party plugin is handed the shell itself.

AppLibraryShim.qml rebuilds that capability out of what a plugin can reach: DesktopEntries for the entries, and the shell's own AppSearch.js, hidden-entries.sh and launcher.hides for identical ranking and identical NoDisplay / OnlyShowIn / NotShowIn filtering. ShellWithAppLibrary.qml carries it in, since appLibrary is readonly on the base but the shell property it reads from is not. The swap only happens when the host supplies no library of its own, so the day Omarchy starts providing one the plugin goes back to using it. The one thing not reproduced is the "Launching…" OSD, which needs host-only state; the launch itself is the same gtk-launch call.

Requirements

Omarchy 4 (Quattro) with the Quickshell-based omarchy-shell. The plugin uses only commands Omarchy already ships (omarchy-clipboard-paste-text for the clipboard, omarchy-notification-send for the confirmation); there are no external dependencies to install.

One caveat: the import of the stock menu is a literal file:///usr/share/omarchy/shell/plugins/menu, because a QML import path cannot be built from an environment variable at runtime. That is the packaged $OMARCHY_PATH. An Omarchy installed somewhere else needs that line changed in Menu.qml and BarWidget.qml.

Hacking on it

Saving a file under ~/.config/omarchy/plugins/ reloads plugin code automatically. If the plugin directory is a symlink to a checkout elsewhere the shell's file watcher will not see the change, so reload by hand:

omarchy restart shell

QML errors land in the shell log:

quickshell log --pid "$(pgrep -f 'quickshell -n -p /usr/share/omarchy/shell')" -t 40

License

MIT. Plugins run unsandboxed inside omarchy-shell; read the code before you enable it — it is four short files.