Omahub
← All plugins
E

Nordsettings

by espen

Guided Hyprland look-and-feel settings with live profiles, visual previews, and undo

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
e893068
Scanned
3 weeks 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
e893068
Reviewed
3 weeks ago

This is a legitimate Hyprland look-and-feel settings widget. It writes state files and generates a Lua overlay under ~/.local/state/omarchy, and applies changes via hyprctl eval, all of which is expected and clearly documented. The code is transparent, well-tested, and uses defensive file-handling (descriptor-safe, symlink/ownership checks) with no signs of obfuscation, credential theft, or destructive behavior.

  • The plugin modifies Hyprland configuration and writes generated Lua that Hyprland loads; this is the intended function and requires user consent via installation and use.
  • The bundled StateStore.py is invoked with /usr/bin/python3; if that path is unavailable the plugin will error, 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/ekrist1/nordsettings --enable
Appearance #Hyprland

Nordsettings

An Omarchy shell plugin that opens Hyprland look-and-feel settings from a gear icon on the top bar.

Change gaps, borders, rounding, blur, opacity, shadows, dimming, tiling layout, floating-window snapping, per-leaf animation speed and named curves, pointer behaviour, and touchpad options from a guided panel that matches the rest of the desktop. Five reversible live profiles, named user snapshots, category diagrams, Basic / Advanced modes, global search, and Undo / Redo history make the larger Hyprland schema approachable.

Compatibility

Nordsettings targets Omarchy's current shell-plugin API and Hyprland 0.55 or newer, where Omarchy's Hyprland configuration is Lua-based. The model and generated configuration are covered by automated tests; the complete panel still requires an Omarchy/Hyprland session for UI testing.

Omarchy 4.0.3

Omarchy 4.0.3 hands installed bar widgets a PluginBarApi facade instead of the bar itself, and on that facade centerHoverRevealSuppressed is readonly. Nordsettings now sets the bar's center-hover hint through setCenterHoverRevealSuppressed() when the host provides it and falls back to the direct assignment on older hosts. Panel teardown can also no longer abort controller.hide(), so the full-screen layer-shell overlay is always released even if a future host rejects part of the close path.

Install

omarchy plugin add https://github.com/ekrist1/nordsettings.git --enable --yes
omarchy bar move io.github.ekrist1.nordsettings --section right

From this folder, without git:

omarchy plugin validate .
mkdir -p ~/.config/omarchy/plugins
rsync -a --delete --delete-excluded --exclude .git --exclude .agents --exclude .codex ./ \
  ~/.config/omarchy/plugins/io.github.ekrist1.nordsettings/
omarchy restart shell
omarchy plugin enable io.github.ekrist1.nordsettings --yes
omarchy bar move io.github.ekrist1.nordsettings --section right

Re-syncing after an edit currently needs omarchy restart shell, not omarchy-shell shell rescanPlugins: the latter reloads the plugin entry but the QML engine keeps its already-compiled Panel.qml, so the running shell quietly carries on with the old code.

Keyboard shortcut

Add this to ~/.config/hypr/bindings.lua:

o.bind(
  "SUPER + SHIFT + C",
  "Hyprland settings",
  "omarchy-shell shell toggle io.github.ekrist1.nordsettings"
)

Hyprland reloads the file on save. You can also toggle it from a terminal:

omarchy-shell shell toggle io.github.ekrist1.nordsettings

Use

Click the gear on the bar (right section by default). The panel uses five task-oriented categories:

  • Overview — five quick profiles, Undo, and Reset
  • Windows — geometry, opacity, and the active tiling layout
  • Effects — blur, shadows, and inactive-window dimming
  • Motion — global animation plus per-leaf speed and named curves
  • Input — pointer, keyboard repeat, cursor, and hardware-aware touchpad behavior

Basic mode shows the controls most people are likely to need. Advanced mode reveals the complete schema. Child controls collapse when their parent feature is off; layout-specific controls appear only for the selected layout. Search is always global and includes Advanced settings, even when another category is selected.

The Balanced, Snappy, Calm, Minimal, and Battery Saver profiles are partial starting points. Selecting one applies it live but saves nothing. Review its exact before/after diff, then choose Keep or Revert. Closing the panel also reverts an unaccepted preview. Profiles never change input devices or choose a tiling layout.

j/k or the arrow keys move between rows. h/l nudges the selected slider, cycles an enum, or flips a toggle. Enter or Space does the same for toggles and enums. / or q jumps to search — type a name, a description, or a group ("blur", "gaps", "touchpad") and the list keeps only the matches. Escape clears the query, then closes. Tab and Shift+Tab move to the next or previous bar panel.

Sliders apply after a short debounce so dragging does not stall Hyprland. A footer status reports loading, applying, and saving. If Hyprland or a file operation fails, controls stop accepting changes and the footer offers Retry; failed live changes are not written as though they succeeded. An up-to-20-step Undo / Redo history appears after an ordinary edit; a continuous slider drag is coalesced into one action. Keeping a profile can also be undone. Rows owned by Nordsettings are marked and have an individual reset button. A row reset removes only that override, reloads Hyprland, and reveals the value from Omarchy or your hand-written config. Animation controls reset their whole leaf because Hyprland applies each animation leaf as one record. A Reset row at the bottom deletes this plugin's overlay and runs hyprctl reload, which returns those keys to Omarchy defaults plus anything you still have in looknfeel.lua / input.lua.

