An Experiment That Returned Zero
Running cross-repo-intelligence across LightRAG and graphrag:
index_repository(
repo_path="/path/to/LightRAG",
mode="cross-repo-intelligence",
target_projects=["mnt-hdd-...-graphrag"]
)Output:
status: success
cross_http_calls: 0
cross_async_calls: 0
cross_channel: 0
cross_grpc_calls: 0
total_cross_edges: 0
elapsed_ms: 109Zero cross-repo edges.
The first instinct is 'the tool found nothing — something failed.' That's wrong. This result is entirely correct, and it's highly informative.
LightRAG and graphrag are two open-source frameworks that do similar things — both graph-based RAG — but they are parallel alternatives, not an integrated system. No LightRAG code calls graphrag's API, and vice versa. cross-repo-intelligence finds integration relationships, not functional similarity. There was never an integration relationship between them; returning 0 is the right answer.
This matters because it draws a clear boundary: cross-repo analysis solves a completely different class of problem than single-repo analysis.
Single-Repo vs Cross-Repo: Two Different Problems
Looking back at the first ten articles, all the questions a single-repo knowledge base can answer live within one repository boundary:
- 'Where is this function?' (symbol path)
- 'Who calls it?' (graph path, inbound)
- 'What does it call?' (graph path, outbound)
- 'Which functions frequently change together?' (FILE_CHANGES_WITH)
These answers are all in the same codebase. The call graph is complete. BFS from any node works.
But when system scope expands across multiple repositories, a class of questions appears that single-repo analysis physically cannot answer:
- 'Which interfaces of Service B does Service A call?'
- 'If I modify Service B's
/queryendpoint, which upstream services are affected?' - 'Service C changed the message format it sends to Service D via message queue — can D detect this?'
- 'In the entire microservice network, who are the central nodes, who are the islands?'
These answers span repository boundaries. A single-repo call graph stops dead at the service boundary — the graph becomes a map with 'dangling terminal nodes' that call some external URL, but don't know who handles that URL.
cross-repo-intelligence connects those dangling nodes.
How Cross-Repo Edges Are Discovered
The core logic of cross-repo-intelligence mode: match Route nodes against HTTP_CALLS nodes across indexed projects.
Concretely:
-
Discover server-side routes: Scan all indexed projects for
Routenodes (HTTP endpoint definitions). Build apath → projectrouting table. -
Discover client-side calls: Scan
HTTP_CALLSedges (HTTP requests in the code). Extract the target URLs or path patterns. -
Path matching: For each
HTTP_CALLSedge, look for a matchingRoutein other projects. When found, create aCROSS_HTTP_CALLSedge that crosses the repository boundary, connecting the caller to the callee.
The same logic applies to:
CROSS_ASYNC_CALLS: message queues (Kafka topic names, RabbitMQ exchanges, etc.)CROSS_GRPC_CALLS: gRPC service/method namesCROSS_CHANNEL: other named channels (WebSocket channels, Redis pub/sub keys)
This explains why LightRAG × graphrag returns 0: no LightRAG code sends HTTP requests to graphrag's routes, and graphrag doesn't call LightRAG's API. The tool didn't fail — it correctly reported that there is no integration relationship between these two systems.
What Each System's Route Profile Actually Looks Like
Even without cross-repo edges, examining each system's routes reveals their roles immediately.
LightRAG: REST API server
Route nodes (lightrag/api/routers/):
GET /query
POST /query
GET /query/stream
POST /query/stream
GET /health
POST /login
GET /auth-status
GET /graph/label/list
POST /documents/paginated
...LightRAG exposes a full HTTP service interface — document management, querying, graph browsing, health checks. From the cross-repo perspective, it's a callee: if another service sends requests to http://lightrag-host/query, that request becomes one end of a cross-repo edge.
The corresponding code structure: create_query_routes and create_document_routes are massive route registration functions (1,566 lines, complexity 118, cognitive complexity 266) — among the hardest functions in the project, because they handle all the HTTP boundary cases.
graphrag: LLM client
Route nodes (graphrag/):
PATCH / (API root — to LiteLLM)
external: https://litellm.ai
external: https://raw.githubusercontent.com/.../cspell.schema.jsongraphrag isn't a service — it's a command-line tool + Python SDK. Its 'routes' are HTTP calls it makes to external LLM services (LiteLLM) and GitHub, not endpoints it exposes. From the cross-repo perspective, it's a pure caller — if you deploy both graphrag and LightRAG in the same system, graphrag might call LiteLLM (creating CROSS_HTTP_CALLS edges), but graphrag won't call LightRAG and LightRAG won't call graphrag.
This role difference is immediately visible from the route profile: one has real REST API routes, the other only has outbound HTTP client calls.
Where Cross-Repo Analysis Has Real Engineering Value
If LightRAG × graphrag has no cross-repo edges, what kind of system does?
A typical microservice architecture:
Frontend App
└─ CROSS_HTTP_CALLS → API Gateway (gateway-service)
└─ CROSS_HTTP_CALLS → User Service
└─ CROSS_HTTP_CALLS → Auth Service
└─ CROSS_HTTP_CALLS → Order Service
└─ CROSS_ASYNC_CALLS → Kafka: order.created
└─ CROSS_ASYNC_CALLS → Notification ServiceIn this architecture, if User Service's GET /users/{id} interface is being modified (say, a returned field is being removed), cross-repo analysis tells you which services have CROSS_HTTP_CALLS edges pointing to that route — and need to be updated in sync. Pure single-repo analysis can't answer this at all.
cross_service mode trace_path:
trace_path(
function_name="get_user_by_id",
project="user-service",
mode="cross_service",
depth=3
)This call follows HTTP_CALLS → CROSS_HTTP_CALLS → Route edges across service boundaries, returning the full cross-service call chain — from some frontend handler all the way down to a database query in User Service.
Three Practical Cross-Repo Use Cases
Use case 1: Service dependency map
After indexing all microservice projects, query the cross-repo call graph:
MATCH (a)-[r:CROSS_HTTP_CALLS]->(b)
RETURN a.file_path, r.path, b.file_pathThe result is the entire system's service dependency map. Which services are 'hubs' (called by many others), which are 'islands' (no cross-repo calls), whether there are circular dependencies — one query surfaces all of it.
Use case 2: Interface change impact assessment
# 1. Find the interface definition
search_code("GET /api/v2/payments", project="payment-service")
# 2. Find cross-repo callers
trace_path("get_payment", mode="cross_service", direction="inbound")
→ returns all upstream services with CROSS_HTTP_CALLS edges to this routeBefore modifying /api/v2/payments, know which services depend on it. Without cross-repo analysis, this requires manually grep-ing that URL across every repository in the organization — a process with frequent misses.
Use case 3: Message contract tracing
If services communicate via Kafka:
MATCH (producer)-[r:CROSS_ASYNC_CALLS]->(consumer)
WHERE r.channel = "order.completed"
RETURN producer.file_path, consumer.file_pathFind all producers and consumers of the order.completed message. When the message schema needs to change, the full blast radius is visible immediately.
Zero Cross-Repo Edges Still Has Value: Interface Design Comparison
Back to LightRAG and graphrag — no cross-repo edges, but both indexes exist. Holding two indexed projects simultaneously enables something useful even without integration edges: interface design comparison.
LightRAG's query interface:
# LightRAG
async def aquery(self, query: str, param: QueryParam) -> strgraphrag's query interface:
# graphrag
async def local_search(
config: GraphRagConfig,
entities: pd.DataFrame,
communities: pd.DataFrame,
community_reports: pd.DataFrame,
text_units: pd.DataFrame,
relationships: pd.DataFrame,
covariates: pd.DataFrame | None,
community_level: int,
response_type: str,
query: str,
) -> tuple[str | dict, str | list[pd.DataFrame] | dict[str, pd.DataFrame]]Two frameworks doing the same category of thing, with radically different interface philosophies. LightRAG encapsulates all configuration in QueryParam (designed for a service runtime). graphrag expects the caller to manage every DataFrame directly (designed for a batch analytics pipeline).
These interface designs reflect completely different target use cases — and this kind of cross-project interface comparison is one of the most valuable analyses for technology selection decisions. It's also a side-effect of having both projects indexed at the same time, without requiring any cross-repo edges.
Summary
Cross-repo analysis isn't 'single-repo analysis made bigger.' It solves a genuinely new class of problem: connecting knowledge at service boundaries.
Three core conclusions:
-
Zero cross-repo edges is a meaningful answer: it says two systems have no integration relationship — not that the analysis failed. Don't conflate 'the tool found something' with 'the tool worked correctly.'
-
Cross-repo analysis works by route matching: it matches Route nodes exposed by one service against HTTP_CALLS / ASYNC_CALLS edges from another. That's what it can find, and only that. Functional similarity, code style comparison, duplicate logic detection — those are different tools' jobs.
-
Projects with no cross-repo edges still benefit from joint indexing: a cross-repo knowledge base lets you query multiple projects simultaneously. Even without call edges, parallel indexes have analytical value — like interface design comparison.
Next article: we turn to knowledge base evaluation — how do you know your knowledge base is 'good enough'? What metrics matter, how to design evaluation datasets, and what production systems should track when Recall@5 is no longer the only metric that matters.
Follow me at dongqi.dev for more LLM engineering content.
At PrimeSkills, we help engineering teams build cross-repo knowledge bases for multi-service architectures — including service dependency graph construction and cross-service interface change impact assessment. If your team manages multiple microservices, reach out to discuss how to operationalize cross-repo knowledge bases.