Omahub
← All plugins
D

OmaShuffle

by Deunnis

Applies a different theme on every real boot, or by time of day via an optional Day & Night schedule, drawn from a shuffled deck of themes you curate. Fullscreen picker opened from the Omarchy menu; every switch stays fully reversible.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
283951b
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
283951b
Reviewed
1 month ago

The plugin is a theme shuffler that applies themes via the standard `omarchy theme set` command and manages a desktop/menu entry. The code is well-structured with careful file handling (bounded reads, O_NOFOLLOW, atomic writes) and no network, elevated privileges, or destructive operations. The deterministic scan found no issues, and manual review confirms the behavior matches the documented functionality.

  • The plugin writes to user-level config files (~/.local/share/applications/omashuffle.desktop and ~/.config/omarchy/extensions/omarchy-menu.jsonc) and copies a helper script into the extensions directory, but these are reversible and only touch files with a specific marker.
  • It runs `python3` helper scripts and `omarchy theme set` at startup, but these are bounded and non-privileged.
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/Deunnis/OmaShuffle --enable
Appearance #Hyprland #quickshell
<div align="center"> <img src="icon.png" alt="OmaShuffle" width="128">

OmaShuffle

A fresh Omarchy theme every time you boot — or every sunrise and sunset.

Pick the themes you like once. From then on, every real boot deals you the next one from a shuffled deck — no repeats until you've seen them all. Turn on Day & Night and it switches by time of day instead: a light theme while the sun's up, a dark one once it's down.

<img src="https://img.shields.io/badge/Omarchy-4.x-a855f7?style=flat-square" alt="Omarchy 4.x"> <img src="https://img.shields.io/badge/kind-overlay-22d3ee?style=flat-square" alt="overlay plugin"> <img src="https://img.shields.io/badge/network-none-16a34a?style=flat-square" alt="no network"> <img src="https://img.shields.io/badge/license-MIT-64748b?style=flat-square" alt="MIT">

<br><br>

<img src="screenshots/picker.png" alt="The OmaShuffle picker: a grid of every installed theme with palette swatches, some ticked into the rotation; the header carries Boot shuffle, Day & Night and Schedule controls" width="860"> </div>

Is this for you?

  • You installed six themes, loved the third one for a week, and now you're bored again.
  • You keep omarchy theme set-ing around at 1am instead of sleeping.
  • You genuinely can't decide, and honestly you'd rather your computer just surprised you.
  • You like your desk to feel a little different on a Monday than it did on Friday.

If any of that landed: this is for you. OmaShuffle turns "ugh, which theme today" into a decision you already made, once, in a nice grid.

How it works

You open the picker and tick the themes you want in the rotation. That's the whole setup.

After that, every real boot OmaShuffle quietly applies the next theme in the deck. The deck is a shuffled bag: every theme you picked comes up exactly once, then the bag reshuffles and the theme you're currently wearing is pushed to the back so you don't see it twice in a row.

"Real boot" means a genuine power-on or reboot — the kind where you had to type your disk-unlock passphrase. It reads /proc/sys/kernel/random/boot_id, a value the kernel regenerates on every boot and keeps stable within one. So:

This happens Theme switches?
You reboot / power on yes
omarchy restart shell, or the shell reloads no
You log out and back in no
Suspend / resume, closing the lid no

Nothing here is a one-way door. It's a normal omarchy theme set under the hood — grab any theme by hand from the picker (or the usual omarchy theme command) whenever the deck deals you something you're not in the mood for.

Day & Night

An independent, opt-in (off by default) alternative to boot shuffle: instead of one theme per boot, OmaShuffle switches by time of day. Turn it on from the Schedule tab.

<img src="screenshots/schedule.png" alt="The OmaShuffle Schedule tab: a Switch themes by time of day toggle, a manual latitude/longitude location, and three slots (Day, Afternoon, Evening) each with a light/dark mode, a sunrise/sunset anchor, and a minute offset" width="760">
  • Slots. Two by default — Day (a light theme, from sunrise) and Night (a dark theme, from sunset) — each with its own no-repeat deck, so "night" isn't the same theme every night. Add up to six total; each new slot is explicitly tagged light or dark, anchored to sunrise or sunset, with its own minute offset from that event.
  • Location. Reused from Omarchy's own weather location (omarchy-weather-location) when it has coordinates — no setup needed. If none is set, the tab asks for latitude/longitude directly; the actual sunrise/sunset math is pure arithmetic, so this never makes a network call.
  • Switching. Instant, no notification — the exception is a slot whose mode has no matching themes in your rotation, which notifies once and leaves the current theme alone rather than switching to nothing useful. It switches only when a slot boundary is actually crossed (checked roughly once a minute, and once at startup to catch a boundary you were off/asleep for). A plain shell restart mid-slot changes nothing — a theme you set by hand, with the picker or omarchy theme, is never undone.
  • No location, no switching. Until Omarchy knows your coordinates (or you enter them in the tab), Day & Night stays completely inert even when it's toggled on.
  • Manual picks from the grid pause Day & Night until the next boundary — it doesn't fight you — and that pause survives a shell restart.
  • Shuffle now / Reshuffle deck act on whichever slot is currently active instead of the (dormant, while Day & Night is on) boot-shuffle deck.