How persistence works

Omarchy configures Hyprland in Lua. Live hyprctl keyword is rejected in that mode, so the plugin applies changes with:

hyprctl eval 'hl.config({ general = { gaps_in = 8 } })'
hyprctl eval 'hl.animation({ leaf = "windows", enabled = true, speed = 4, bezier = "easeOutQuint" })'

Those evals are session-only. To keep them, Nordsettings writes two files:

File Role
~/.local/state/omarchy/nordsettings/overrides.json Source of truth for keys this plugin has set
~/.local/state/omarchy/nordsettings/profiles.json Named, complete user profile snapshots
~/.local/state/omarchy/toggles/hypr/zz-nordsettings.lua Generated hl.config / hl.animation Hyprland actually loads

profiles.json is portable: copy it to the same path on another machine to share the named snapshots. Settings unsupported by that machine's Hyprland version or absent hardware are skipped when a profile is previewed.

The toggles directory is already require'd after your user Hyprland files, so the overlay is picked up on the next reload or login without editing hyprland.lua. It also survives omarchy refresh hyprland.

All three files are accessed through the bundled StateStore.py helper. It uses nonblocking, no-follow descriptor opens; validates directory and file type, owner, permissions, and link count; rejects oversized input before parsing; and saves through an exclusive same-directory temporary file followed by fsync and atomic replacement. Unsafe state paths are reported instead of being followed or overwritten.

Do not edit zz-nordsettings.lua by hand — the plugin overwrites it. Keep hand-written extras in ~/.config/hypr/looknfeel.lua and ~/.config/hypr/input.lua.

Same key in both places: the overlay file loads last, so a gap you set here wins over the same key uncommented in looknfeel.lua. Keys this plugin does not expose (window rules, colours, binds, monitors) stay yours.

Theme files still own border colours. This plugin does not write colour keys, so omarchy theme set keeps working.

Hyprland's animation API replaces a complete animation leaf at once. The first time you change a leaf's speed, curve, or enabled state, Nordsettings therefore snapshots all four fields for that leaf into overrides.json. This makes the source of truth accurately describe everything the generated hl.animation call owns. Reset removes that ownership.

If overrides.json is malformed or from an unsupported future version, Nordsettings leaves it untouched and disables editing. Fix or move the file, then select Retry; it will not silently replace unreadable state.

Options unavailable in the running Hyprland version are omitted without blocking the rest of the panel. Touchpad and touchscreen-only controls are also hidden when Omarchy does not detect the corresponding hardware.

What this is not

Monitors (use the stock Display panel), keybindings, window / workspace / layer rules, a custom bezier point editor, autostart, or environment variables. Animation curves are a named pick from Omarchy's look-and-feel (default, easeOutQuint, easeInOutCubic, linear, almostLinear, quick). It is not a second Quickshell process and it is not HyprMod.

Settings

Tune the widget from the bar settings panel, or inline in ~/.config/omarchy/shell.json:

{
  "id": "io.github.ekrist1.nordsettings",
  "hoverOpen": false
}

hoverOpen opens the panel when the pointer rests on the gear. It is off by default so a pass across the bar does not drop a large settings card.

Tests

The option schema, hyprctl -j parsing, Lua emission, and JSON overlay logic live in HyprModel.js as plain functions:

npm test

That also runs tests/source-lint.test.js, a static pass over the QML and JS, plus tests/state-store.test.js, which plants FIFOs, symlinks, oversized files, and unsafe destinations against the real helper. Other checks cover invalid string escapes, unbounded SplitParser use, manifest settings, and the requirement that live apply use hyprctl eval.

The installed-shell freshness check is deliberately a development diagnostic, not a source test:

npm run check:installed

Full UI coverage still belongs to using the plugin on the bar — QML here depends on omarchy-shell, Hyprland, and layer-shell.

Architecture

  • Panel.qml — panel composition and keyboard navigation
  • SettingsBackend.qml — live reads, reversible preview, Undo, retry, reset, and transactional persistence
  • SettingsRow.qml — reusable header, setting control, and reset-row delegate
  • SettingsFooter.qml — search, keyboard hints, progress, and retry feedback
  • CategoryTabs.qml — category and Basic / Advanced navigation
  • PresetGallery.qml, PresetCard.qml, PresetPreviewBar.qml — profile selection and review
  • UserProfiles.qml — save, rename, preview, and delete named snapshots
  • HistoryBar.qml — bounded Undo / Redo controls
  • SettingVisualizer.qml — live category diagrams
  • HyprModel.js, Presets.js — pure schema, profile, diff, parsing, coercion, filtering, and Lua emission
  • StateStore.py — bounded descriptor-safe reads, atomic writes, and safe removal for plugin state

Remove

omarchy plugin remove io.github.ekrist1.nordsettings

That takes the widget off the bar and removes the plugin folder. Generated overlay files are left in place so your Hyprland look does not jump on remove. Delete them and reload if you want Omarchy defaults back:

rm -f ~/.local/state/omarchy/toggles/hypr/zz-nordsettings.lua \
      ~/.local/state/omarchy/nordsettings/overrides.json
hyprctl reload

License

MIT