CLI tool
blacknon/hwatch avatar
blacknon/hwatch

hwatch keeps a history of your watched command and shows what changed

hwatch: alternative watch command with history, diff view, JSONL logging, and change hooks. since 2018.

1,088 stars29 forksRustMIT

At a glance

What is it?
hwatch is a Rust alternative to the watch command that records every execution result, diffs consecutive runs, can render those diffs as JSONL logs, and can run a hook command when something changes. It is a terminal UI by default with a batch mode for scripting, and the diff renderer is pluggable through dynamic libraries.
Who is it for?
hwatch earns its place when you spend real time staring at a command whose output changes slowly, because the diff view answers what changed rather than what the output is now. Skip it for a quick one off check where a single run of the command is enough, since the TUI and its history buffer cost more than plain watch.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 54 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

watch shows the present, hwatch keeps the past

The problem hwatch addresses is one of attention. The watch command re-runs a program on an interval and redraws the screen with whatever the output is at that moment, so anything that scrolled past is gone. If you are watching a log, a service status, a queue depth or a config file, the question you actually have is what changed between the last two runs, and that question is awkward to answer with a tool that only shows the current state.

hwatch was started in 2018 for exactly this reason, and the README describes it as an alternative watch command that records the result of command execution, can display its history and diffs, and can hook and run commands. The feature list spells out the differences. History is kept when a difference occurs so you can check it later, and the display method for a difference can be changed in real time. Execution results can be output as a log in JSON format, the result can be scrolled, custom keymaps are available, and ANSI color code is supported.

The last item on that list is the one that makes hwatch usable in a pipeline rather than only in a terminal. It is not only a TUI application: the differences can also be written to standard output, and with the batch flag the execution results go to stdout instead. That difference in approach is what separates it from a plain watch loop, which is why the tool is useful both for a human watching a screen and for a script consuming diffs.

The diff renderer is a plugin loaded as a dynamic library

The mechanism behind the diff display is a workspace with two local crates, crates/ansi and crates/diffmode, both published as part of the package at version 0.4.2, and the diffmode crate is what a plugin extends. The README states that diff mode plugins can be loaded as dynamic libraries to add custom diff rendering, and the flag is --diff-plugin. There is a sample plugin in the repository under examples/plugin_cdylib_sample, and the crate list confirms the mechanism: libloading is a direct dependency, which is how a native shared object is brought into the process at runtime.

The diff itself is computed with the similar crate, configured with the serde, unicode, text, inline and bytes features, so the same diff engine covers line, word and character level comparisons. The --diff-output-only flag displays only the lines with differences during line diff and word diff, and --ignore-spaceblock ignores diffs where only consecutive whitespace blocks differ. The --enable-summary-char option collects a character level diff count in the summary, while --no-summary disables the summary calculation entirely, and the README notes that summary computation runs in the background.

The architecture is worth noting: hwatch is a Cargo workspace whose root package holds the binary and whose two local crates are the ANSI handling and the diff modes. The UI is built on ratatui with crossterm, which is why the option list is full of terminal specific toggles such as --border, --with-scrollbar and --mouse.

The aftercommand hook receives the change data as JSON

The hook mechanism is the feature that turns a viewer into something you can build on. The --aftercommand option takes a command that is executed when the output changes, and the information about what changed is passed in JSON format through the environment variable HWATCH_DATA. There is a companion flag, --after-command-result-write-file, which passes the same HWATCH_DATA to the aftercommand as a temporary file path instead of inline JSON data, which is the practical choice when the change payload is large or the command is easier to write against a file.

The logging side of the same idea is the --logfile option, which takes an optional path. Its behaviour has a wrinkle: if a log file is already used, its contents will be read and executed, so a log file is not purely an output sink. The --force-logfile-overwrite flag exists to continue even if an existing logfile is empty or unreadable, and the JSONL format for results is the same shape of data the aftercommand receives.

Two other options change how the command is run rather than how the output is shown. The --use-pty flag runs the command through a pseudo-TTY so that commands which colorize when they think they are on a terminal keep their color output, and --exec runs the command directly rather than through the shell, which the README compares to the -x option of the watch command. The default is to run through a shell, and the --shell option sets that shell, defaulting to sh -c, with the ability to insert the command at a {COMMAND} placeholder.

Installing from a release asset, a package manager or cargo

The most direct route is a release asset from GitHub Releases, and the README lists what is published: Linux x86_64 glibc and musl tarballs, a musl .deb, a Fedora .rpm, an aarch64 musl tarball, macOS x86_64 and aarch64 darwin tarballs, and a Windows msvc zip. The generic tarball install is three commands.

bash
curl -LO https://github.com/blacknon/hwatch/releases/latest/download/hwatch-<VERSION>.<TARGET>.tar.gz
tar xf hwatch-<VERSION>.<TARGET>.tar.gz
sudo install -m 0755 bin/hwatch /usr/local/bin/hwatch

You replace VERSION and TARGET with the values from the asset list, and you should see a single hwatch binary in /usr/local/bin. The generated packages install the same way as any other package.

bash
# Debian/Ubuntu-style systems
sudo dpkg -i hwatch-<VERSION>.x86_64-unknown-linux-musl.deb

# Fedora/RHEL-style systems
sudo dnf install ./hwatch-<VERSION>.x86_64-fedora.rpm

Package managers cover the rest. Alpine has apk add hwatch today, macOS has brew install hwatch and sudo port install hwatch, Arch has paru -S hwatch and yay -S hwatch, Nix has nix profile install nixpkgs#hwatch, conda-forge has conda install conda-forge::hwatch, and mise and asdf are both listed. If you build from source, the last option is cargo install hwatch. Debian packaging has been accepted into unstable, though availability depends on mirror sync, and the README is explicit that Fedora packaging is in progress and not yet available, with EPEL packaging planned after Fedora is finalised.

The flag set is where the real behaviour is documented

The README's usage section is the help output of the tool itself, and it is more informative than a separate options table. A few entries explain behaviour you would otherwise have to guess at.

The --beep flag beeps if the command has a change result, and --chgexit exits when the output changes, with no value meaning it exits after the first change and with N meaning it exits after N changes. That last one turns hwatch into a conditional script, which is the most direct answer to the question of when to use it in automation rather than by hand. The --interval option sets the seconds between updates and defaults to 2, --compress compresses data in memory with the caveat that it may not help when the output is small, and --line-number and --wrap control the presentation.

Two flags are about not disturbing you. --no-title hides the UI on start, and the help text says to use t to toggle it. --no-help-banner hides the Display help with h key message, and --border surrounds each pane with a border frame, optionally with a scrollbar on the right side of the watch pane when that option is enabled. Shell completion is generated for bash, fish and zsh with --completion, and the repository carries a completion directory and a man directory for the man page.

The mouse flag comes with an honest warning in the help text: enabling mouse wheel support may make copying text with your terminal harder, and the suggestion is to hold the Shift key.

Two flags run code, and the README says so plainly

The security section is short and specific, and it is worth reading before the tool goes anywhere near a shared machine. The --diff-plugin flag loads native dynamic libraries, and the instruction is to only load plugins you trust. That is the risk of the plugin design: a diff renderer is a shared object mapped into the process, so a hostile plugin is arbitrary native code, not a rendering bug.

The second risk is command execution. The --shell option, the monitored command itself and --aftercommand all execute commands on the system, and the README says to treat those values as trusted input only. The --aftercommand case is the one people forget, because it is not the thing you typed at the prompt. A configuration that runs hwatch with an aftercommand on a machine where the command output is influenced by untrusted data is a path to execution that does not go through your shell prompt.

The repository has a SECURITY.md file at the root and an AGENTS.md alongside the CONTRIBUTING guide, and the project is MIT licensed with the licence text in the LICENSE file. The version in the Cargo manifest is 0.4.2, matching the 0.4.2 release from 2026-04-29, with 0.4.1 and 0.4.0 both from 2026-04-25, so the 0.4 line arrived in a burst. The last push was on 2026-08-30, and the project is not archived.

Editorial conclusion

hwatch earns its place when you spend real time staring at a command whose output changes slowly, because the diff view answers what changed rather than what the output is now. Skip it for a quick one off check where a single run of the command is enough, since the TUI and its history buffer cost more than plain watch. Before enabling it in a shared environment, read the SECURITY notes, because --diff-plugin loads native code and --aftercommand runs a shell command whenever the output changes.

Frequently asked questions

How do I install hwatch?

You can install a release asset from GitHub Releases with curl, tar and install, use a package manager such as apk, brew, paru, nix profile, conda-forge, mise or asdf, or build from source with cargo install hwatch. Debian packaging has been accepted into unstable, while Fedora packaging is still in progress.

What is the difference between hwatch and the watch command?

hwatch records every execution result and keeps a history of what changed, while offering diff views that can be changed in real time. It can also write the results out as a JSON log and run a hook command when the output changes, and with the batch flag it writes results to stdout.

How do I run another command when the output changes?

Use the --aftercommand option. The change information is passed in JSON format through the HWATCH_DATA environment variable, and the --after-command-result-write-file flag passes it as a temporary file path instead of inline JSON data.

Can hwatch be used in a script?

Yes. The batch flag outputs execution results to stdout, the diff output can be written to standard output, and the chgexit option exits when the output changes, with a value of N meaning it exits after N changes.

Is it safe to load a diff plugin?

The README states that the diff-plugin flag loads native dynamic libraries and that you should only load plugins you trust. It also warns that the shell option, the monitored command and aftercommand all execute commands on the system and should be treated as trusted input only.

Official sources

  1. blacknon/hwatch on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/blacknon-hwatch.svg)](https://hysenlabs.com/projects/blacknon-hwatch)

Was this useful?