DiskWatch
A single-host, read-only disk diagnostics TUI covering devices, SMART, IO, volumes, and hot files.
Repository Health
Technical Analysis
DiskWatch is a read-only terminal UI for diagnosing single-host disk problems without reaching for a half-dozen different tools. It reads live device, volume, filesystem, IO, SMART, and hot-file data across eight tabs, or condenses the same signals into a six-box Dense layout or a six-key Lite screen sized for an SSH session onto a NAS.
It runs with zero configuration, resolving colors through the terminal’s existing palette by default so it sits beside other CLI tools rather than imposing its own theme, and it deliberately never writes to or deletes anything on the disks it watches.
What You Get
- An eight-tab full view (Overview, Devices, Volumes, FS, IO, SMART, Hot Files, Insights) that replaces lsblk, iostat, smartctl, df, and fs_usage
- A Dense mode that tiles six btop-style boxes — io, devices, latency, volumes, smart, files — onto one screen with keybinds living in the box borders
- A Lite mode: an 80x24, six-key screen with throughput, a time-to-full capacity projection, and busiest files, sized for a tmux split or SSH session
- Hot-file process attribution that cross-references FSEvents/inotify events against per-process IO and file-descriptor data to name who is writing a busy path
- A zero-config default with an optional
--write-configfile, and a documented CLI > env var > config file > default precedence chain - Prebuilt binaries for Linux and macOS (x86_64/aarch64, musl, armv5te) and Windows, plus Homebrew, Nix, and Arch packages
Common Use Cases
- An engineer opens DiskWatch instead of chaining iostat, iotop, and lsof together when a disk light won’t stop blinking
- Someone SSHed into a home NAS runs
diskwatch --liteto see a days-to-full capacity projection before a volume fills - A sysadmin checks the SMART tab’s wear and temperature figures across attached devices without separate smartctl wrappers per platform
- The Dense view’s latency histogram with p50/p95/p99 buckets shows whether a slow application is caused by disk tail latency
Under The Hood
Architecture
main.rs owns CLI parsing (clap) and a pure resolve() function that folds CLI flags, an environment variable, and a config file into one Resolved settings struct — kept side-effect-free so the precedence rules are unit-tested without touching the filesystem or environment. app::run then builds an App holding one collector per data source (collect::devices, collect::io, collect::smart, collect::hot_files, collect::processes, collect::growth), each polled on its own cadence inside App::tick — 5Hz IO sampling, a 1Hz usage refresh, a 30s slow metadata rescan, and a user-configurable SMART interval. Presentation is split cleanly from collection: tabs/ renders the eight-tab full view, ui/ holds the Dense and Lite screens plus shared chrome, theme, and graph-style modules, and insights/ recomputes anomaly detection as pure functions over current state each tick. Each view (full, Lite, Dense) owns its entire key-handling surface via separate handle_*_key functions, so a keybinding in one view can’t leak into another.
Tech Stack
Rust 2021 (MSRV 1.75) built on ratatui 0.29 for widget rendering and crossterm 0.28 for the terminal backend, with sysinfo 0.32 for cross-platform system data, clap 4 (derive) for CLI parsing, and anyhow for contextual error propagation. Filesystem events come from notify 7, using its raw (non-debounced) stream so FSEvents on macOS and inotify on Linux both report every write rather than a coalesced summary. Platform-specific collectors read /proc/diskstats and /proc/mdstat on Linux and shell out to ioreg, diskutil, and system_profiler on macOS, with smartctl used opportunistically for SMART attribute tables on both. Release builds use thin LTO, single codegen unit, and stripped symbols for small optimized binaries distributed via crates.io, Homebrew, Nix, Arch, and prebuilt GitHub Releases.
Code Quality
About half the crate’s 35 source files carry colocated #[cfg(test)] unit tests, including an exhaustive suite in main.rs covering every branch of the CLI/env/config precedence chain (flag beats env beats file beats default, in both directions). CI runs cargo fmt --check, cargo clippy -W clippy::all, and cargo test across an ubuntu/macos/windows matrix, plus a Windows-specific mounted-folder IO test run explicitly with --ignored. Fallible paths use anyhow::Result with .context() for descriptive failure chains instead of panicking, and doc comments throughout explain design rationale (why a cadence was chosen, why a flag needs a negation) rather than restating the code.
What Makes It Unique Neither FSEvents nor inotify carries a process id, so DiskWatch infers the writer of a hot file by joining watched paths against per-process IO-rate and open-file-descriptor data, and states its two known blind spots (2-second sampling, unprivileged visibility) directly in the UI rather than presenting the join as an exact measurement. Metrics a platform genuinely can’t expose render as a placeholder rather than shifting the layout, so Dense and Lite look identical across machines. By default every color resolves through the terminal’s own ANSI palette instead of pinning RGB, so a pywal or system-wide terminal theme carries straight through; a designed RGB palette is opt-in for anyone who wants gradient effects instead.