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 watchchild 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 watchchild processes for each repository and manages them viaWatchDaemonincode_review_graph/daemon.py. - Use
crg-daemon addandcrg-daemon removeto 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_dirfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →