whirr 0.3.0

A whirring macOS system dashboard for your terminal
docs.rs failed to build whirr-0.3.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

whirr

A macOS system dashboard that lives in your terminal. Run whirr, leave it running all day: processes, CPU, temperature, power draw, memory pressure, network throughput, localhost dev servers and Claude Code sessions — all on one glanceable screen. Named after the sound of a fan spinning up (its logo is one).

(screenshot placeholder — paste a terminal capture of `whirr` at ≥120×30 here)

Why

Everything it shows normally requires either Activity Monitor (mouse-driven, one view at a time) or sudo powermetrics (root, and it owns your terminal). whirr reads the same IOKit / IOReport / sysctl data powermetrics does, but through the read-only channels a normal user account already has access to — no sudo, ever. The one trade-off: processes owned by other users (e.g. WindowServer) don't expose CPU/memory counters without root, so they are not listed.

Built for Apple Silicon. Developed and tested on an M5 running macOS 26; Intel Macs are out of scope — the IOReport power channels whirr reads don't exist there.

Install

brew install scoobynko/whirr/whirr

Or, without Homebrew:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/scoobynko/whirr/releases/latest/download/whirr-installer.sh | sh

Or from crates.io, if you have a Rust toolchain:

cargo install whirr

Both the tap and the installer script ship a prebuilt aarch64-apple-darwin binary — no Rust toolchain required.

git clone https://github.com/scoobynko/whirr && cd whirr
cargo build --release
ln -sf "$(pwd)/target/release/whirr" /opt/homebrew/bin/whirr

The screen

whirr picks one of three layouts from the terminal size. All three share the same design — the burst fan, the bitmap wordmark, the same cards — and differ only in how much room each card gets:

Size Layout
≥ 120×30 Four hero-number gauge cards in one row; processes, network, and three separate cards for localhost / Claude sessions / other listeners
≥ 70×40 (narrower) The same hero cards, stacked 2×2 across two bands — a tall, narrow window keeps the full design rather than dropping to compact
anything smaller Plain readouts instead of hero numbers, and one combined Ports card

Panels drop out in priority order as space gets tight: ports first, then network, then power, then temperature. Processes and CPU always survive.

Keys

Key Action
Tab cycle focus: processes → localhost → Claude sessions → others
/ move the selection within the focused card
c / m sort processes by CPU / memory
k kill the selected process or dev server (SIGTERM, y/n to confirm)
q / Ctrl-C quit

k is deliberately inert on the Claude sessions and others cards: ending a session mid-conversation, or killing a system agent, shouldn't be one keypress away.

Flags

Flag Effect
-h, --help print usage and exit
-V, --version print the version and exit
--no-fan disable the fan animation; the UI then only redraws on new data, a keypress, or a resize — useful on battery or over a slow SSH link
--list-sensors print the raw HID temperature sensors and IOReport Energy Model channels this Mac exposes, then exit (no TTY needed)

Performance budget

whirr is meant to be left running indefinitely, so it's held to a budget: < 0.5% average CPU and < 25 MB RSS. Three sampler threads (2 s / 5 s / 10 s cadence) push immutable snapshots over a channel; the UI thread sleeps until input, data, or the next animation frame, and only redraws when something actually changed. The process table is scanned with raw libproc calls (one proc_pidinfo per pid, names cached) — ~1 ms per pass instead of the ~35 ms a full sysinfo process refresh costs.

Note: the budget is measured on an interactive terminal at normal QoS; sandboxed/background-QoS runs report inflated CPU (~5×) because the whole process is scheduled on efficiency cores at idle clocks.

Releases

Releases are automated from conventional commits: release-plz opens a release PR with the version bump and changelog, and merging it tags the version, publishes to crates.io, and triggers cargo-dist to build the binary and update the tap. See CONTRIBUTING.md.

License

MIT, see LICENSE.