Before the modern watchers, there was entr, and it's still one of the most elegant tools in the category. The idea is pure Unix: you pipe it a list of files (from find, fd, ls, git, anything), and entr runs a command whenever any of those files changes. It does one thing, does it in a tiny C binary, and composes with everything because its input is just a list of filenames on stdin.
Pipe Files In, Run a Command
The composability is the whole design - whatever produces the file list is up to you:
# Re-run tests when any tracked file changes
git ls-files | entr -c ./run-tests.sh
# Reload a server, clearing the screen each time
ls *.py | entr -r python app.py
# React to changes under a directory
fd -e md | entr make docs
Small, Fast, Everywhere
Because it takes its file list from stdin, entr fits into any pipeline and any tool's idea of "which files" - git-tracked files, a fd query, a glob. It's minimal by design: no config, no project model, just a reliable trigger. That simplicity is why it's endured.
Rough Edges and Limitations
- You supply the file list. It doesn't discover files itself; you pipe them in, which is the point but also a step.
- Re-run to pick up new files. A newly-created file isn't watched until you regenerate the list.
- Unix-oriented. Most at home on Linux and macOS.
For a minimal, composable "run this when those change" trigger, entr is a small tool that has more than earned its long life.
Internal link suggestion: link "the modern watchers" to the watchexec post, its feature-rich descendant.