A unified system monitor for the Omarchy Quattro bar: CPU, GPU, memory, and network in one compact bar widget and one tabbed panel — plus a Drives tab. The disk bar segment is off by default when a dedicated GPU is present; on iGPU-only machines it fills the GPU slot instead. Per-process disk attribution is not available. Each panel tab identifies the hardware it is measuring — CPU model and topology, GPU name and driver, installed RAM and swap devices, block devices and mounts — then shows live usage.
Clicking a segment opens the panel on that segment's tab; clicking anywhere else toggles the panel on the last-used tab.
Built against the documented Quattro plugin contract. Supports Omarchy 4
(the Quattro shell). Requires bash ≥ 5, jq, ps (procps), ss
(iproute2), df (coreutils), and awk (mawk or gawk); nvidia-smi only if you have an
NVIDIA card; lspci (pciutils) is optional and used to name AMD/Intel
GPUs.
Quadrant is a third-party plugin and runs unsandboxed with your user permissions. Review the repository before enabling it.
-
Open the Omarchy menu.
-
Choose Setup → Plugins → Add.
-
Enter:
https://github.com/BVisagie/omarchy-quadrant.git -
Read and accept Omarchy's plugin warning, then choose whether to enable Quadrant.
The Add action opens a terminal so the warning, confirmation, and install output remain visible.
omarchy plugin add https://github.com/BVisagie/omarchy-quadrant.gitWithout --enable, Omarchy asks whether to enable the plugin after cloning
and validating it. Choosing no lets you inspect the installed checkout at
~/.config/omarchy/plugins/dev.bvisagie.quadrant/ first. Enable it later
with:
omarchy plugin enable dev.bvisagie.quadrantThe widget starts in the right bar section (barWidget.defaultSection).
Move it with omarchy bar move dev.bvisagie.quadrant --section center.
omarchy plugin update dev.bvisagie.quadrantOmarchy shows the incoming diff, validates the revision, and only then fast-forwards the installed checkout.
From the Omarchy menu, choose Setup → Plugins → Remove, then select Quadrant.
Or remove it from a terminal:
omarchy plugin remove dev.bvisagie.quadrantOmarchy disables Quadrant before removing its git checkout. No sudo or pkexec
is required, and no manual deletion under ~/.config/omarchy/plugins/ is needed.
- Bar segments: CPU, GPU, memory, disk, and network each pair a Nerd Font
glyph (or
C/G/M/D/NwithbarLabels letter) with a live value on one line. Intel GPU prefixes~when the value is a frequency estimate. Network uses compact rates (↑ 1.0K ↓ 99K) in a font-sized stable slot; vertical bars stack those rates on two lines and drop the glyphs. Each segment toggles independently; the slot shrinks to fit. Icon and value sit in a tight pair; neighbouring cells share one small gap rather than a divider, so the slot reads as one composition. The GPU segment and tab are dedicated cards only — integrated graphics live on the CPU tab. When no dedicated GPU is detected, the defaultgputoken is shown as Drives (diskFallbackWithoutGpu, on by default) without rewritingsegments. A disk segment is otherwise off by default so the slot stays compact on a crowded bar; enable it from the Drives tab's Show in bar checkbox or viasegments. Unchecking every segment leaves a compact system-monitor glyph; clicking it still opens the full panel. Vertical bars are supported (segments stack; cells clamp to the 28 px slot and drop the glyph). Values at ≥90% load use the theme urgent color;barPalette vividrestores the original per-resource hues.barLabelsisglyph(default),letter, ornone. - Panel: click the widget.
←/→or1–N(N = visible tabs; GPU is omitted when no dedicated card is present) switch tabs,Rrefreshes the active tab and re-reads hardware identity,Esccloses.Tabkeeps its Quattro meaning (switch to the adjacent bar panel) and is deliberately not used inside Quadrant. Each tab has a Show in bar checkbox (Drives off by default when a dedicated GPU is present) that persists the existingsegmentssetting; hiding a segment never hides its tab. - IPC (for scripts and keybinds):
quickshell ipc -p "$OMARCHY_PATH/shell" call dev.bvisagie.quadrant showTab gpu # cpu | gpu | mem | disk | net
omarchy-shell shell summon dev.bvisagie.quadrant '{}' # open on last-used tab
omarchy-shell shell hide dev.bvisagie.quadrantAll settings live inline on the widget's entry in
~/.config/omarchy/shell.json and are declared in the manifest schema, so
omarchy bar set works:
omarchy bar set dev.bvisagie.quadrant processCount 8
omarchy bar set dev.bvisagie.quadrant networkInterface '"wg0"'| Key | Default | Meaning |
|---|---|---|
segments |
["cpu","gpu","memory","network"] |
Which bar segments to show. disk is valid but off by default when a dedicated GPU is present. Each panel tab's Show in bar checkbox writes this list; an empty list shows a compact system-monitor icon. |
processCount |
5 |
Top-process rows per tab (1–10) |
barIntervalMs |
1000 |
Stream cadence feeding bar + history (250–60000) |
panelIntervalMs |
2000 |
On-demand sampler cadence while the panel is open (500–60000) |
networkInterface |
"auto" |
auto = default route across IPv4 and IPv6, lowest metric wins, IPv4 takes ties |
gpuDevice |
"auto" |
Dedicated GPU for the GPU segment and tab. auto = boot display card among dedicated GPUs when determinable, else card0; or a specific cardN. Integrated cards are not selected. |
integratedGpuDevice |
"auto" |
Which card is integrated graphics on the CPU tab. auto = Intel at 00:02.x or a known AMD APU name; none = treat every card as dedicated; or a specific cardN. |
diskFallbackWithoutGpu |
true |
When no dedicated GPU is detected, show Drives in place of the configured gpu bar token without rewriting segments. |
diskDevice |
"auto" |
auto = physical disk backing / (LUKS/LVM folded), else the largest whole device; or a sysfs name such as nvme0n1 |
barPalette |
"theme" |
theme = urgent color at ≥90% load; vivid = original per-resource hues |
barLabels |
"glyph" |
glyph = Nerd Font icons; letter = C/G/M/D/N; none = value only |
- CPU: user (incl. nice) and system (incl. irq/softirq) are stacked in
the graph;
iowaitis its own series;stealis labeled separately and never folded into "system". The tab header is themodel namefrom/proc/cpuinfowith physical cores / threads, L3 cache, scaling governor, and current/max frequency (scaling_cur_freqwhen present, else the cpuinfo snapshot). When an integrated GPU is present, a GRAPHICS block on this tab shows its identity and live frequency or busy metrics (sampled while the CPU tab is open). - Memory: composition splits RAM into Applications / Kernel
(unreclaimable slab) / Cache (page cache + Buffers + SReclaimable) /
Free. The RAM ring is the primary gauge; the pressure ring is PSI memory
some avg10. PSI is optional per resource — when/proc/pressure/cpuor/proc/pressure/memoryis unreadable that half is JSONnulland the ring shows--, not zero. The process column is "% of RAM". The tab header is installed RAM; swap devices from/proc/swapsare listed (zram includes the active compression algorithm and disk size). - GPU: the GPU tab and bar segment cover dedicated cards only.
AMD reads
amdgpusysfs (gpu_busy_percent,mem_busy_percent, per-engineengine/*/busy_percent, VRAM info, hwmon temp/power, active DPM sclk). NVIDIA runsnvidia-smi(timeout-bounded, row-capped) only while the GPU segment or tab is visible — never in the 1 Hz stream. Discrete Intel uses the same frequency-ratio estimate as the CPU-tab iGPU block. Intel i915 frequency files are read from the DRM card node as well as the PCI device node (and xetile*/gt*/freq0). Integrated Intel (PCI00:02.x) and known AMD APUs appear on the CPU tab instead;integratedGpuDeviceoverrides that mapping. Multi-GPU systems get a dedicated-card selector in the GPU tab; the choice is persisted withomarchy bar set … gpuDevice. The tab header is the card's marketing name: NVIDIA'snvidia-sminame, orlspci -D -mmjoined by PCI slot for AMD/Intel, falling back to vendor + PCI ID when pciutils is not installed. Driver and slot come from sysfsuevent. Per-process GPU attribution is v2. - Disk:
/proc/diskstatsfor whole block devices (/sys/block/<name>), excludingloop*,ram*,zram*(zram is on the Memory tab),fd*,nbd*, andsr*. Device-mapper (dm-*) and md RAID (mdN) with a single physical parent are folded onto that parent — LUKS root onnvme0n1p2is shown asnvme0n1, not asdm-0. RAID across two disks stays selectable asmd0. Rates are 512-byte sectors on the physical (or unfolded) device; busy % isio_ticksover wall time. Capacity per mount comes fromdf -P -B1 -T, skipping virtual filesystems, and the Drives tab lists only mounts that resolve onto the selected disk. Device model and SSD/HDD come from sysfs; NVMe temperature is thenvmehwmon only — same whitelist rule as CPU temp, never a first-readable-sensor fallback.autofollows the disk backing/after that fold, else the largest whole device. A pinned name that is missing after remap shows Pinned disk … is not available; wrapping quotes fromomarchy bar setare stripped on read. Per-process disk I/O is deferred:/proc/<pid>/iois only readable for your own processes, so a half-attributed list would lie. The disk bar segment is off by default when a dedicated GPU is present; on machines with only integrated graphics (or no GPU), Drives fills the vacant GPU slot unlessdiskFallbackWithoutGpuis turned off. Toggle it with Show in bar on the Drives tab. - Network: rates for the selected interface plus 60s down/up history.
Per-process attribution uses per-socket TCP byte counters from
ss -tinp, scoped to the watched interface's addresses (ss is global; the byte counters are not). UDP, sockets on other interfaces, sockets owned by other users, and closed-socket remainders cannot be attributed — they appear as an honest Other traffic row (keyed onpid == 0; a process literally named "Other traffic" can never collide with it). The tab footer says Default route via … when the interface is auto-picked, or Pinned interface … whennetworkInterfaceis set. - Temperature: hwmon whitelist only (
k10temp,coretemp,zenpower,cpu_thermalfor the CPU tab;nvmefor the Drives tab). There is no first-readable-sensor fallback — Quadrant shows--rather than another chip's temperature.
Quadrant runs unsandboxed inside omarchy-shell with your user
permissions — the same model as every Quattro plugin. Concretely:
- Read-only. The plugin sends no signals to other processes and writes
nothing outside a
mktemp -ddirectory under$XDG_RUNTIME_DIR(a FIFO used as the sampler's tick clock, removed on exit). Process actions (terminate from the panel) are deferred to v2 behind anallowProcessActionssetting that defaults off. - No secrets in process data. Process lists read
ps -o comm=— neverargs, never/proc/*/cmdline, neverenviron. - Injection-safe rendering. Every
Textelement bound to script output or process names setstextFormat: Text.PlainText(Qt's default AutoText can interpret HTML-like strings, including inline images). CI enforces this with a check over all QML files. The bar tooltip is rates/percentages (never process comm) and is rendered by the shell's WidgetButton tooltip, which is already PlainText. - Safe transport. Process names, firmware strings, PCI-DB names, and
raw tool output travel as JSON strings built with
jq --arg— never TSV through a name. Thessparser anchors on the kernel's trailingpid=field, so a forged process name cannot borrow another pid.lspci -mmis parsed in Model.js (fixture-tested), never concatenated in bash. - Exact-match icons. Desktop-entry matching for process icons/names is
exact-match only (normalized id, Name, Icon,
StartupWMClass); the rawcommis always shown beside any friendly name. - Failures are visible. A helper that exits non-zero or times out
surfaces an error in the panel — never an empty list presented as "no
activity". QML distinguishes
[]+ exit 0 from failure. - Hardened scripts.
set -euo pipefail, helpers resolved from/usr/bin/<name>first thencommand -v, quoted expansions, POSIX awk only (CI runs the suite under mawk and gawk). - Binaries invoked:
bash,jq,ps,ss,ip,df,timeout,mktemp,mkfifo,nvidia-smi(NVIDIA only, on demand),lspci(optional, one shot at startup / on R). No root, no setcap, no setuid, no daemons.
One long-lived sampler, scripts/quadrant-stream, emits one JSON line per
tick (CPU ticks, meminfo, PSI, vmstat swap counters, per-interface net
counters, per-disk diskstats, default routes, whitelisted CPU temp, cheap GPU
sysfs fields for a dedicated AMD/Intel card, optional scaling_cur_freq). It is a single bash process with
zero fork/exec per tick — timing comes from read -t on a self-held FIFO —
consumed in QML via Process + SplitParser with a restart timer. The
stream ships raw counters only; all deltas and rates are pure functions in
Model.js, tested with node --test against captured fixtures (including
hostile ones). Panel samplers (process-cpu, process-memory,
process-net, gpu-stats, disk-info) run on demand while the panel is
open, each with a kill watchdog. Integrated-GPU metrics use gpu-stats sample
while the CPU tab is open. Hardware identity (scripts/system-info)
runs once at startup and again when the user hits R — never on the 1 Hz
path. disk-info also runs at startup so the Drives tab has identity
before it is opened.
node --test tests/model.test.js # pure-logic tests
bash tests/intel-freq-paths.sh # Intel sysfs path lookup
shellcheck -x scripts/* # script lint (follows sourced helpers)
mawk -f tests/check-plaintext.awk BarWidget.qml Panel.qml tabs/*.qml components/*.qmlCI runs all of the above on every push, with the script smoke tests and the PlainText check under both mawk and gawk.
Pre-publish gate (needs an Omarchy install):
omarchy plugin validate /path/to/omarchy-quadrant
qmllint -I "$OMARCHY_PATH/shell" /path/to/omarchy-quadrant/BarWidget.qml /path/to/omarchy-quadrant/Panel.qmlManual test matrix before publishing: AMD / NVIDIA / Intel dedicated,
Intel or AMD iGPU-only, hybrid iGPU+dGPU, no-GPU,
IPv6-only network, swapless machine, vertical bar, both mawk and gawk as
awk, spinning disk and multi-filesystem machines.
MIT — see LICENSE.






