* Extract the speed test gauge cluster into a shared SpeedTestOverlay The dial cluster -- scrim, ignition sweep, self-ranging dials, run-again button -- moves from the network speed test panel into qs.Ui with the labels, unit, title, scale stops, and layer namespace as parameters, so other measurements can wear the same cluster. The network panel keeps its process handling and becomes a thin dressing of the overlay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add a disk speed test and move speed tests under Trigger > Tests omarchy-disk-speedtest streams live write and read MB/s once a second by sampling the backing block device's kernel I/O counters while dd workers generate the traffic, the same way the network test samples the interface counters. The stress data is an incompressible urandom chunk staged in RAM, written with fdatasync per pass and fadvise drop-behind: O_DIRECT silently falls back to the page cache on btrfs, and zeros never reach a compressed filesystem at all. Scratch files are created exclusively per invocation and removed even when a dismissal interrupts the run mid-phase. The omarchy.disk-speedtest panel dresses the shared SpeedTestOverlay with write and read dials in MB/s, titled with the hardware model of the disk under test. The menu grows a Trigger > Tests submenu holding the new Disk Speed Test and the Network Speed Test, which moves there from Setup > Network. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Make the disk speed test reproducible, direct, and read-first Successive runs could swing 40% because the settled figure was just the last one-second sample of a single buffered dd stream, taken while btrfs copy-on-write churned the extent allocator on every rewrite pass and the fadvise cache-eviction dance stayed advisory. The test files are now marked NOCOW, which is what makes O_DIRECT truly direct on btrfs -- with checksums on it silently falls back to the page cache -- and lets every rewrite land in place. Four parallel workers per phase give the device a queue depth it can stretch out on, and the figure the dial settles on is the steady-state average over the whole phase with the first warm-up second excluded, not whatever rate the final second happened to catch. Together this tightens successive runs from +/-40% to a few percent of each other, at the device's actual spec throughput. The read phase now runs first, staged against freshly written files, with the read dial on the left. Workers also only loop while the main script lives, so a dismissal that loses the kill race can no longer leave an orphan hammering the disk forever, and any worker dying before the deadline fails the run instead of passing off partial figures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop the menu aliases from the speed test entries Aliases are reserved for established alternate names users already type, kept for compatibility -- not something new entries pick up by default. Note that in the menu definition header and AGENTS.md so the next entry doesn't repeat it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Group dial readouts with thousands separators A gen5 disk reads five digits; 11,450 scans, 11450 doesn't. Uses the locale's grouping separator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Trim redundant overlay props and unused imports from the speed test panels The network panel restated the overlay's default unit and scale stops, and both panels carried imports and an omarchyPath property nothing uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Publish the specific speed test error whichever handler fires last Process exit and stderr stream-finished have no guaranteed order, so a failure that beat the collector showed the generic message forever even when the command emitted an actionable one; the collector now replaces it once the text lands. Also stop clearing the error on every stdout line: only a new run should do that, or buffered output delivered after a failed exit erases the failure message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Arm the disk speed test cleanup before any scratch file exists A preflight failure -- tmpfs target, missing device statistics, not enough free space -- exited between mktemp and the trap, leaking the scratch files. Cleanup also now unlinks before stopping the workers and sweeps once more after, so even a cleanup cut short by an impatient SIGKILL leaves no names behind and a final worker pass cannot recreate one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
6.2 KiB
Task Guides
Deeper instructions for specific kinds of work live in agents/skills/. Read the
matching guide before starting:
agents/skills/command-metadata.md- adding or changing commands inbin/agents/skills/install-scripts.md- working underinstall/or on system/user setup commandsagents/skills/shell-dev.md- editing the Quickshell desktop undershell/agents/skills/acceptance-tests.md- writing or running graphical acceptance tests undertest/acceptance.d/agents/skills/visual-verification.md- verifying any change with a visual effect in the running UIdocs/migrations.md- creating or changing migrations undermigrations/
Style
- Two spaces for indentation, no tabs
- Use bash 5 conditionals: use
[[ ]]for string/file tests and(( ))for numeric tests - In
[[ ]], don't quote variables, but do quote string literals when comparing values (e.g.,[[ $branch == "dev" ]]) - Prefer
(( ))over numeric operators inside[[ ]](e.g.,(( count < 50 )), not[[ $count -lt 50 ]]) - For strings/paths with spaces, quote them instead of escaping spaces with
\(e.g.,"$APP_DIR/Disk Usage.desktop", not$APP_DIR/Disk\ Usage.desktop) - Shebangs must use
#!/bin/bashconsistently (never#!/usr/bin/env bash) - Scripts under
install/andmigrations/may be sourced and intentionally omit shebangs
Command Naming
All commands start with omarchy-. Prefixes indicate purpose.
The authoritative command group list lives in bin/omarchy in GROUP_DESCRIPTIONS. Keep GROUP_DESCRIPTIONS updated when adding a new command prefix.
Common prefixes include:
cmd-- check if commands exist, misc utility commandscapture-- screenshots, screen recordings, and other capture toolspkg-- package management helpershw-- hardware detection (return exit codes for use in conditionals)refresh-- copy default config to user's~/.config/restart-- restart a componentlaunch-- open applicationsinstall-- install optional softwaresetup-- interactive setup wizardstoggle-- toggle features on/offtheme-- theme managementupdate-- update components
Do not maintain a second exhaustive prefix list here. Consult
GROUP_DESCRIPTIONS when selecting or checking a command group so this
guidance does not drift from the router.
Runtime Environment
$OMARCHY_PATHis set at the top level by the uwsm session environment and is always available to Omarchy runtime code.- Commands in
bin/and Quickshell QML should rely on$OMARCHY_PATH/Quickshell.env("OMARCHY_PATH"); do not derive fallback paths fromHOME,Quickshell.shellDir, or re-export/defaultOMARCHY_PATHmanually.
Privileged Commands
- Follow the "Privilege Escalation" section of
default/agents/skills/omarchy/SKILL.md. It draws thesudo/pkexecline by whether the caller has a terminal to enter a password in, and the repo's own scripts follow it.
Git
- Commits should be atomic: include only one coherent change or fix, and do not mix unrelated work.
- Commit messages should be succinct and describe the change being made.
Helper Commands
Use these instead of raw shell commands:
omarchy-cmd-missing/omarchy-cmd-present- check for commandsomarchy-pkg-missing/omarchy-pkg-present- check for packages (don't use these if you can just useomarchy-pkg-add/omarchy-pkg-drop)omarchy-pkg-add- install packages (handles both pacman and AUR)omarchy-pkg-drop- remove packages; use this instead of rawpacman -R*omarchy-notification-send- send desktop notifications; do not callnotify-senddirectlyomarchy-hw-asus-rog- detect ASUS ROG hardware (and similarhw-*commands)
Commands installed by Omarchy's default package set are runtime invariants. Invoke them directly; do not add defensive omarchy-cmd-present / omarchy-cmd-missing checks around them. Use command-presence helpers only for genuinely optional dependencies or code that can run before the default package set is installed.
Exceptions are allowed for migration and package-helper scripts where the helper may not be available yet, where the helper itself is being implemented, or where direct package-manager behavior is required.
Menu
- The menu definition lives in
default/omarchy/omarchy-menu.jsonc. - Do not add
aliasesto new menu entries. Aliases are reserved for established alternate names users already type, kept for compatibility.
Config Structure
config/- default configs copied to~/.config/default/themed/*.tpl- templates with{{ variable }}placeholders for theme colorsthemes/*/colors.toml- theme color definitions (accent, background, foreground, red/green/yellow/blue/magenta/cyan and bright_* variants)
Tests
Run focused automated tests for the area you changed. Current test entry points:
./test/all- aggregate runner for CLI and shell tests; it intentionally does not run graphical acceptance tests./test/cli- CLI routing, command metadata, theme helpers, and safe dispatch coverage./test/shell- all Omarchy shell tests undertest/shell.d/
New Omarchy shell tests should live in test/shell.d/*-test.sh so ./test/shell picks them up automatically. Source test/shell.d/base-test.sh for shared root-path discovery, assertions, and Node test helpers.
The graphical acceptance suite runs in a disposable VM, not in the active
development session; see agents/skills/acceptance-tests.md.
Visual changes must be verified in the running UI in addition to automated
tests; follow agents/skills/visual-verification.md.
Refresh Pattern
To copy a default config to user config with automatic backup:
omarchy-refresh-config hypr/hyprland.lua
This copies $OMARCHY_PATH/config/hypr/hyprland.lua to ~/.config/hypr/hyprland.lua. The argument
is interpolated into both paths and only checked with [[ -e ]], so pass a plain relative path: a
name containing .. resolves and copies, landing outside ~/.config rather than being rejected.