How to Set Up and Configure the Multi-Repo Daemon (crg-daemon) for Watching Multiple Repositories

The crg-daemon monitors multiple repositories by spawning individual watcher processes for each entry in ~/.code-review-graph/watch.toml, automatically restarting failed watchers and reloading configuration on file changes.

The crg-daemon is a built-in multi-repository watch daemon included in the code-review-graph toolkit. It eliminates the need to manually manage separate code-review-graph watch processes for each project by centralizing configuration, process management, and health monitoring in a single background service.

Installation and Prerequisites

The daemon ships with the core code-review-graph package and requires no additional dependencies beyond the base installation.

pip install "code-review-graph[all]"

This creates the crg-daemon entry point automatically. You can also access sub-commands through the main CLI via code-review-graph daemon … as documented in the project's command reference.

Configuring the Watch List

The daemon reads its configuration from ~/.code-review-graph/watch.toml. This file defines the session name, logging directory, polling interval, and the list of repositories to monitor.

Manual Configuration

Create or edit ~/.code-review-graph/watch.toml with the following structure:

session_name = "crg-watch"
log_dir = "~/.code-review-graph/logs"
poll_interval = 2

[[repos]]
path = "/home/user/project-a"
alias = "project-a"

[[repos]]
path = "/home/user/project-b"
alias = "project-b"

The helper functions that parse and persist this file are implemented in code_review_graph/daemon.py (lines 40-55). The file generates automatically the first time you run a modifying command, but manual editing is fully supported.

Adding Repositories via CLI

Use the add sub-command to register new repositories without manually editing TOML:


# Add with a custom alias

crg-daemon add /path/to/repo-a --alias repo-a

# Add with default alias (directory name)

crg-daemon add /path/to/repo-b

These commands invoke add_repo_to_config in code_review_graph/daemon.py (lines 97-43), which validates that the target directory contains a VCS marker (.git, .svn, or .code-review-graph) before persisting the entry.

Adding Repositories Programmatically

For automation scripts or custom tooling, import the configuration helpers directly:

from code_review_graph.daemon import add_repo_to_config

# Validate and persist the new repository

config = add_repo_to_config("/path/to/repo-a", alias="repo-a")
print(f"Added repo-a, total repositories: {len(config.repos)}")

Managing the Daemon Lifecycle

Once configured, the daemon manages child processes, PID files, and log aggregation.

Starting the Daemon

Launch the daemon in the background:

crg-daemon start

For debugging or development, keep the process attached to the terminal:

crg-daemon start --foreground

The start command creates a PID file at ~/.code-review-graph/daemon.pid via write_pid (lines 80-85 in daemon.py). On Unix systems, it performs a double-fork to detach from the controlling terminal, then instantiates a WatchDaemon class that:

  • Registers each repository in the central registry via Registry.register (lines 75-82)
  • Performs an initial graph build for repositories without existing databases via _initial_build (lines 97-14)
  • Spawns individual code-review-graph watch child processes per repository via _start_watcher (lines 38-75)

Checking Daemon Status

Verify that the daemon and all child watchers are running:

crg-daemon status

This command uses WatchDaemon.status to report the session name, process IDs for each repository watcher, and alive/dead state by checking both in-process Popen handles and the persisted state file (lines 95-38).

Viewing Logs

Access aggregated logs for troubleshooting:


# Tail the main daemon log

crg-daemon logs --follow

# Tail a specific repository's log by alias

crg-daemon logs --repo project-a --follow

Log files are stored under the directory defined by log_dir (defaulting to ~/.code-review-graph/logs). Each watcher process writes to log_path = self._config.log_dir / f"{repo.alias}.log" as configured in _start_watcher (lines 40-42).

Stopping the Daemon

Terminate all watchers and clean up state:

crg-daemon stop

This command kills all child processes, removes the PID file via clear_pid, and clears persisted state through _clear_state (lines 8-22).

Advanced Configuration and Monitoring

The daemon provides automatic recovery and configuration hot-reloading for production reliability.

Automatic Reloading and Health Checks

Configuration Watching: The daemon uses ConfigWatcher (with a fallback polling mechanism when the watchdog package is unavailable) to detect changes to watch.toml. When modifications occur, it calls reconcile to start, stop, or restart child processes as needed (lines 33-46).

Health Monitoring: Every 30 seconds (_HEALTH_CHECK_INTERVAL = 30), a background thread inspects each child process. Dead or crashed watchers are automatically restarted without manual intervention (lines 74-10).

Removing Repositories

Remove repositories from the watch list using either path or alias:


# By absolute path

crg-daemon remove /path/to/repo-a

# By alias

crg-daemon remove repo-b

Programmatically:

from code_review_graph.daemon import remove_repo_from_config

config = remove_repo_from_config("repo-b")
print(f"Remaining repositories: {len(config.repos)}")

Both approaches invoke remove_repo_from_config in code_review_graph/daemon.py (lines 45-73).

Summary

  • crg-daemon centralizes multi-repository watching through a single configuration file at ~/.code-review-graph/watch.toml.
  • The daemon spawns isolated code-review-graph watch child processes for each repository and manages them via WatchDaemon in code_review_graph/daemon.py.
  • Use crg-daemon add and crg-daemon remove to modify the watch list without manual TOML editing.
  • Automatic health checks every 30 seconds restart failed watchers, while configuration file changes trigger hot-reloading via ConfigWatcher.
  • Logs are partitioned by repository alias and stored in the configured log_dir for isolated debugging.

Frequently Asked Questions

What file format does crg-daemon use for configuration?

The daemon uses TOML format for its configuration file located at ~/.code-review-graph/watch.toml. This file stores the session name, logging directory, poll interval, and a list of repositories with their paths and aliases. The parsing logic resides in code_review_graph/daemon.py.

How does crg-daemon handle crashed watcher processes?

The daemon implements a health check mechanism that runs every 30 seconds (_HEALTH_CHECK_INTERVAL = 30). If a child process terminates unexpectedly, the daemon automatically restarts it using the _start_watcher method, ensuring continuous monitoring without manual intervention.

Can I run crg-daemon without installing the watchdog package?

Yes. While the daemon prefers using watchdog for file system events, it includes a fallback polling mechanism in ConfigWatcher that periodically checks for configuration changes if watchdog is unavailable. This ensures the daemon functions in minimal environments.

Where are the daemon logs stored?

By default, logs are stored in ~/.code-review-graph/logs/. Each repository watcher writes to a separate file named {alias}.log within this directory. You can override this location by setting the log_dir key in watch.toml or using the --log-dir flag during daemon startup.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →