OmarchyDock

A macOS-style dock for the Omarchy shell. Hover the
bottom edge of the screen and it slides up; move away and it hides again.
It can live on any edge — bottom, top, or vertical against the left or
right — aligned to the start, centre, or end of that edge (edge/align,
or "Position on screen" in the configurator).
Two sections: pinned launchers on the left (glyphs or app icons, themed
tiles), and — after an automatic divider — every running app that isn't
pinned, derived live from the compositor and never written to config.
Anything running carries an accent indicator; clicking it focuses its most
recent window, wherever it is. Right-click (or click-and-hold, for
trackpads) for the app's own Desktop Actions (its .desktop jump list —
a browser's private window, a launcher's saved hosts…), then New Window,
Pin/Unpin, per-window focus, and Close; Click Opens… makes one of those
actions what a plain click on the icon runs. A click-and-hold can carry
straight on into the menu: keep the button down, slide up onto the row you
want and release there — same as clicking it. Let go on the icon instead
and the menu just stays up. An app whose list changes at
runtime can simply rewrite its .desktop file; the menu picks it up on
the next open. Hover a running app for the pin badge; drag
icons to reorder, and drag across the divider to pin or unpin. App icons
can be colorized to the theme accent so arbitrary apps sit next to your
curated glyphs as one set.
Multiple windows of one app collapse to a single icon with a count badge.
Holding the pointer over a running icon for a beat opens a vertical stack of
live window previews — even for a single window — click one to focus it,
or hit the close badge on a preview to close that window. Once a stack is
up it follows the pointer along the dock, taskbar-style, and folds when you
drift away. Set hoverActivate: true to focus windows as you hover the
stack, full macOS style (off by default: hover-focus steals focus from
wherever you were typing).
The right-click menu dismisses like every other shell popup: click anywhere else or pick a row. Hovering another icon dismisses it too, so a menu opened by mistake never needs a trip off the dock.
It ships as a third-party Quickshell plugin (rdf.dock) plus a settings
GUI (right-click → Dock Settings…, or double-click the dock background)
and a terminal configurator, omarchy-dock-config.
The settings GUI is drawn with the shell's own controls and has two tabs. Items lists everything pinned — add an app (searchable), a command or a divider, reorder with the arrows or ↑/↓, and edit the selected item on the right: name, what it opens, what a click runs, icon or glyph, colour, size, a "only show while" command and the window class it matches. Dock holds the dock-wide settings in sections (position, size, look, running apps, show and hide), each with a reset-to-default button. Everything saves as you go; Undo puts back an item you edited or removed.
Requirements
- Omarchy (Hyprland + the Quickshell-based
omarchy-shell) jqandgum— used by the configuratorinotify-tools— only forscripts/dev-watch.sh
Install
omarchy plugin add https://github.com/Robindfuller/omarchy-dock --enable
That's the whole install: the repo root is the plugin. The dock appears with an empty pinned section and your running apps; right-click any of them to pin, or open the settings GUI (right-click → Dock Settings…). Two optional extras the plugin manager doesn't do:
- Blur behind the dock — copy hypr/dock.lua to
~/.config/hypr/dock.luaand addpcall(require, "hypr.dock")to~/.config/hypr/hyprland.lua. - The configurator on your PATH — the dock always runs its bundled
copy, but for terminal use link it:
ln -s ~/.config/omarchy/plugins/rdf.dock/bin/omarchy-dock-config ~/.local/bin/
From a checkout
git clone https://github.com/Robindfuller/omarchy-dock ~/src/omarchy-dock
cd ~/src/omarchy-dock
./install.sh
install.sh is idempotent, backs up anything real it displaces, and takes
--dry-run if you want to see the plan first. It:
| Step | Destination |
|---|---|
| Links the plugin | ~/.config/omarchy/plugins/rdf.dock → the checkout |
| Links the configurator | ~/.local/bin/omarchy-dock-config → bin/ |
| Links the Hyprland settings | ~/.config/hypr/dock.lua → hypr/dock.lua |
Adds pcall(require, "hypr.dock") |
~/.config/hypr/hyprland.lua |
| Seeds a starter dock entry | ~/.config/omarchy/shell.json |
Everything except shell.json is a symlink back into this checkout, so this
repo stays the single source of truth — edit here, commit here. shell.json
is shared with the rest of the shell, so the dock's entry is merged into it
instead, staged through a temp file and only swapped in once jq confirms
the result still parses and still contains the dock. A broken shell.json
costs the whole bar, not just this plugin.
An existing dock entry is never overwritten; re-running the installer leaves
your settings alone unless you pass --replace-config.
The pcall on the Hyprland require is deliberate: if this checkout is
deleted, the config degrades to "no blur behind the dock" rather than taking
down the whole Hyprland config with a missing-module error.
Configure
omarchy-dock-config # or right-click the dock
The configurator writes straight into the dock's entry in shell.json, which
the shell re-reads on save — changes show up immediately, no restart.
Your dock contents are yours, not the repo's. What ships in
config/shell.dock.json is a neutral starting point (app launcher, browser,
terminal, files) so a fresh install has a working dock. Add your own items
after installing; they live in shell.json and are intentionally not tracked
here. If an item points at a custom .desktop entry or a script, that entry
or script is a prerequisite you install separately.
Settings on the plugin entry:
| Key | Meaning |
|---|---|
items |
The pinned section; {"spacer": true} draws a divider |
showRunning |
The running-apps section (default true; false = the v1 dock) |
runningIndicator |
"dot" (default), "line", or "none" |
tintIcons, tintRunning |
Colorize pinned / running app icons to the theme (defaults false / true) |
hoverActivate |
Row-hover in the window stack focuses that window (default false) |
edge |
Screen edge: "bottom" (default), "top", "left", or "right" — left/right give a vertical dock |
align |
Placement along that edge: "center" (default), "start", or "end" ("left"/"right"/"top"/"bottom" are accepted as aliases) |
iconSize |
Icon edge length in px |
labels |
Show a label beside the hovered item (above a horizontal dock, inward of a vertical one) |
magnify |
macOS-style hover magnification |
tiles, tileStyle, tileOpacity, tileRadius |
Draw items as themed tiles |
cornerRadius, edgeGap |
Shape and offset of the dock card |
fullWidth |
Stretch the card along the whole edge, edge gap on all sides (icons stay centred) |
revealDelay, hideDelay |
Hover-in and hover-out delays in ms |
stackDelay |
Hover dwell before a running icon's window previews open, in ms (default 300) |
hotspotFullWidth, hotspotHeight |
Size of the trigger zone on the dock's edge |
hideOnLaunch |
Hide the dock after activating an item |
showWhenEmpty |
Still reveal when there are no items |
Item keys: exec, desktop, glyph, icon, label, iconScale, tint,
appId, action, spacer, and when (a shell command; the item only
shows when it exits 0).
Glyphs
An item can be drawn as a Nerd Font glyph instead of its app icon, in the
theme's ink, so the dock reads like the rest of the shell rather than a row
of full-colour logos. Both pickers — Icon → Glyph in the settings
GUI and omarchy-dock-config — offer the same catalogue: every icon the
installed Nerd Font can actually draw, around 10,800 of them, from Material
Design, Font Awesome, Devicons, Codicons, Octicons, the distro logos and the
weather set.
That is far too many to scroll, so the GUI picker opens on Popular — a
couple of hundred hand-picked ones covering the apps and actions a dock
usually needs — with a search box and category chips (Apps, Code, Files,
System, Media, Comms, UI, Places, Nature, Symbols, Other, All) above the
grid. Search matches the name, the category and the icon set, so rust,
arrow, weather and dev all work, and typing anything jumps out of
Popular into the full catalogue. Hover a tile to see its name. In the TUI
the same list comes up under gum filter, one glyph per row with its
category appended.
Anything the catalogue misses can still be pasted in by hand — "Paste a
glyph" in the TUI, or "glyph": "" in shell.json. A glyph wins over
icon and over the desktop entry's own artwork.
The list itself is glyphs.json, generated by scripts/build-glyphs.py
from the Nerd Fonts project's own glyphnames.json and filtered against
the cmap of the font that is installed — a glyph the font can't draw would
be a tofu box in the picker, so it never makes the list. Re-run it after a
font upgrade:
./scripts/build-glyphs.py # or --font /path/to/NerdFont.ttf
Click opens a Desktop Action
A desktop-entry item can make one of its own Desktop Actions what a plain
click runs — an RDP launcher's "Work PC" straight from the icon, a
browser's private window. Right-click the icon → Click Opens… and pick
it (the row a click runs wears the glyph in the menu from then on); or
"Click action" in omarchy-dock-config; or "A click opens" in the settings
GUI; or by hand:
{ "desktop": "dev.rdf.Rdp", "action": "connect-work-pc" }
action is the action's id from the .desktop file (Actions= /
[Desktop Action <id>]). With it set the item is a shortcut to that
action: a click always runs it, whether the app is running or not —
that's the point of it (connecting to Work PC must work while Work VM is
up), and the app's own action decides whether to raise an existing session
or start another. The running indicator, hover stack, and the rest of the
menu are unchanged, so focusing a window is one hover or right-click away.
An id the entry no longer ships falls back to the plain click. The hover
label (and the settings list) names the item after the action — "Work PC"
rather than "Remote Desktop" — unless the item carries an explicit label,
which always wins.
How windows are matched to items
The running state keys on the Wayland appId (Hyprland "class"), resolved
per item as: explicit appId (string or array — wins outright), else the
desktop entry's StartupWMClass, else the desktop id itself.
Case-insensitive, tolerant of reverse-DNS tails.
Known limitation: two launchers for the same binary — e.g. chromium
profiles — open windows with the same appId, and the compositor cannot
tell them apart. Fix it at the launcher: add --class=chromium-work to
the work profile's Exec and set that as the item's appId.
Programmatic CLI
The GUI, pin badge, and drag all persist through omarchy-dock-config
subcommands — one validated writer for shell.json (indices 0-based):
omarchy-dock-config pin <appId> [index]
omarchy-dock-config unpin <index>
omarchy-dock-config move <from> <to>
omarchy-dock-config set-item <index> <json>
omarchy-dock-config add <json> [index]
omarchy-dock-config set <key> <json> # dock-level; null unsets
Development
./scripts/dev-watch.sh
Leave that running while you edit Dock.qml and the dock reloads on
save. It exists because the shell watches ~/.config/omarchy/plugins with
inotifywait -r, which does not traverse symlinks — so with the plugin
directory linked here, the shell's own watcher never sees your edits and the
dock silently keeps serving the code it started with. The script watches the
real files and calls omarchy-shell shell rescanPlugins, which clears Qt's
component cache and reloads the QML from disk.
Without the watcher, apply changes by hand:
omarchy-shell shell rescanPlugins # or: omarchy restart shell
Edits to shell.json need none of this — the shell hot-reloads that on save.
Layout
./ the shell plugin itself (manifest.json + Dock.qml at the root,
so the repo installs directly via `omarchy plugin add`)
bin/ omarchy-dock-config, the interactive configurator
hypr/ dock.lua — blur and layer rules for Hyprland
config/ shell.dock.json — the starter dock entry for shell.json
scripts/ dev-watch.sh — reload the shell while editing
Uninstall
Installed through the plugin manager:
omarchy plugin remove rdf.dock
Installed from a checkout:
./uninstall.sh # keeps your dock settings in shell.json
./uninstall.sh --purge-config # drops them too
It only removes symlinks that point back into this checkout, so anything you installed another way is left alone.