Managing Multiple Projects in a Shared Graph with cgr CLI

The cgr CLI uses project namespaces to isolate multiple codebases within a single graph database while preserving cross-project query capabilities and enabling incremental updates.

Code-Graph-RAG (cgr) is an open-source tool that builds language-agnostic code graphs for retrieval-augmented generation. The cgr command-line interface allows you to capture, store, and query source code from multiple projects within a single shared graph without conflicts. This guide explains how the project namespace system works and how to manage multi-project workflows using commands defined in codebase_rag/main.py.


How Project Namespaces Work in cgr

Every node and edge in a cgr graph carries a project attribute that identifies its originating codebase. When you run cgr capture, the CLI extracts this value from the --project flag and attaches it to all captured entities via decorators in codebase_rag/decorators.py.

The architecture separates concerns across three layers:

  1. Capture Layer (codebase_rag/capture.py) — Parses source files using Tree-Sitter and produces normalized Node and Edge objects.

  2. Graph-Update Layer (codebase_rag/graph_updater.py) — Persists captured data to the backing database (Memgraph by default), merges duplicates based on signature + project, and ensures idempotent updates.

  3. Query Layer (codebase_rag/graph_loader.py and CLI commands in codebase_rag/main.py) — Loads graph data for read operations with optional project filtering.

This design means projects coexist peacefully: same-named functions from different codebases remain distinct because their project attributes differ, yet you can still query across all projects when needed.


Adding Projects to a Shared Graph

Capturing Your First Project

Initialize the graph with any codebase by specifying a unique project name:

cgr capture ./my-api --project my-api

The capture sub-command in codebase_rag/main.py forwards the path to codebase_rag/capture.py, which walks the directory, parses supported files, and yields entities. The GraphUpdater class in codebase_rag/graph_updater.py then writes these to the database with project: "my-api" labels.

Adding Subsequent Projects

Capture additional codebases using different --project values:

cgr capture ./shared-lib --project shared-lib
cgr capture ./legacy-service --project legacy-service

Each invocation creates or updates only the nodes and edges belonging to that project. Existing data from other projects remains untouched.

Incremental Updates for Existing Projects

Re-running capture on the same project updates changed entities without duplicating unchanged ones:

cgr capture ./my-api --project my-api

The deduplication logic in codebase_rag/graph_updater.py matches nodes by their composite key (symbol signature + project) and performs MERGE operations rather than blind inserts.


Querying Across and Within Projects

Project-Agnostic Queries (All Projects)

Omit project constraints to search the entire graph:

cgr query "MATCH (f:Function) RETURN f.name, f.project ORDER BY f.project"

This executes through the query handler in codebase_rag/main.py, which passes the Cypher statement to codebase_rag/graph_loader.py for execution against Memgraph.

Project-Specific Isolation

Filter results to a single project using Cypher WHERE clauses:

cgr query "MATCH (f:Function) WHERE f.project = 'my-api' RETURN f.name, f.file_path"

Or combine with other predicates:

cgr query "
  MATCH (f:Function)
  WHERE f.project = 'shared-lib' AND f.name CONTAINS 'validate'
  RETURN f.name, f.docstring
"

Cross-Project Relationship Analysis

The project attribute on edges enables powerful cross-project queries. Find calls that span project boundaries:

cgr query "
  MATCH (caller:Function)-[c:CALLS]->(callee:Function)
  WHERE caller.project <> callee.project
  RETURN caller.name, caller.project, callee.name, callee.project
"

Or locate which projects depend on shared-lib functions:

cgr query "
  MATCH (consumer:Function)-[:CALLS]->(lib:Function {project: 'shared-lib'})
  RETURN DISTINCT consumer.project AS dependent_project, count(*) AS call_count
  ORDER BY call_count DESC
"

Core Implementation Files

Understanding these source files helps troubleshoot multi-project issues and extend cgr functionality:

  • codebase_rag/main.py — Defines CLI entry points including capture, query, and serve sub-commands. Parses --project arguments and orchestrates calls to capture and update layers.

  • codebase_rag/graph_updater.py — Contains GraphUpdater class with update_graph() method that handles node/edge persistence, project attribute injection, and merge-on-conflict logic.

  • codebase_rag/graph_loader.py — Provides GraphLoader class for read-only graph access with helper methods for project-scoped queries.

  • codebase_rag/capture.py — Implements capture_directory() and language-specific capture functions that produce intermediate representations before graph persistence.

  • codebase_rag/decorators.py — Supplies @with_project decorator that attaches project metadata to captured entities during the capture pipeline.


Best Practices for Multi-Project Graphs

  1. Use consistent project naming — Choose stable identifiers (repository names or package names) since the project attribute becomes part of node identities. Avoid spaces and special characters that complicate Cypher queries.

  2. Document project relationships — The cross-project query patterns above help visualize architecture. Consider scheduling periodic queries to detect unwanted coupling between systems.

  3. Separate staging and production captures — Use project names like my-api-staging and my-api-prod if you need to compare code graphs across environments.

  4. Monitor graph growth — Each project adds nodes and edges. Use cgr query "MATCH (n) RETURN count(n)" periodically to track size and plan database capacity.


Summary

  • The cgr capture --project <name> command isolates each codebase using a project namespace attribute on every node and edge.

  • Multiple projects coexist in one shared graph without collision, enabling both isolated per-project queries and cross-project relationship analysis.

  • Incremental updates are automatic—re-capturing a project merges changes without duplicating existing data, handled by codebase_rag/graph_updater.py.

  • The cgr query command accepts any Cypher, with WHERE f.project = '...' clauses providing fine-grained isolation when needed.

  • Cross-project edges (CALLS, IMPORTS, etc.) retain source and target project attributes, making boundary-spanning analysis straightforward.


Frequently Asked Questions

How does cgr prevent name collisions between functions in different projects?

Every captured entity receives a project attribute via decorators in codebase_rag/decorators.py. The GraphUpdater in codebase_rag/graph_updater.py uses this attribute as part of the merge key, so my-api/utils.py:parse() and shared-lib/utils.py:parse() remain distinct nodes despite identical local names.

Can I remove a single project without affecting others?

As of the current implementation, cgr does not include a dedicated remove sub-command. You can delete project-specific nodes manually using Cypher: cgr query "MATCH (n {project: 'old-project'}) DETACH DELETE n". Full project lifecycle management may be added in future releases.

What happens if I capture the same directory with two different project names?

cgr treats these as separate projects—nodes and edges are duplicated with different project values. Query both with WHERE n.project IN ['name-a', 'name-b'] or deduplicate downstream. Avoid this pattern unless you intentionally need multiple views of identical code.

Does the project attribute affect query performance?

No significant impact. The project property is indexed by default in codebase_rag/graph_updater.py setup routines, making WHERE f.project = '...' filters efficient even in graphs containing millions of nodes across dozens of projects.

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 →