Omahub
← All plugins
C

Desktop Undo

by chris

Super+Z for Hyprland: undo window closes, moves, floats, and workspace sends, with a scrubbable timeline of the last fifty actions.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

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

The deterministic scan found no issues, and the sampled code does not show obfuscated, destructive, or exfiltrating behavior. The plugin only writes bindings.lua after explicit user opt-in, uses atomic symlink-guarded edits, and keeps its journal in a 0700/0600 state directory. Residual risk is local and disclosed: it persists window command-line arguments, transiently reads /proc/<pid>/environ for cookie matching, and relaunches recorded commands when undoing a close.

  • The journal stores the argv of closed windows, which may include command-line secrets; it is protected as 0600/0700 but remains readable by same-user processes and persists until entries age out of the 50-entry ring.
  • Cookie matching reads /proc/<pid>/environ, and may scan /proc when no PID hint is available. Only the DESKTOP_UNDO_COOKIE value is matched and nothing is persisted, but process environments are visible to the plugin.
  • Undoing a closed window relaunches the recorded command line. This is expected, user-initiated behavior, but a tampered journal could lead to arbitrary command execution as the user, so the state file's permissions matter.
  • The plugin runs continuously in the shell process and polls window state frequently; this is a resource/robustness consideration rather than 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/ccdwyer/omarchy-desktop-undo --enable
Desktop #Hyprland #bar #quickshell

Desktop Undo

Undo for Hyprland. The last fifty window closes, moves, floats, and workspace sends are a journal; undo walks them back. The bar chip opens a scrubbable timeline with live preview. Hotkeys are opt-in from that overlay — nothing is written to bindings.lua until you click Set hotkey.

This is an Omarchy shell plugin (service + overlay + bar-widget). It runs inside the long-lived omarchy-shell process. It does not start a second Quickshell instance.

Install

omarchy plugin add https://github.com/ccdwyer/omarchy-desktop-undo.git --enable

That is the whole install. The plugin ships compat/undo-probe.sh and uses it automatically for process-tree / cookie matching. No compile step is required on a fresh machine.

build.sh is optional. If you have Rust, you can compile a faster bin/undo-probe; if that binary is absent, the shell fallback is used as-is.

Put the chip on the bar if --enable did not:

omarchy bar put io.github.chris.desktop-undo --section right

Reload plugins if the shell was already running:

omarchy-shell shell rescanPlugins

Usage

Suggested combos (not installed until you opt in):

Combo Action
Super+Z Undo
Super+Y Redo
Super+Shift+Z Open timeline overlay

Hotkeys are opt-in from the bar overlay. The plugin never writes ~/.config/hypr/bindings.lua on first load. Click the bar chip, then Set hotkey. That writes a marked o.bind(...) block if the combos are free. Occupied shortcuts (including stock Omarchy hotkeys) are skipped or replaced with Super+Alt variants. It never unbinds someone else's key. If a hotkey is already set, the overlay shows it and offers Change hotkey / Remove hotkey.

Undo/redo hit the plugin's IpcHandler (the service). summon opens the overlay. They are not interchangeable. The handler requires a third argument (use an empty string when the method needs no payload):

bind = SUPER, Z, exec, omarchy-shell io.github.chris.desktop-undo undo ''
bind = SUPER, Y, exec, omarchy-shell io.github.chris.desktop-undo redo ''
bind = SUPER SHIFT, Z, exec, omarchy-shell shell summon io.github.chris.desktop-undo

The bar chip always summons the overlay, even if no hotkey is set.

In the overlay: Left/Right (or click a card) scrubs with live preview — the desktop actually steps back. Enter commits (truncates redo). Esc rolls forward to the present.

What undo does

Action Undo Fidelity
Close a window Relaunch the command, then re-apply workspace / geometry when we can best-effort
Drag/resize a floating window movewindowpixel / resizewindowpixel exact exact
Send to another workspace movetoworkspacesilent back exact
Float / tile toggle settiled / setfloating + restore geometry if floating exact
Fullscreen fullscreenstate to the recorded state (never a blind toggle) exact

Close-undo for terminals walks /proc/<pid>/task/*/children to the deepest child shell and restores that cwd, so a kitty running htop in ~/projects/demo comes back in that directory. Matching the relaunched window uses a short-lived DESKTOP_UNDO_COOKIE env var read back from /proc/<pid>/environ (never persisted). Geometry restore waits until that new client is identified; it never targets the closed window's dead address.

Honest limitations

  • Close is a relaunch, not a snapshot. Apps whose document is not in argv come back as a fresh instance. The overlay labels these reopen, not undo.
  • Multi-window apps (browsers, Electron, editors) are always "reopen". Geometry is not re-applied — two Firefox windows would race.
  • Tiled swap is not in 1.0. swapwindow is direction-only; dwindle/master trees do not round-trip from pixels. Tiled windows still get workspace-send and float-toggle undo. Pixel-exact restore is floating-only.
  • Tiled intra-workspace drags are not recorded. There is no honest inverse.
  • Journal can contain command lines (tokens in argv). The file is 0600 in a 0700 directory under ~/.local/state/desktop-undo/. environ is never written. Password managers are excluded by default. Relaunch metadata dies when the entry leaves the 50-deep ring.
  • Keybinds are opt-in. Open the overlay from the bar chip and click Set hotkey. Nothing is assigned on first load.

Settings

Settings are inline on the shell.json entry. There is no plugin config.json. Widget defaults and schema live under barWidget in manifest.json (the Quattro shape). The service reads the same keys as injected QML properties.

Bar chip (layout entry):

{ "id": "io.github.chris.desktop-undo", "hideChipAtZero": true }

Service (plugins[] entry — fields land on declared QML properties):

{ "id": "io.github.chris.desktop-undo", "extraExclusions": "my-secret-app" }

hideChipAtZero hides the bar chip when there is nothing to undo. The chip stays visible until a hotkey is set, so you can always open the overlay and click Set hotkey. extraExclusions is a comma-separated list of additional window classes that are never journaled.

IPC

omarchy-shell io.github.chris.desktop-undo undo ''
omarchy-shell io.github.chris.desktop-undo redo ''
omarchy-shell io.github.chris.desktop-undo status ''
omarchy-shell shell summon io.github.chris.desktop-undo
omarchy-shell shell hide io.github.chris.desktop-undo
omarchy-shell io.github.chris.desktop-undo installBinds ''
omarchy-shell io.github.chris.desktop-undo removeBinds ''

The service registers an IpcHandler target of the same id. Those handlers take a string argument. omarchy-shell shell call io.github.chris.desktop-undo <method> '' also works: it invokes the overlay, which forwards to the service.

Tests (off-device)

node tests/run.js
# helper, if you have cargo:
cargo test --manifest-path src/undo-probe/Cargo.toml

Remove

Uninstall the plugin and remove this plugin's bindings.lua block so no hotkey is left behind.

From the overlay, click Remove hotkey first. That runs compat/uninstall-binds.py, which deletes only the marked -- BEGIN io.github.chris.desktop-undo / -- END io.github.chris.desktop-undo block. Then:

omarchy plugin remove io.github.chris.desktop-undo

While the plugin is still installed you can also run:

python3 ~/.config/omarchy/plugins/io.github.chris.desktop-undo/compat/uninstall-binds.py io.github.chris.desktop-undo

If the plugin is already gone, delete that marked block from ~/.config/hypr/bindings.lua by hand. Removal must not leave persistent binds.