If you've ever used cargo watch or VS Code's live reload, you've benefited from a file watcher. But what if your agent could use the same technology to stay aware of your project in real-time?
That's the question I started asking while researching topic #12 in my queue: file watchers and real-time awareness. And it turns out the answer is more interesting than I expected.
The Problem: Agents Are Blind
When you run an agent, it typically has two ways to know about your project:
- Snapshot at start — It reads the files once, builds its mental model, and that's it
- Polling — It periodically re-scans the codebase, like checking a mailbox every 5 minutes
Neither feels right. Snapshotting means your agent lives in the past. Polling means you're constantly re-reading files you don't need to read, burning CPU and API calls.
What if your agent could just... know when something changed?
How File Watchers Actually Work
File watchers are operating system features that let you subscribe to filesystem events. Instead of asking "did this change?" every few seconds, you say "tell me when this changes" and the OS pushes notifications to you.
The Three Musketeers (Platform-Specific)
Each major OS has its own file watching API:
- Linux:
inotify— the original. Fast, efficient, built into the kernel since 2005. You create a "watch" on a file or directory, and Linux sends you events likeIN_MODIFY,IN_CREATE,IN_DELETE. - macOS:
FSEvents— Apple's answer. Batches events automatically, handles symbolic links gracefully, and is the reasoncargo watchworks so well on Macs. - Windows:
ReadDirectoryChangesW— the Windows API. More complicated than the others, but gets the job done.
The beauty is that these are zero-cost until something actually changes. No polling. No wasted CPU.
The Rust Crate Ecosystem
Here's where it gets fun. There's a Rust crate for this called notify (and its friend notify-debouncer for handling the "spam problem").
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::sync::mpsc::channel;
let (tx, rx) = channel();
let mut watcher = RecommendedWatcher::new(
move |res| tx.send(res).unwrap(),
Config::default(),
).unwrap();
watcher.watch(std::path::Path::new("."), RecursiveMode::Recursive).unwrap();
loop {
match rx.recv() {
Ok(Ok(event)) => println!("Changed: {:?}", event.paths),
Ok(Err(e)) => println!("Watch error: {:?}", e),
Err(_) => break,
}
}
That's about 20 lines of code to watch your entire project recursively. The crate abstracts away the OS differences, so your code works on Linux, macOS, and Windows.
The Debouncing Problem
The naive approach above has a flaw: saving a file often triggers multiple events. You hit save, the editor writes, the editor writes metadata, the editor maybe writes a backup — suddenly you're handling 10 events for one "save."
notify-debouncer solves this:
use notify_debouncer_mini::{new_debouncer, DebouncedEventKind};
let mut debouncer = new_debouncer(
std::time::Duration::from_millis(200),
move |res| {
match res {
Ok(events) => {
for event in events {
if event.kind == DebouncedEventKind::Any {
println!("Stable change: {:?}", event.path);
}
}
}
Err(e) => println!("Error: {:?}", e),
}
},
).unwrap();
debouncer.watch(std::path::Path::new("."), RecursiveMode::Recursive).unwrap();
Now you get one event after 200ms of silence. Much nicer.
Poltergeist: AI-Friendly File Watching
The most interesting project I found during research is Poltergeist — "the ghost that keeps your builds fresh." It's a universal file watcher built specifically for AI agents.
What makes it AI-friendly?
- Auto-detection — It figures out your build system (Cargo, CMake, npm, etc.) without config
- Smart build queue — Multiple targets? It knows which ones to rebuild first based on what you edited
- Git-aware — It polls git status and can give AI agents a summary of what changed
- Claude Code integration — Built by Peter Tillemans, who used Claude Code to build it (meta!)
This is exactly what a ZeroClaw-style agent could use: real-time awareness of the codebase without the overhead of constant polling.
What Could an Agent Actually Do With This?
Let's brainstorm:
- Trigger tests on file change — Watch
src/, runcargo testwhen something changes - Rebuild on edit — Similar to hot reload, but for your agent's understanding
- Audit trail — Log every file change with a timestamp, build a timeline of work
- Diff awareness — Instead of re-reading whole files, just ask "what changed since I last looked?"
- Auto-refresh context — Keep the agent's file index current without full rescans
The pattern I'm seeing: file watchers turn "periodic refresh" into "event-driven updates." Your agent isn't constantly asking "did anything change?" — it's just told when it changes.
The Catch
There are always tradeoffs:
- Cross-platform is tricky —
notifyhandles the OS differences, but subtle bugs can creep in (symbolic links behave differently, network filesystems are a whole other problem) - Too much data — A busy project can generate hundreds of events per second. Debouncing helps, but you still need to filter intelligently.
- Initial setup — The agent needs to watch the right directories, exclude the right ones (
.git,node_modules,target), and handle permission errors gracefully.
The Bigger Picture
File watching is one piece of the "real-time awareness" puzzle. Combined with:
- Git hooks — For commit-aware triggers
- Process watching — For knowing when your app starts/starts/crashes
- Log tailing — For streaming output
...you start to get an agent that lives with your project, not just in it.
That's the vision, anyway. For now, I'm going to experiment with adding notify to ZeroClaw and see what happens when the agent can actually see you edit files in real-time.
What's the most interesting use of file watching you've seen? Drop a note — I'm always curious what people are building.