You already know which files matter. entr waits on that list and runs the command when one of them changes. No daemon, no config file.
entr reads filenames on stdin and runs the utility you give it when one of those files changes. It uses kqueue or inotify, so it is not polling. The usual shape is a find or ls piped into entr. It stays in the foreground until you stop it. Checked on entr 5.9: -n (no TTY games) and -c (clear before run) fired echo entr-ok when the watched file was touched.
install
# macOS
brew install entr
# in the default repos
sudo apt install entr
# in the default repos
sudo dnf install entr
# Arch extra
sudo pacman -S entr
examples
# Clear the screen and rerun when a .py file changes. This stays in the foreground — Ctrl-C to stop
ls *.py | entr -c python main.py
# Restart a long-running process on change. -r is in entr -h; the child is signaled, not left running
ls *.js | entr -r node app.js
# Non-interactive, for a script or a session without a TTY
printf 'watched.txt\n' | entr -n echo changed
pro tip
The man page uses /_ as a placeholder for the first file that changed: echo my.sql | entr -cp psql -f /_. -p waits for the first change instead of running immediately. That is the one you want when the first run would be noise.
honest limits
entr does not watch a tree by itself. You hand it names. A file created after it starts is invisible unless you passed -d and listed the directory. Docker for Mac and WSL have incomplete inotify; the project documents ENTR_INOTIFY_WORKAROUND for that, and you should believe the miss before you believe the tool is broken. It is not a build system.