# Real-Time Filesystem Updates with Watchdog Integration in Code-Graph-RAG

> Keep your Code-Graph-RAG knowledge graph synced with live codebases using Watchdog. Instantly propagate filesystem changes to Memgraph for real-time updates.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: how-to-guide
- Published: 2026-08-15

---

**Code-Graph-RAG keeps its knowledge graph synchronized with live codebases by monitoring filesystem changes through Watchdog and propagating updates instantly to Memgraph.**

This architecture eliminates manual re-indexing after every edit. The [`realtime_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py) module orchestrates the entire pipeline—from detecting file events to rebuilding graph nodes and edges—making Code-Graph-RAG suitable for interactive development workflows.

## How the Watchdog Integration Works

### Starting the File System Observer

The `start_watcher()` function in [`realtime_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py) (line 33) initializes a **Watchdog `Observer`** that recursively monitors the target repository directory. This observer runs in a dedicated thread, ensuring non-blocking operation while the main process handles graph mutations.

```bash
python realtime_updater.py /path/to/repo

```

### Event Handling with `CodeChangeEventHandler`

The `CodeChangeEventHandler` class extends `FileSystemEventHandler` and implements three critical responsibilities:

- **Path filtering** — Ignores files matching `IGNORE_PATTERNS` and `IGNORE_SUFFIXES` defined in [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py)
- **Event debouncing** — Coalesces rapid successive saves into single updates
- **Change dispatching** — Triggers the five-step graph update pipeline

Source: [`realtime_updater.py → CodeChangeEventHandler.__init__`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py#L75)

## Hybrid Debounce Strategy for Performance

Filesystem events fire aggressively during saves—especially from IDEs that write temporary files or auto-formatters that touch multiple files. The handler implements a **hybrid debounce** combining two thresholds:

| Parameter | CLI Flag | Default | Behavior |
|-----------|----------|---------|----------|
| Debounce interval | `--debounce` (`-d`) | 5 seconds | Quiet period after last event |
| Maximum wait | `--max-wait` (`-m`) | 30 seconds | Hard ceiling before forced processing |

When an event arrives, the handler stores it and restarts the timer. If the max-wait limit expires, processing triggers immediately; otherwise, the debounce interval governs. Setting `--debounce 0` disables this layer entirely, restoring legacy process-on-every-event behavior.

Source: [`realtime_updater.py → dispatch`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py#L21)

### CLI Configuration Examples

```bash

# Aggressive batching for high-frequency edits

python realtime_updater.py /path/to/repo --debounce 2 --max-wait 10

# Disable debouncing entirely

python realtime_updater.py /path/to/repo --debounce 0

```

## The Five-Step Graph Update Pipeline

The `_process_change_locked()` method (line 30) executes atomic updates through a deterministic sequence:

1. **Delete** stale module and file nodes from Memgraph
2. **Clear** in-memory caches for the affected file
3. **Re-parse** the file (for creates/modifies) and generate generic file nodes
4. **Re-compute** all `CALLS` edges, flushing resolution caches
5. **Flush** accumulated Cypher statements to Memgraph in a single transaction

This sequential design prevents orphaned edges and ensures referential integrity within the knowledge graph.

Source: [`realtime_updater.py → _process_change_locked`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py#L30)

## Thread-Safety Architecture

Two distinct locks protect concurrent operations:

- `self.lock` — Guards debounce state including timers and pending events
- `self._update_lock` — Serializes expensive graph-update transactions

The dual-lock design allows rapid event accumulation without blocking, while ensuring that only one database transaction executes at a time. This prevents race conditions that could leave `CALLS` edges pointing to non-existent nodes.

Source: [`realtime_updater.py → __init__`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py#L99)

## Programmatic API Integration

Embed the watcher in larger Python applications:

```python
from realtime_updater import start_watcher

start_watcher(
    repo_path="/path/to/repo",
    host="localhost",
    port=7687,
    debounce_seconds=3,
    max_wait_seconds=15,
)

```

All CLI parameters have direct equivalents in the `start_watcher()` signature.

## Initial Bootstrap Sequence

Before entering the watch loop, `_run_watcher_loop()` (line 70) invokes `GraphUpdater.run()` for a full repository scan. This guarantees complete base state—subsequent incremental updates build upon accurate foundation rather than partial data.

Source: [`realtime_updater.py → _run_watcher_loop`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py#L70)

## Supporting Files and Responsibilities

| File | Role |
|------|------|
| [`realtime_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py) | Orchestrates Watchdog observer, debounce logic, and update pipeline |
| [`codebase_rag/graph_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_updater.py) | `GraphUpdater` service for Memgraph interaction, parsing, and state |
| [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py) | Debounce defaults, ignore patterns, Cypher templates |
| [`codebase_rag/logs.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/logs.py) | Centralized event logging (`WATCHER_DEBOUNCE_ACTIVE`, `CHANGE_DETECTED`) |
| [`codebase_rag/cli_help.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/cli_help.py) | Help strings for CLI options |

## Why Watchdog Was Selected

- **Cross-platform compatibility** — Native operation on Linux, macOS, and Windows without platform-specific extensions
- **Granular event types** — Distinguishes `FileCreatedEvent`, `FileModifiedEvent`, `FileDeletedEvent` for precise graph mutations
- **Low runtime overhead** — Thread-based observation keeps the main process available for parsing and database I/O

## Summary

- [`realtime_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py) provides the complete real-time filesystem update pipeline for Code-Graph-RAG
- **Hybrid debouncing** balances responsiveness against database load through configurable quiet-period and max-wait thresholds
- **Five-step atomic updates** ensure graph consistency: delete, clear, re-parse, re-compute edges, flush
- **Dual-lock architecture** separates event handling from transaction serialization
- Full bootstrap scan precedes watching to establish complete initial state
- Watchdog enables cross-platform, low-overhead file monitoring without native dependencies

## Frequently Asked Questions

### What happens if I set debounce to zero?

Setting `--debounce 0` disables the debouncing layer entirely. Every filesystem event triggers immediate graph processing, matching the legacy behavior. This maximizes responsiveness but increases database load during rapid edit sequences.

### How does Code-Graph-RAG prevent duplicate processing during IDE auto-save?

The hybrid debounce strategy coalesces rapid successive events. When an IDE writes a file multiple times in quick succession (e.g., formatting on save, then actual save), the timer resets with each event. Processing only occurs after the configured quiet period or when the max-wait ceiling is reached.

### Can I monitor multiple repositories simultaneously?

The current `start_watcher()` implementation accepts a single `repo_path`. For multiple repositories, instantiate separate `CodeChangeEventHandler` and `Observer` instances with distinct Memgraph database names, or run multiple [`realtime_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/realtime_updater.py) processes.

### What file patterns are ignored by default?

The `IGNORE_PATTERNS` and `IGNORE_SUFFIXES` constants in [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py) filter common non-source paths including version control directories, build artifacts, virtual environments, and cache files. Modify these constants or extend the handler's filtering logic for repository-specific exclusions.