A native system-monitoring panel for Omarchy: CPU, memory, GPU, disk, network and processes in one large floating window, keyboard-driven, in the spirit of btop but drawn by the shell itself. A bar cell with a quick-reference dropdown sits alongside it for a lighter glance — the full panel stays the deep-dive view.
omarchy plugin add https://github.com/PixelatedContinuum/omarchy-sysmonitor.git --enableThen bind it. In ~/.config/hypr/bindings.lua:
o.bind("SUPER + CTRL + SHIFT + T", "System Monitor", "omarchy-shell shell toggle jharrison.sysmonitor")It is a Quickshell FloatingWindow, so Hyprland tiles it by default. To float and centre it like btop's window, in ~/.config/hypr/hyprland.lua:
o.window({ class = "^org\\.quickshell$", title = "^System Monitor$" }, { tag = "+sysmonitor-window" })
o.window({ tag = "sysmonitor-window" }, { float = true })
o.window({ tag = "sysmonitor-window" }, { center = true })
o.window({ tag = "sysmonitor-window" }, { size = { 1180, 900 } })
-- Omarchy tags every window "+default-opacity" (0.985/0.96). On a dense grid
-- of small numbers even 4% of bleed-through costs legibility.
o.window({ tag = "sysmonitor-window" }, { tag = "-default-opacity" })
o.window({ tag = "sysmonitor-window" }, { opacity = "1 1" })Update with omarchy plugin update jharrison.sysmonitor.
Installing the plugin also registers a bar-widget kind — a compact row of icon-prefixed
readouts (CPU, GPU if a discrete AMD card is detected, memory, CPU temperature, network
throughput), using the same Nerd Font glyph family Quadrant's own bar cell uses so the two
read as one visual language rather than two clashing styles. Click it for a condensed
quick-reference dropdown: the same headline numbers plus disk in an animated grid, and the
top few processes broken into two sections — by CPU and separately by memory. It polls
independently of the full panel, so it stays current whether or not the big window is open.
Not shown anywhere by default; place it in ~/.config/omarchy/shell.json under bar.layout
(left, center, or right):
{ "id": "jharrison.sysmonitor" }It reserves its own edge margin on both sides — the same convention WidgetButton gives
every ordinary bar widget by default — so it won't crowd whatever ends up next to it, no
matter which section it's placed in or which side that neighbor is on. If you'd like even
more breathing room than that as a matter of taste, Omarchy ships a first-party
omarchy.spacer bar-widget — drop one into the array with a pixel size:
{ "id": "omarchy.spacer", "size": 24 }omarchy-restart-shell afterwards. The dropdown has an "Open full monitor" link that runs the
same omarchy-shell shell toggle jharrison.sysmonitor command as the keybinding above — a
second door into the same panel, not a second implementation of it.
omarchy plugin remove jharrison.sysmonitorThat is the whole uninstall. The panel writes nothing outside its own plugin directory, grants no capability to any binary, installs no helper script and adds no system policy file, so removing it leaves no permission behind to revoke and no file elsewhere on the system to clean up.
The keybinding in bindings.lua and the window rules in hyprland.lua from Install are just a
few lines you added by hand — removing the plugin does not touch either file. Leaving them in
place is harmless (the panel's window class simply never appears again), but delete them too
for a clean config.
| Section | Detail |
|---|---|
| CPU | Model, total usage with a rolling history graph, a per-thread heatmap that colours each core by load, load average, and pressure stall (cpu/io/mem) |
| Memory | RAM with a history graph, swap, and zram compression ratio |
| GPU | AMD: model, core and memory-controller utilisation with a history graph, VRAM, power against cap, sclk/mclk, and fan |
| Thermal | Every temperature the machine exposes in one place: CPU package, the GPU's edge/junction/memory sensors, and each NVMe drive, with the hottest summarised in the heading |
| Disk | Per-filesystem usage as an animated ring gauge with the percentage in its center, deduplicated by device |
| Network | Per-interface throughput, with separate down and up history graphs on a shared scale |
| Processes | CPU, threads, runtime, memory; search by name or pid; click for executable path, working directory and full ancestry; terminate, force-kill, renice, or open in lsof |
The three headline percentages sit in the top strip as ring gauges. Each section heading takes its own colour, drawn from the active Omarchy theme's palette, so switching themes recolours the panel with it.
| Key | Action |
|---|---|
j / k, arrows |
Move the cursor |
h / l |
Previous / next section |
1–9 |
Jump to a section |
/ |
Search processes by name or pid |
Enter |
Process detail (or, while searching, apply the filter) |
x |
Terminate the selected process |
s |
Sort by CPU or memory |
p |
Pause the process list |
r |
Refresh everything |
PgUp / PgDn, Home / End |
Scroll |
Esc |
Back, then close (or, while searching, clear the filter) |
Search matches the process name, its full command line (so --flag value style
arguments count), and pid, all as substrings — and, unlike the plain process
list, is never limited to the top processCount rows. That distinction is the
point of the feature: a stuck or idle process (a game window that will not
exit, holding ~0% CPU and memory) sorts to the bottom on every key and drops
out of the capped view entirely, so search is what makes it findable again.
ps %cpu reports CPU time ÷ elapsed time averaged over a process's whole lifetime, scaled to one core. A scanner holding one core of sixteen reports "98%", which reads as nearly the whole machine while the headline says 12%. Both numbers are right and they measure different things.
This panel computes CPU the way btop does — utime+stime deltas between polls, read from /proc/[0-9]*/stat — and the column is share of the whole machine, so it sums toward the headline instead of contradicting it. The per-core figure is in the detail view: "6.1% of 16 threads (98% of one core)".
None. The panel runs entirely as your own user and asks for nothing.
Everything on screen comes from /proc and /sys, both world-readable, plus ps, df and
free, which are ordinary unprivileged commands. The plugin performs no privilege escalation of
any kind: it raises no authentication prompt, installs no system policy file and no helper into a
system directory, grants no file capability to any binary, and asks you to join no group. It
writes nothing outside its own plugin directory. Install it and it works.
The one thing this costs is per-process network bandwidth. Attributing traffic to a process
needs raw socket or eBPF access, which is privileged no matter which tool does it, so the
NETWORK section reports per-interface throughput only. Drive temperature is unaffected and still
shown, read from hwmon like every other sensor on the panel; the SMART fields that genuinely
need root, wear level and error counts, are the deliberate omission.
Process actions are bounded the same way. Terminate, force-kill and renice are offered only for processes you already own, and the panel re-checks the target's owner, command name and elapsed time in the same shell invocation that sends the signal, so a pid reused between the last poll and the keypress cannot be signalled by mistake.
manifest.json → panel.defaults:
| Key | Default | Meaning |
|---|---|---|
pollInterval |
2000 |
Base poll in ms |
showCpuPerCore |
true |
Per-thread CPU grid |
processCount |
14 |
Rows in the process table |
showAllSensors |
false |
Every hwmon reading rather than one per device |
fontScale |
1.25 |
Multiplier over the theme's font tokens |
A panel-kind plugin receives no settings injection from the shell, so the manifest is the config surface. Edit it and run omarchy-restart-shell.
The window is resizable and tileable; nothing assumes the 1180px it opens at. Cores reflow 4 → 2 → 1, the dashboard stacks below 700px, and process columns drop right-to-left as width runs out, with COMMAND absorbing the slack. minimumSize is 360×280.
node test-model.jsAll parsing lives in Model.js: pure functions plus the collector shell scripts, so the panel and the tests run byte-identical commands. The suite exercises them against this machine's real /proc, sysfs, ps and df output. Checks report PASS, FAIL or SKIP; a skip is never counted as a pass. Because nothing here needs privileges, skips should normally be zero: one appearing means a genuine hardware gap on the machine running the suite (no zram, no PSI, no AMD GPU), not something the tests could not reach.
A QML edit needs omarchy-restart-shell to take effect — the FloatingWindow survives hide/show, so reopening the panel keeps the old object and its stale property values.
docs/PLAN.md carries the design history and the traps found along the way.
Omarchy shell (Quickshell). The AMD GPU section needs an amdgpu card present; everything else reads /proc and sysfs directly, with no package to install and no permission to grant. Sections whose source is missing hide themselves rather than rendering empty.
MIT.