A cross-platform file system watcher utility built with Rust that monitors file and directory changes in real-time.
knotify is a command-line tool that watches specified files and directories for changes and reports events in a structured format. It leverages the notify crate to provide efficient, cross-platform file system monitoring with support for various backends (inotify on Linux, kqueue on macOS/BSD).
- Multi-path watching: Monitor multiple files and directories simultaneously
- Recursive monitoring: Watch entire directory trees recursively
- JSON output: Structured event output in JSON format
- Event filtering: Filter events by type (create, modify, remove, rename)
- Smart event handling: Automatic filtering of metadata and access events
- Cross-platform: Works on Linux, macOS, Windows, and BSD systems
- Real-time monitoring: Instant notification of file system changes
- Rust 1.70 or later
- Cargo (comes with Rust)
# Clone the repository
git clone
# Build the project
cargo build --release
# The binary will be available at ./target/release/knotifycargo install --path .knotify --path <PATH> [OPTIONS]| Argument | Description | Required | Default |
|---|---|---|---|
--path |
One or more paths to watch (can be specified multiple times) | Yes | - |
--recursive |
Watch directories recursively | No | false |
--backend |
Backend to use: auto, inotify, or kqueue |
No | auto |
--json |
Output events in JSON format | No | true |
--debounce |
Debounce delay in milliseconds | No | 100 |
--log |
Log level: error, warn, info, debug, trace |
No | info |
--once |
Exit after first event (useful for testing) | No | false |
--filter |
Filter events by type (comma-separated): create, modify, remove, rename |
No | All events |
knotify --path /path/to/directoryknotify --path /path/to/dir1 --path /path/to/dir2 --path /path/to/file.txtknotify --path /path/to/directory --recursiveknotify --path /path/to/directory --backend inotifyknotify --path /path/to/directory --backend kqueueknotify --path /path/to/directory --json falseknotify --path /path/to/directory --onceWatch only for file creation events:
knotify --path /path/to/directory --filter createWatch for create and modify events only:
knotify --path /path/to/directory --filter create,modifyWatch for file deletions only:
knotify --path /path/to/directory --filter removeWatch for rename events only:
knotify --path /path/to/directory --filter renameknotify reports the following event types in JSON format:
CREATE_FILE- A file was createdCREATE_FOLDER- A directory was createdCREATE- Generic creation event
MODIFY_CONTENT- File content was modifiedMODIFY_SIZE- File size changedMODIFY_DATA- Generic data modificationMODIFY- Generic modification event
RENAME_FROM- Source of a rename operationRENAME_TO- Destination of a rename operationRENAME_BOTH- Complete rename eventRENAME- Generic rename event
REMOVE_FILE- A file was deletedREMOVE_FOLDER- A directory was deletedREMOVE- Generic removal event
Events are output as JSON objects with the following structure:
{
"kind": "CREATE_FILE",
"paths": ["/path/to/file.txt"]
}{
"kind": "MODIFY_CONTENT",
"paths": ["/path/to/modified-file.txt"]
}{
"kind": "REMOVE_FILE",
"paths": ["/path/to/deleted-file.txt"]
}.
├── Cargo.toml # Project manifest and dependencies
├── src/
│ ├── main.rs # Application entry point
│ ├── config.rs # CLI argument parsing and configuration
│ └── watcher.rs # File system watching logic and event handling
- main.rs (
src/main.rs:1): Entry point that parses CLI arguments and starts the watcher - config.rs (
src/config.rs:1): Defines CLI arguments usingclapand converts them to internal configuration - watcher.rs (
src/watcher.rs:1): Implements theWatchmanstruct that handles file system events and JSON output
- Initialization: The application parses command-line arguments using
clap - Configuration: Arguments are converted to an internal
Configstructure - Watcher Setup: A
notifywatcher is created with the recommended backend for the platform - Event Loop: The watcher monitors specified paths and sends events through a channel
- Event Processing: Events are filtered, categorized, and output as JSON
- Cleanup: Smart filtering ignores metadata and access events to reduce noise
The watcher implements intelligent event handling:
- Metadata events are filtered out to reduce noise
- Access events are ignored
- Rename events are analyzed to detect deletions disguised as renames on macOS
- File existence is checked to distinguish between actual renames and deletions
- clap (v4.5.48): Command-line argument parsing
- notify (v8.2.0): Cross-platform file system notification library
- serde_json (v1.0.145): JSON serialization and deserialization
- Linux: Uses inotify backend
- macOS: Uses kqueue/FSEvents backend
- Windows: Uses ReadDirectoryChangesW backend
- BSD: Uses kqueue backend
cargo run -- --path /path/to/watchcargo testcargo build --releaseknotify supports cross-compilation for multiple platforms using the cross tool.
Install the cross tool:
cargo install cross --git https://github.com/cross-rs/crossOr use the provided Makefile:
make install-crossUse the provided build script to build for all supported platforms:
./build-all.shOr use the Makefile:
make build-allThis will create binaries for:
- Linux (x86_64 and ARM64, both glibc and musl)
- Windows (x86_64)
- macOS (x86_64 and ARM64)
- FreeBSD (x86_64)
Binaries will be placed in target/release-builds/ with platform-specific names.
Use the Makefile targets:
make build-linux # Linux targets only
make build-windows # Windows targets only
make build-macos # macOS targets only
make build-freebsd # FreeBSD targets onlyOr build individual targets using cross:
# Linux (glibc)
cross build --release --target x86_64-unknown-linux-gnu
# Linux (musl - statically linked)
cross build --release --target x86_64-unknown-linux-musl
# Linux ARM64
cross build --release --target aarch64-unknown-linux-gnu
# Windows
cross build --release --target x86_64-pc-windows-gnu
# FreeBSD
cross build --release --target x86_64-unknown-freebsd
# macOS (native build on macOS)
cargo build --release --target x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin| Platform | Target Triple | Notes |
|---|---|---|
| Linux x86_64 (glibc) | x86_64-unknown-linux-gnu |
Standard Linux |
| Linux x86_64 (musl) | x86_64-unknown-linux-musl |
Statically linked, portable |
| Linux ARM64 (glibc) | aarch64-unknown-linux-gnu |
For ARM servers/devices |
| Linux ARM64 (musl) | aarch64-unknown-linux-musl |
ARM, statically linked |
| Windows x86_64 | x86_64-pc-windows-gnu |
Windows 64-bit |
| macOS x86_64 | x86_64-apple-darwin |
Intel Macs |
| macOS ARM64 | aarch64-apple-darwin |
Apple Silicon (M1/M2/M3) |
| FreeBSD x86_64 | x86_64-unknown-freebsd |
FreeBSD systems |
- Development tools: Watch source files and trigger builds/tests on modifications
- Deployment automation: Monitor directories for new files to process (filter:
--filter create) - Log monitoring: Watch log directories for new entries (filter:
--filter create,modify) - Backup systems: Trigger backups when files change (filter:
--filter create,modify) - Security monitoring: Track file deletions for security purposes (filter:
--filter remove) - Content management: Monitor media directories for new uploads (filter:
--filter create) - File synchronization: Detect renames and moves (filter:
--filter rename)
Ensure you have read permissions for all directories you want to watch:
# Check permissions
ls -la /path/to/watch
# Run with appropriate permissions if needed
sudo knotify --path /path/to/protected/directoryOn Linux/macOS, you may hit file descriptor limits when watching many directories recursively:
# Increase the limit temporarily
ulimit -n 4096
# Or set it permanently in /etc/security/limits.confIf experiencing high CPU usage:
- Increase the
--debouncevalue to reduce event frequency - Consider using
--recursive falseif you don't need recursive watching - Filter paths to watch only what's necessary
[Add your license information here]
[Add contribution guidelines here]
[Add author information here]