Turning Day & Night on doesn't touch boot shuffle's own toggle or deck; it just takes over deciding the applied theme until you turn it back off.

Requirements

  • Omarchy 4 with its Quickshell-based shell
  • python3 — the only dependency beyond Omarchy itself. Used once at startup to read this plugin's own small state file safely (see Notes for reviewers). It's present on a normal Omarchy install.

No network access. No elevated privileges. No package management.

Install

omarchy plugin add https://github.com/Deunnis/OmaShuffle.git --enable
omarchy restart shell

That's it — it starts working from the next boot. Until you pick at least one theme it does nothing but show a one-line reminder on boot.

Opening the picker

Out of the box: Super + Space. Enabling OmaShuffle installs a launcher entry (~/.local/share/applications/omashuffle.desktop), so the picker shows up in the Omarchy menu and app launcher straight away — search OmaShuffle or theme shuffle. Disabling or removing the plugin deletes that entry again; only a file carrying the X-OmaShuffle-Managed=true marker is ever touched.

Other ways, if you want them:

A keybind (fastest). Add one to ~/.config/hypr/bindings.lua, on any combo that's free for you:

o.bind("SUPER + SHIFT + S", "Theme shuffle", "omarchy-shell shell toggle io.github.omashuffle")

A dedicated menu row. The launcher entry lands under Apps; if you'd rather have a row somewhere specific, the gear → Omarchy menu → Add menu entry adds a Style → Theme Shuffle row (remove it from the same place). By hand, drop this into ~/.config/omarchy/extensions/omarchy-menu.jsonc:

"style.omashuffle": {"icon":"󰔎","label":"Theme Shuffle","aliases":["shuffle"],"action":"omarchy-shell shell toggle io.github.omashuffle"},

IPC, for scripts: omarchy-shell shell toggle io.github.omashuffle

Using the picker

<img src="screenshots/settings.png" alt="The OmaShuffle settings pane: boot-shuffle and notification toggles, transparency / corner / outline sliders, and Add / Remove menu entry buttons" width="640">
Action What it does
Click a theme (or Enter) apply it right now
Right-click a theme (or Space) add / remove it from the rotation
Arrow keys move the highlight
Shuffle now jump straight to the next deck theme
Reshuffle deck throw out the current order and draw a fresh shuffle
Select all / none bulk-edit the rotation
All dark / All light add every dark (or light) theme to the rotation in one click
Boot shuffle: on / off the master switch for the once-per-boot behaviour
Day & Night: on / off the master switch for time-of-day switching (see below)
Schedule open the Day & Night tab — slots, offsets, location
Filter themes… narrow the grid by name
gear icon notifications, card transparency / corners / outline, menu entry
Esc close (or leave settings)

The header always tells you what you're wearing now and what's queued for next boot. The strip along the bottom is your recent history.

Where it keeps things

Everything lives in one file: ~/.local/state/omarchy/io.github.omashuffle/state.json

  • pool — the theme slugs you put in the rotation
  • deck — the remaining shuffled order for the current bag; when it empties, a fresh shuffle of pool is drawn
  • history — the last 40 themes OmaShuffle applied, with timestamps
  • lastBootId — the boot_id at the last switch, i.e. the "was this a real boot" marker
  • schedule — Day & Night: on/off, location, its slots (each with its own deck), and the manual-pick pause
  • a few UI prefs (notifications, card transparency / corners / outline)

Delete the file to start over; disable the plugin to stop entirely.

