enolaDocsMulti-repo analysis

Documentation

Multi-repo analysis

Load a backend and the services that call it into one graph, see which calls resolved and which did not, and grade a change across the seam.

01 · Compose

Load the repositories

A cluster is one config listing repositories. Paths resolve relative to the file, so it means the same thing wherever it runs:

cluster.yamlyaml
repos:
  - api
  - web

For a folder whose subfolders are the repositories, enola cluster init <folder> writes this file for you. Then pass the config wherever a command takes a repository:

Build and inspect the linked graphshell
enola --generate cluster.yaml
enola coverage cluster.yaml

Every repository's .enola/ receives the same complete linked graph. --generate also recognises a folder holding two or more git repositories as a cluster without being asked, writes cluster.yaml there, and says so; --no-cluster indexes the folder as one repository instead.

Or ask your agenttext
Generate a snapshot of /path/to/backend.
Generate a snapshot of /path/to/web-client with append mode.
Show the cross-repo coverage report.

Over MCP, the first snapshot starts the graph and each call with append: true adds a repository. Use a cluster config when the same repository set must be reproduced in CI.

02 · Resolution

How links are established

SignalResolution ruleLimit
HTTPMatch normalised client calls to loaded server routes, by path and method.Dynamic paths and unsupported clients remain unresolved.
gRPC and GraphQLMatch calls to the services and operations that serve them.Calls to services outside the loaded set are external.
MessagingMatch a consumed Kafka topic to the repository that owns it.Computed topic names may not resolve.
ImportsResolve imports that identify another loaded repository.Runtime loading is not an import edge.
Shared codeRecord two repositories declaring the same distinctive types as coupled.No direction and no traversable edge.

The hard part is that the two sides rarely spell an endpoint the same way. In examples/cross-repo the web service calls /api/v2/orders/{id}, while the API registers /orders/{id} on a subrouter mounted at /api/v2 in another function. Enola composes the prefix across that boundary and stores the route at the path it actually answers on, so the call links. It does the same for Express, FastAPI, Axum, Rails and Swift.

enola coverage cluster.yamloutput
  service  classification  detected  resolved  unresolved
  api      isolated              0         0           0
  web      connected             3         2           1
Cross-repo resolution is evidence, not completeness. The one unresolved call above builds its URL at runtime, so it is counted rather than guessed. A service classified coverage_gap made calls Enola could not place, which is different from isolated. Check coverage before relying on an impact analysis.

03 · State

Receipts and reproducibility

Each repository has snapshot metadata. A graph-wide receipt records the participating repositories, their git state, extractor and provider configuration, fact counts, resolved cross-repo edges, and unresolved calls.

  • Record the repository set and revisions when a result is used in review or CI.
  • A different producer set yields a partial verdict over shared facts. A different Enola version, repository identity, or ignore configuration remains non-comparable.
  • A dirty worktree is part of snapshot provenance; it is not equivalent to the recorded commit.
  • Review unresolved calls before treating the reported blast radius as complete.

04 · Query

Use the same graph tools

traverse, find_path, and impact_analysis cross repository boundaries wherever a link was resolved, with no extra step. coverage_report lists the calls that matched and the call sites that did not.

05 · Check

Grade a change across the seam

Everything in Change control works with the cluster config in place of a repository path:

Across servicesshell
enola baseline pin cluster.yaml
# change the api service's routes
enola check cluster.yaml
enola endpoint 'GET /api/v2/orders' cluster.yaml

Rename a route in api and the verdict can name the client in web that called it, while each repository's tests still pass. enola endpoint asks the same question directly, without a baseline. The unused-routes and crossrepo explainers need a cluster; treat unused routes cautiously when coverage is low. The full walkthrough is docs/CLUSTERS.md.