# How Watch Mode Auto-Updates the Code-Review-Graph on File Changes

> Discover how code-review-graph watch mode auto-updates your graph on file changes. Learn about the CLI daemon and VS Code file watchers that keep your data fresh.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-08-14

---

**The `code-review-graph` VS Code extension implements watch mode through a coordinated two-part system: an external CLI daemon that rebuilds the graph database when source files change, and VS Code-side file watchers that detect those database updates and refresh the UI.**

Watch mode in the `tirth8205/code-review-graph` extension eliminates manual rebuilds by continuously synchronizing the code review graph with your evolving codebase. This article breaks down exactly how the auto-update mechanism works by examining the source code implementation.

## The Watch Mode Architecture

Watch mode operates across process boundaries. The extension delegates file monitoring to a separate CLI process, then reacts to the results through VS Code's file system APIs.

This design separates concerns: the CLI handles expensive parsing and graph construction, while the extension focuses on lightweight UI updates.

## Part 1: Starting the CLI Daemon

When a user triggers watch mode through the **Watch Graph** command, the extension spawns the external `code-review-graph` CLI in watch mode.

### Command Registration in [`extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/extension.ts)

The command palette entry is wired in [`src/extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/extension.ts):

```typescript
// registers the "Watch Graph" command
vscode.commands.registerCommand("codeReviewGraph.watchGraph", async () => {
    const workspaceRoot = getWorkspaceRoot();
    if (!workspaceRoot) {
        vscode.window.showErrorMessage("No workspace folder is open.");
        return;
    }

    vscode.window.showInformationMessage("Code Graph: Watch mode started.");
    const result = await cli.watchGraph(workspaceRoot);
    if (!result.success) {
        vscode.window.showErrorMessage(`Code Graph: Watch failed. ${result.stderr}`);
    }
});

```

The `cli.watchGraph()` call delegates to `CliWrapper.watchGraph()` in [`src/backend/cli.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/cli.ts) (lines 83-86), which launches the CLI with the `--watch` flag.

### What the CLI Daemon Does

Once started, the CLI process:

1. Scans the workspace for source files
2. Builds the initial code review graph
3. Writes the result to `.code-review-graph/graph.db`
4. Enters a **persistent watch loop** monitoring the filesystem
5. Rebuilds affected graph portions on any add/change/delete event
6. Atomically updates `graph.db` with each rebuild

The extension does not poll or directly observe source files—it relies entirely on this external process to detect and process changes.

## Part 2: Watching the Database File

The extension's role begins after the CLI writes its output. Two coordinated watchers detect changes to `graph.db` and trigger UI refreshes.

### The `watchGraphDb()` Function

In [`src/extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/extension.ts) (lines 94-107), `watchGraphDb()` creates a workspace-scoped file watcher:

```typescript
function watchGraphDb(context: vscode.ExtensionContext): void {
    const watcher = vscode.workspace.createFileSystemWatcher(
        "**/.code-review-graph/graph.db"
    );

    const dbPathRef = { current: "" };
    const workspaceRoot = getWorkspaceRoot();
    if (workspaceRoot) {
        const dbPath = findGraphDb(workspaceRoot);
        if (dbPath) {
            dbPathRef.current = dbPath;
        }
    }

    // Reload when the file is written
    watcher.onDidChange(() => {
        if (sqliteReader && dbPathRef.current) {
            sqliteReader.close();
            sqliteReader = new SqliteReader(dbPathRef.current);
            vscode.commands.executeCommand("codeReviewGraph.codeGraph.refresh");
        }
    });

    // Create a new reader on first creation
    watcher.onDidCreate(async () => {
        const wsRoot = getWorkspaceRoot();
        if (wsRoot && !sqliteReader) {
            const dbPath = findGraphDb(wsRoot);
            if (dbPath) {
                dbPathRef.current = dbPath;
                sqliteReader = new SqliteReader(dbPathRef.current);
                vscode.commands.executeCommand("codeReviewGraph.codeGraph.refresh");
            }
        }
    });

    // Dispose the reader when the file is deleted
    watcher.onDidDelete(() => {
        sqliteReader?.close();
        sqliteReader = undefined;
        dbPathRef.current = "";
    });

    context.subscriptions.push(watcher);
}

```

This handler manages three lifecycle events:

- **`onDidChange`** – The most common case: database exists and gets updated. Closes the old `SqliteReader`, instantiates a new one, and triggers view refresh.
- **`onDidCreate`** – Initial database creation, typically after first watch mode start or manual rebuild.
- **`onDidDelete`** – Cleanup when the database is removed, preventing errors from stale file handles.

### The `GraphWatcher` Class with Debouncing

For more controlled observation, [`src/backend/watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/watcher.ts) (lines 25-52) provides a reusable `GraphWatcher` class:

```typescript
export class GraphWatcher implements vscode.Disposable {
    private readonly watcher: vscode.FileSystemWatcher;
    private readonly disposables: vscode.Disposable[] = [];

    constructor(dbPath: string, onChanged: () => void) {
        const dir = path.dirname(dbPath);
        const filename = path.basename(dbPath);

        this.watcher = vscode.workspace.createFileSystemWatcher(
            new vscode.RelativePattern(vscode.Uri.file(dir), filename),
        );

        const debouncedOnChanged = debounce(onChanged, 500);

        this.disposables.push(
            this.watcher.onDidChange(() => debouncedOnChanged()),
            this.watcher.onDidCreate(() => debouncedOnChanged()),
            this.watcher,
        );
    }

    dispose(): void {
        for (const d of this.disposables) {
            d.dispose();
        }
        this.disposables.length = 0;
    }
}

```

The **500ms debounce** prevents rapid-fire refreshes during active editing sessions when the CLI may write multiple incremental updates.

## How the UI Refreshes

After the database reloads, the extension triggers `codeReviewGraph.codeGraph.refresh` via VS Code's command system. This command (implemented in [`src/views/treeView.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/views/treeView.ts)) rebuilds the tree view nodes from the new `SqliteReader` instance without requiring a full extension restart.

The complete data flow:

1. Developer saves a source file
2. CLI daemon detects change → rebuilds graph → writes `graph.db`
3. VS Code `FileSystemWatcher` fires `onDidChange`
4. Extension closes old reader, opens new reader
5. Tree view refreshes with updated graph structure

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`src/backend/cli.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/cli.ts) | `CliWrapper.watchGraph()` starts external CLI in watch mode |
| [`src/backend/watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/watcher.ts) | `GraphWatcher` class provides debounced file observation |
| [`src/extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/extension.ts) | Registers watch command, implements `watchGraphDb()` lifecycle |
| [`src/views/treeView.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/views/treeView.ts) | Handles `codeReviewGraph.codeGraph.refresh` command for UI updates |

## Summary

- **Watch mode uses a two-process design**: CLI daemon monitors source files; VS Code extension watches the output database
- **`CliWrapper.watchGraph()`** in [`src/backend/cli.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/cli.ts) spawns the persistent CLI process
- **`watchGraphDb()`** in [`src/extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/extension.ts) creates a `FileSystemWatcher` for `**/.code-review-graph/graph.db`
- **Database changes trigger reader recreation**: Old `SqliteReader` closes, new instance opens, tree view refreshes
- **`GraphWatcher`** in [`src/backend/watcher.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/backend/watcher.ts) adds 500ms debouncing for stability during rapid updates

## Frequently Asked Questions

### How do I start watch mode in code-review-graph?

Run the **"Watch Graph"** command from the VS Code Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`). This executes `codeReviewGraph.watchGraph`, which starts the CLI daemon. You'll see a confirmation message when watch mode begins.

### Does watch mode work with multiple workspace folders?

The current implementation in [`src/extension.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/extension.ts) uses `getWorkspaceRoot()` to identify a single workspace root. Multi-root workspace support would require extending the watcher to handle multiple `.code-review-graph/graph.db` files simultaneously.

### Why does the graph sometimes take a moment to update?

The **500ms debounce** in `GraphWatcher` and the CLI's rebuild latency both contribute to a brief delay. This intentional throttling prevents UI flicker and reduces resource consumption during active development with frequent file saves.

### What happens if I delete the graph.db file while watching?

The `onDidDelete` handler in `watchGraphDb()` closes the `SqliteReader`, clears the reference, and updates the internal path tracker. The extension gracefully handles deletion; watch mode continues, and the graph will recreate when you restart watch mode or rebuild manually.