Notes for reviewers

  • No network. No privileged calls. The plugin runs omarchy theme set, omarchy-shell, omarchy-notification-send, and its own two python3 helper scripts in bin/. It makes no network requests, needs no elevated privileges, and manages no packages or services.
  • Service.qml writes one file: ~/.local/share/applications/omashuffle.desktop, a launcher entry pointing at omarchy-shell shell toggle io.github.omashuffle. All the file work is delegated to bin/omashuffle-desktop-entry, which holds itself to the same discipline as bin/omashuffle-menu-entry: it reads the bundled omashuffle.desktop template and the existing destination with the bounded O_RDONLY | O_NOFOLLOW | O_NONBLOCK + S_ISREG read below, proceeds only when the destination is absent or already carries the X-OmaShuffle-Managed=true marker (a symlink, FIFO, directory or foreign file all read as "not ours" and are left alone), writes the icon-substituted contents to a fresh mkstemp O_EXCL inode in the verified target directory, and os.replaces that over the destination — which replaces a symlink at the path rather than following it, so nothing is ever written through one. On disable/remove it unlinks the file only when it is a regular file carrying the marker. This mirrors how Omaland registers its launcher entry.
  • Theme slugs are validated in ThemeDeck.js (^[a-z0-9][a-z0-9._-]*$, no /, no .., length-capped) before they are ever passed to omarchy theme set, on top of that command's own checks.
  • Every file this plugin reads is opened as a bounded, regular, non-symlink file — state.json and current/theme.name (both under ~/.local/state) and the menu file are opened once with O_RDONLY | O_NOFOLLOW | O_NONBLOCK, fstat-checked on that same descriptor to require S_ISREG, and read up to a fixed byte cap, so nothing is bounded by what the path claims and a planted FIFO or symlink is refused. state.json writes go through FileView with atomicWrites.
  • bin/omashuffle-scan-themes enumerates the two standard theme directories and pulls hex values (and the mode = "dark"|"light" key, for the All dark / All light buttons and the Day & Night slots) out of each colors.toml with the bounded descriptor-safe read above. It caps theme count, slug length, per-file bytes and total output, runs under an outer timeout, and never executes anything a theme ships. A theme (which may be an installed third-party repo) cannot make it block or grow the shell.
  • bin/omashuffle-menu-entry is only ever run when you press Add menu entry / Remove menu entry in the settings pane — the plugin never edits the menu file on its own. It reads ~/.config/omarchy/extensions/omarchy-menu.jsonc with the bounded descriptor-safe read, builds the edit in a fresh O_EXCL temp inode inside that directory (verified to be a real directory you own), then os.replaces it over the target without following a symlink there. It only ever touches a row it owns, and bails without writing if the file layout is unfamiliar.
  • python3 is the only dependency beyond Omarchy — the three bin/ scripts and the in-QML descriptor-safe readers.
  • Day & Night adds one more read, ~/.local/state/omarchy/settings/weather.json (written by Omarchy's own omarchy-weather-location, read the same bounded/descriptor-safe way as state.json) as the default source of latitude/longitude for sunrise/sunset, and does no I/O beyond that: the sun position math in SunTimes.js is local arithmetic, never a network call. Manual coordinates, if you enter them instead, stay in state.json like everything else.

Not included (by design)

  • No theme creation or editing — OmaShuffle only rotates themes that already exist. Use omarchy theme or a theme-designer plugin for that.
  • No wallpaper-only shuffle — it switches whole themes via omarchy theme set.
  • No background blur behind the picker card (transparency / corners / outline only, for now).

Remove

omarchy plugin remove io.github.omashuffle
omarchy restart shell

Your last theme stays applied. The launcher entry (~/.local/share/applications/omashuffle.desktop) is removed automatically on disable/remove. If you also added the dedicated menu row, remove it from the settings pane (Remove menu entry) or delete the style.omashuffle line from ~/.config/omarchy/extensions/omarchy-menu.jsonc yourself. Delete ~/.local/state/omarchy/io.github.omashuffle/ to clear the rotation and history.

Development

omarchy plugin validate ~/.config/omarchy/plugins/io.github.omashuffle
python3 -m py_compile bin/omashuffle-menu-entry bin/omashuffle-scan-themes bin/omashuffle-desktop-entry
node --check <(tail -n +2 ThemeDeck.js)   # strip the .pragma line
node --check <(tail -n +2 SunTimes.js)    # same, for the sun-position math
omarchy restart shell                     # plugin QML is cached by URL

ThemeDeck.js and SunTimes.js are pure logic with no QML or I/O dependencies — the easy place to reason about shuffling, the no-immediate- repeat rule, slug validation, and sunrise/sunset math.

License

MIT — see LICENSE.