# How Codebase-Memory-MCP Detects Code Changes: Git-Based Watcher Architecture

> Discover how Codebase-Memory-MCP detects code changes via its Git watcher. Learn about polling, HEAD commit comparisons, and dirty state checks for efficient re-indexing.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: internals
- Published: 2026-07-04

---

**Codebase-Memory-MCP detects code changes through a lightweight Git-based watcher that polls repositories, compares HEAD commits, checks working tree dirty states, and triggers adaptive re-indexing.**

The DeusData/codebase-memory-mcp project implements a local-first approach to keeping its knowledge graph synchronized with your codebase. Understanding how Codebase-Memory-MCP detects code changes reveals a sophisticated polling mechanism that balances resource efficiency with real-time awareness.

## Project Registration and Baseline Initialization

Before detecting changes, the system must establish a monitoring baseline for each repository.

### Registering Projects with cbm_watcher_watch()

Projects enter the watch list via `cbm_watcher_watch()` in [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) (lines 85-95). This function allocates a `project_state_t` structure for each indexed project, storing metadata required for subsequent change detection cycles.

### Initializing Baselines with init_baseline()

When a project is first registered, `init_baseline()` performs three critical validations:

1. **Repository verification** – Calls `is_git_repo()` to confirm the root directory contains a valid Git repository
2. **HEAD capture** – Records the current commit hash via internal Git operations
3. **File counting** – Executes `git_file_count()` to determine the repository size for adaptive polling calculations

This initialization occurs in [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) (lines 60-78), establishing the reference point against which all future changes are measured.

## Adaptive Polling Mechanism

The watcher employs an intelligent polling strategy that scales with repository size.

### Dynamic Interval Calculation

The polling interval adapts based on tracked file count to prevent resource exhaustion. The calculation follows: **base 5 seconds + 1 second per 500 files**, capped at a maximum of 60 seconds. This logic appears in [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) (lines 64-68), ensuring large monorepos do not trigger excessive Git operations.

### The Background Run Loop

The `cbm_watcher_run()` function implements the continuous monitoring loop (lines 21-30 and 31-46). It repeatedly calls `cbm_watcher_poll_once()` and sleeps in small chunks to enable rapid service shutdown. This architecture ensures the MCP server remains responsive while maintaining vigilance over registered projects.

## Git-Based Change Detection

Every poll cycle executes `check_changes()` to determine if the knowledge graph requires updating.

### Detecting HEAD Movement

The primary change detection mechanism compares the stored baseline against the current repository state:

- **`git_head()`** – Retrieves the current HEAD commit hash to detect new commits, checkouts, or pulls (lines 91-99)
- **Hash comparison** – If the returned hash differs from the stored `project_state_t` baseline, the system identifies a committed change

### Checking Working Tree Status

Beyond committed changes, the watcher detects uncommitted modifications:

- **`git_is_dirty()`** – Examines the working tree for unstaged or uncommitted changes, including submodule dirty states (lines 137-154)
- **Comprehensive coverage** – This captures developer work-in-progress that has not yet been committed but affects code semantics

## Re-indexing and Synchronization

When `check_changes()` identifies modifications, the system triggers automatic knowledge graph updates.

### Triggering the Index Pipeline

Upon change detection, the watcher invokes the registered **`index_fn`** callback (lines 44-51 and 45-53). This function pointer drives the full indexing pipeline, parsing modified files and updating the graph database. Successful re-indexing updates the stored HEAD hash and recalculates the adaptive polling interval for the next cycle.

### Auto-Index Configuration

Users can enable automatic indexing via the configuration command:

```bash
codebase-memory-mcp config set auto_index true

```

When enabled, new projects receive immediate baseline initialization upon first open, and the background watcher maintains continuous synchronization without manual intervention.

## Explicit Change Detection Tool

Beyond automatic polling, Codebase-Memory-MCP exposes a callable RPC for agents requiring immediate change impact analysis.

The **`detect_changes`** MCP tool maps Git diffs onto the knowledge graph, returning affected symbols and risk classifications. This tool, implemented in [`src/mcp/tools/detect_changes.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/tools/detect_changes.c), wraps the same Git-status checks used by the watcher but provides granular visibility into specific modifications.

```bash

# Query symbols impacted by current git diff

codebase-memory-mcp cli detect_changes '{"project":"myproject"}'

```

## Practical Usage Examples

Trigger manual re-indexing when you need immediate updates outside the polling cycle:

```bash
codebase-memory-mcp cli index_repository '{"repo_path":"/path/to/my/project"}'

```

Enable persistent automatic indexing for all future sessions:

```bash
codebase-memory-mcp config set auto_index true

```

Check specific project changes through the MCP tool interface:

```bash
codebase-memory-mcp cli detect_changes '{"project":"myproject"}'

```

## Summary

- **Git-native detection** – Codebase-Memory-MCP relies on Git operations (`git_head()`, `git_is_dirty()`) rather than filesystem hooks, ensuring compatibility across platforms
- **Adaptive polling** – Intervals scale from 5 seconds to 60 seconds based on repository file count, optimizing CPU usage
- **Dual-change detection** – Monitors both committed HEAD movement and uncommitted working tree dirty states
- **Automatic re-indexing** – The `index_fn` callback triggers full pipeline reprocessing when changes are detected
- **Local-first architecture** – All operations run within the [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) implementation without external service dependencies

## Frequently Asked Questions

### How does Codebase-Memory-MCP detect code changes without filesystem watchers?

The system uses a polling-based architecture centered in [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) rather than inotify or FSEvents. Every `cbm_watcher_poll_once()` cycle executes Git commands to compare the current HEAD against the stored baseline and check dirty states. This approach avoids platform-specific filesystem notification APIs while maintaining cross-platform consistency.

### What triggers a re-index in Codebase-Memory-MCP?

Re-indexing occurs when `check_changes()` detects either a moved HEAD (new commits, pull operations, or branch checkouts) or a dirty working tree (uncommitted modifications). The watcher then calls the registered `index_fn` to rebuild the knowledge graph. Users can also trigger manual re-indexing via the `index_repository` CLI command.

### How does the adaptive polling interval work?

The interval calculation in [`src/watcher/watcher.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/watcher/watcher.c) (lines 64-68) starts at 5 seconds and adds 1 second for every 500 tracked files, capped at 60 seconds. This ensures small repositories receive near-real-time updates while massive monorepos do not overwhelm system resources with excessive Git operations.

### Can I disable automatic change detection and run updates manually?

Yes. Set `auto_index` to false using `codebase-memory-mcp config set auto_index false`. With automatic polling disabled, the background watcher skips registered projects, and you must explicitly call `index_repository` or `detect_changes` to synchronize the knowledge graph with your codebase.