Omahub
← All plugins
C

Notepad Calc

by chris

A live calculation notepad: prose with numbers, units, currency, dates and variables — every line evaluates as you type.

Security review

Potentially dangerous behavior detected · 27 findings

Deterministic scan — not a security guarantee

High
Risk level
High
Analyzed commit
8c444d1
Scanned
1 month ago
  • high curl_pipe_sh …/workflows/test.yml:86

    curl output is executed by a shell (curl | sh pattern).

    curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
  • curl output is executed by a shell (curl | sh pattern).

    curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
  • medium external_hosts …/workflows/test.yml:86

    Downloads or connects to an external HTTP(S) host.

    curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
  • medium external_hosts …/workflows/test.yml:160

    Downloads or connects to an external HTTP(S) host.

    curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
  • medium package_manager …/workflows/test.yml:38

    System package manager operation.

    apt-get update
  • medium package_manager …/workflows/test.yml:39

    System package manager operation.

    apt-get install -y --no-install-recommends \
  • medium package_manager …/workflows/test.yml:81

    System package manager operation.

    apt-get update
  • medium package_manager …/workflows/test.yml:82

    System package manager operation.

    apt-get install -y --no-install-recommends \
  • medium package_manager …/workflows/test.yml:155

    System package manager operation.

    apt-get update
  • medium package_manager …/workflows/test.yml:156

    System package manager operation.

    apt-get install -y --no-install-recommends \
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net true >/dev/null 2>&1; then
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net sh -c "ip link set lo up 2>/dev/null || true; cd '$ROOT' && node tests/run.js"
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net)"
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net bash -c 'ip link set lo up 2>/dev/null || true; cd '"$PWD"' && node tests/run.js && tests/helper.test.sh'
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get update
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net bash -c 'ip link set lo up 2>/dev/null || true; cd '"$PWD"' && export QML_BIN='"$QML_BIN"' REQUIRE_QML=1 QT_QPA_PLATFORM=offscreen && tests/run-qml.sh'
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get update
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net true >/dev/null 2>&1; then
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net env \
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net)"
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get update
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net true >/dev/null 2>&1; then
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net env \
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net)"
  • Augments a command with octal/hex escape sequences.

    \x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", comp) + chunk(b"IEND", b"")
  • low obfuscation …/ui/pixeldiff.py:18

    Augments a command with octal/hex escape sequences.

    \x89PNG\r\n\x1a\n":
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo unshare --net`; if neither works the job **fails**. `tests/offline.sh` also **fails closed** when a net namespace cannot be created.

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
8c444d1
Reviewed
1 month ago

The plugin is a QML bar widget that performs local calculations and optional currency-rate refreshes. The deterministic scan flagged high risk, but those findings are all in CI/test files (curl|sh to install Nix, sudo in test scripts, PNG magic bytes in test helpers) and are not part of the plugin's runtime code. The plugin's runtime behavior is benign: it writes only to its own data directory and, only on explicit user opt-in, appends a marked block to Hyprland's bindings.lua.

  • The CI workflow uses `curl | sh` to install Nix, but this runs only in GitHub Actions, not on the user's machine.
  • The plugin can write to ~/.config/hypr/bindings.lua, but only when the user explicitly clicks to install a hotkey; the code refuses symlinks and preserves other bindings.
  • The optional rates refresh fetches from the ECB over HTTPS with a 5s timeout and falls back to a bundled snapshot; it never blocks the UI.
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/ccdwyer/omarchy-notepad-calc --enable
Productivity #bar #quickshell

Notepad Calc

Changing 2 × $429 monitors to 3 × ripples the downstream results

A living calculation notepad for the Omarchy bar. Type prose with numbers; every line that is actually math evaluates as you type, and changing one number ripples through the sheet.

Inspired by Soulver. The concept is Soulver's. This is a native, theme-aware, fully offline Omarchy implementation — not a clone of the product, and not affiliated with Acqualia.

The catalog already has one-shot =expr and a single-pair currency overlay. Notepad Calc's unit is the sheet: ten lines of budget math, each referencing the ones above, all live.

Install

omarchy plugin add https://github.com/ccdwyer/omarchy-notepad-calc.git --enable

Optional helper (daily ECB rate refresh). The plugin works without it — it ships a dated snapshot:

~/.config/omarchy/plugins/io.github.chris.notepad-calc/build.sh

Reload if the shell is already running:

omarchy-shell shell rescanPlugins

The chip lands in the bar's right section (barWidget.defaultSection). Move it with omarchy bar move if you want.

Usage

Click the Σ chip (it shows the focused sheet's total). The first-run sheet is Omarchy battlestation — monitors, tax, EUR, desk width, a copy-time, a delivery date, and $120/mo × 14 months in EUR. Change 2 × $429 to 3 × and watch the downstream results pulse.

Key Action
Click Σ Open / close the notepad
Set hotkey Opt-in Super+N toggle / Super+Alt+N summon (skips occupied; never unbinds others)
Hotkey chip Shows the installed combo; click for Change / Remove
Esc Close (or dismiss help / sheet switcher)
Ctrl+K Sheet switcher
Ctrl+N New sheet
Ctrl+Shift+C Copy the result on the cursor line
Click a result Copy that result
Ctrl+S Save now (also autosaves on idle)
? Help

The widget stays loaded on the bar, so Quattro call reaches it. Every call takes a final argument.

Hotkeys are opt-in from the bar. First load does not write ~/.config/hypr/bindings.lua. If none is installed, the chip next to Σ shows Set hotkey and suggests Super+N (toggle) and Super+Alt+N (summon). That click is the only thing that writes this plugin's marked o.bind block. Occupied combos are skipped; Super+N falls back to Super+Alt+Shift+N. Super+Shift+N is Omarchy's Editor bind and Super+Ctrl+N is nightlight, so those are never stolen. Once a hotkey is set, the chip shows it; click for Change (next free suggested combo) or Remove (deletes the marked block). Hide stays click-based (Esc in the panel). The plugin never hl.unbinds someone else's key.

-- BEGIN io.github.chris.notepad-calc
o.bind("SUPER + N", "Notepad Calc", "omarchy-shell io.github.chris.notepad-calc toggle '{}'")
o.bind("SUPER + ALT + N", "Notepad Calc summon", "omarchy-shell io.github.chris.notepad-calc summon '{}'")
-- END io.github.chris.notepad-calc

summon / hide / toggle / installBinds / changeBinds / removeBinds are string-argument methods on the bar-widget IpcHandler (BarWidget.qml). omarchy-shell shell call <id> hits overlay/panel loaders only — this plugin is bar-widget-only, so that returns unknown. Host-level shell summon|hide|toggle <id> is for panel/overlay kinds and is not used for this widget. The nested panel is opened by BarWidget.open.

omarchy-shell io.github.chris.notepad-calc toggle '{}'
omarchy-shell io.github.chris.notepad-calc installBinds ''

Grammar (v1, frozen)

Unknown words are prose, not errors. Anchors that turn a line into math: numbers, currency, units, operators, and reserved words (in of per as from to ago sum total prev avg).

rent = $1,200/mo
utilities = $180/mo
year cost = (rent + utilities) × 12          → $16,560.00
in EUR                                        → €14,275.86   (applies to prev; bundled 2026-08-18 rates)
20% of year cost                              → $3,312.00
year cost + 8.1% tax                          → $17,901.36
sum                                           → contiguous results above, to the last blank
$120/mo × 14 months in EUR                    → €1,448.28
10 GB / 4 MB/s                                → 41 min 40 s
3pm in Los Angeles → Tokyo time               → 7:00 AM tomorrow, JST
today + 45 days                               → Oct 3, 2026   (from 2026-08-19)
1440 minutes as hours                         → 24 h
  • X + N% is Soulver's rule: X × (1+N/100). The first-run sheet includes a tax line so you see it before you type it.
  • N% of X multiplies.
  • in <unit|currency> is a postfix conversion. Bare in EUR converts prev.
  • Variables: name = expr. Names may contain spaces (longest match, defined-before-use). Redefinition shadows downward.
  • Hover sum to underline exactly the lines it captured.
  • Hover a timezone result to see the resolved IANA id (America/Los_Angeles, Asia/Tokyo).

Three-state lines:

What you typed Result column
No math anchors (planning the desk) silent
Math plus a missing name (budget = flights + hotl) muted ?hotl
Resolvable the value

version 2 of the plan stays prose.

Currency

ECB daily reference rates — about 30 currencies, not 170. Cross-rates give more pairs, not more currencies. The header always shows rates: YYYY-MM-DD. Offline, you get the bundled snapshot. A background refresh runs at most once per calendar day (5s timeout, single-flight, atomic replace of ~/.local/share/notepad-calc/rates.json). Network is an enhancement, never a dependency, and never blocks the UI.

Files

~/.local/share/notepad-calc/sheets/*.calc   # plain text; first line is the title
~/.local/share/notepad-calc/rates.json      # last successful ECB pull
~/.local/share/notepad-calc/state.json      # last fetch date

Sheets are yours. Git them. Nothing proprietary can corrupt them.

Settings live inline on the shell.json bar entry (defaultCurrency). There is no plugin config file.

Remove

omarchy plugin remove io.github.chris.notepad-calc

Also remove this plugin's marked block from ~/.config/hypr/bindings.lua (the lines between -- BEGIN io.github.chris.notepad-calc and -- END io.github.chris.notepad-calc). If the hotkey chip is still on the bar, Remove there deletes that block before uninstall. Hyprland reloads on save. Other keybindings are left alone.

Honest limitations

  • Grammar is frozen to the lines above and their compositions. Natural-language improvisation will misfire; that is why the demo is the first-run sheet.
  • ~30 ECB currencies. No crypto, no exotic pairs, no live ticker.
  • ~50 city / IANA zones, DST-correct for 2024–2028 from bundled TZDB transition timestamps (tools/tzgen.py, not generic US/EU rules). City names are the documented form (Los Angeles, not PST in the demo). Ambiguous abbreviations (IST, CST) are refused rather than guessed.
  • 130 canonical units (UCUM-ish subset: length, mass, time, data, area, volume, speed, temperature, data-rate, angle, frequency).
  • × 12 on a $ /mo quantity treats 12 as twelve of that period so (rent + utilities) × 12 is a year total. Prefer × 12 months if you want the unit algebra spelled out.
  • Row alignment is wrap-free monospace. Long lines scroll horizontally; they do not wrap. That is deliberate.
  • Helper binary is optional. Missing bin/notepad-calc-rates falls back to compat/rates-refresh.sh (curl), then to the bundled snapshot.
  • No second Quickshell process. Everything runs inside omarchy-shell.
  • Keybinds are opt-in from the bar. First load does not write bindings.lua. Occupied combos are skipped. Never hl.unbind.

Tests

This Mac cannot run Quickshell or Qt Quick. Node is the local gate. QML UI, soak, and the fresh-machine demo run in Linux CI.

Local:

node tests/run.js                  # shared engine corpus (≥200 cases)
tests/helper.test.sh               # helper parse + IPC surface + archive excludes
./build.sh && cargo test --manifest-path src/rates-refresh/Cargo.toml
compat/rates-refresh.sh fetch --xml tests/fixtures/ecb-daily.xml --out /tmp/rates-out.json
./pack.sh                          # git archive tarball (not a working-tree dump)

Linux CI (.github/workflows/test.yml, network disabled):

tests/run-qml.sh                   # same corpus under qml6
tests/ui/run.sh                    # grabToImage; pixel-diff vs committed goldens (skip-warn if absent)
tests/ui/demo.sh                   # fresh HOME, plugin install, battlestation demo
tests/ui/soak.sh                   # 500-line keystroke replay, RSS < 5MB, exactly one rate attempt, 1 hour
cargo test --manifest-path src/rates-refresh/Cargo.toml