Graph Analysis: Impact Assessment & Architecture Evaluation

SkillDocs & knowledge

Lets your agent use a graph claude skill to map dependencies and see what a code change would break.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Graph Analysis: Impact Assessment & Architecture Evaluation skill

About this capability

Query the project as a dependency graph to assess the blast radius of a change, find dead or risky elements, and evaluate module health. Use when planning a refactor, judging what a change will break, or looking for unused documents.

What this skill tells your AI

The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/graph-analysis/SKILL.md and read by ahel’s review.

Use this skill when assessing the impact of a change, identifying risky elements, evaluating module health, or planning a structural refactor. The graph tables model the entire project as a dependency graph and expose topology metrics on top of it.

When to Read This Skill

  • Before modifying an entity or microflow that might be widely used
  • Before moving elements between modules
  • When assessing architectural health (coupling, cohesion, god nodes)
  • When planning to split a module or extract a bounded context
  • When identifying dead code to remove

Setup: Two-Step Refresh

Two separate commands are needed. The full catalog must exist before community detection runs.

# Step 1: Build the full catalog (activities, widgets, cross-references)
# Skip if already fresh — check .mxcli/catalog.db mtime
./mxcli -p app.mpr -c "REFRESH CATALOG FULL"

# Step 2: Run graph algorithms (community detection, centrality, layers, cycles)
./mxcli -p app.mpr -c "REFRESH CATALOG COMMUNITIES"

What each step populates:

StepTables populated
REFRESH CATALOG FULLGRAPH_GOD_NODES, GRAPH_MODULE_COUPLING, GRAPH_MODULE_COHESION, GRAPH_DEAD_ASSETS, GRAPH_ENTITY_HOTSPOTS, GRAPH_MODULE_DEPENDENCIES, GRAPH_REFKIND_DISTRIBUTION
REFRESH CATALOG COMMUNITIESCOMMUNITIES, COMMUNITY_SUMMARY, GRAPH_CYCLES, GRAPH_LAYERS, GRAPH_CENTRALITY, GRAPH_INTEGRATION_SURFACE

An empty table from the second row is ambiguous unless you check. Step 2 is not a build mode — it augments whatever the catalog is, so Build mode: full says nothing about whether it ran, and before mendixlabs/mxcli#1060 an un-run pass and a genuinely cycle-free project produced the same 0 rows. A query now warns requires refresh catalog communities (not run for this catalog) when the pass is missing, and SHOW CATALOG STATUS has a Graph analysis: line. No warning plus no rows is a real answer; treat anything else as "not computed yet", not as "clean".

REFRESH CATALOG COMMUNITIES with a resolution modifier:

  • REFRESH CATALOG COMMUNITIES — default resolution (balanced granularity)
  • REFRESH CATALOG COMMUNITIES resolution 0.6 — coarser clusters (fewer, larger communities; good for monolith-to-multi-app planning)
  • REFRESH CATALOG COMMUNITIES resolution 2.0 — finer clusters (more, smaller communities; good for identifying sub-modules within a large module)

Use Case 1: Pre-Change Impact Assessment

Run before modifying any entity, microflow, or association. Takes under a minute.

-- Is this element a god node? How many things depend on it?
SELECT Asset, ObjectType, InDegree, OutDegree, Degree
FROM CATALOG.GRAPH_GOD_NODES
WHERE Asset = 'MyModule.MyEntity'

-- What layer is it in? (0 = leaf/data, higher = orchestration)
SELECT AssetName, Layer
FROM CATALOG.GRAPH_LAYERS
WHERE AssetName = 'MyModule.MyMicroflow'

-- Is it a bridge? Would breaking it disconnect subsystems?
SELECT AssetName, PageRank, Betweenness
FROM CATALOG.GRAPH_CENTRALITY
WHERE AssetName = 'MyModule.MyMicroflow'

-- Which community does it belong to? What else is in that cluster?
SELECT c.AssetName, c.CommunityId, cs.Label
FROM CATALOG.COMMUNITIES c
JOIN CATALOG.COMMUNITY_SUMMARY cs ON c.CommunityId = cs.CommunityId
WHERE c.AssetName = 'MyModule.MyEntity'

Interpretation:

  • InDegree > 15: many callers — changing this will require wide testing
  • Betweenness > 100: this element is a bridge; removing or changing its signature will disconnect subsystems
  • High layer number (8+): orchestration-level code; changes propagate downward
  • Layer 0: pure data entity or leaf microflow — changes affect only direct callers

Use Case 2: Dead Code Identification

-- All unreferenced elements project-wide
SELECT QualifiedName, ObjectType, ModuleName
FROM CATALOG.GRAPH_DEAD_ASSETS
WHERE ModuleName NOT IN ('System', 'Atlas_Core', 'Atlas_Web_Content',
    'Atlas_NativeMobile_Content', 'WorkflowCommons', 'CommunityCommons',
    'NanoflowCommons', 'NativeMobileResources', 'WebActions', 'DataWidgets')
ORDER BY ModuleName, ObjectType

False positives to exclude before deleting:

PatternWhy it's a false positive
Microflows named *_ToolRegistered as LLM agent tools dynamically — never called directly in code
ApplicationCore.ASU and ASU_*Configured in project settings, not referenced in MDL
Pages used as workflow user task pagesWorkflow activities reference pages via model GUID, not code edges
Pages used as navigation home pagesNavigation assignments are not code edges
IVK_* microflowsCalled by external systems via published REST/web services
SCH_* microflowsCalled by scheduled events — no code edge

Safe to delete: pages, snippets, and microflows with no inbound edges that do not match any of the patterns above, and that are not referenced in navigation (check SHOW NAVIGATION).


Use Case 3: Module Health (Cohesion & Coupling)

-- Cohesion per module: low % = module does too many things / should be split
SELECT ModuleName, IntraEdges, InterEdges, CohesionPct
FROM CATALOG.GRAPH_MODULE_COHESION
ORDER BY CohesionPct ASC

-- Cross-module coupling: find unexpected entanglements
-- Filter to custom modules by replacing the IN list
SELECT SourceModule, TargetModule, Edges, RefKinds
FROM CATALOG.GRAPH_MODULE_COUPLING
WHERE SourceModule IN ('MyModule1', 'MyModule2', 'MyModule3')
  AND TargetModule IN ('MyModule1', 'MyModule2', 'MyModule3')
ORDER BY Edges DESC

-- Dependency direction breakdown: what kinds of references cross module boundaries?
SELECT SourceModule, TargetModule, RefKind, Edges
FROM CATALOG.GRAPH_MODULE_DEPENDENCIES
WHERE SourceModule = 'MyModule'
ORDER BY Edges DESC

Interpreting CohesionPct:

RangeMeaning
70–100%Self-contained module — good
40–70%Moderate coupling to other modules — watch if it drops further
< 40%Low cohesion — module is a cross-cutter or should be split; investigate whether this is intentional (e.g. an orchestration/startup module)

Coupling RefKinds to watch:

  • retrieve, datasource, create, change: data access across module boundaries — should go through a service microflow in the owning module
  • call: microflow calls across modules — acceptable if intentional API
  • generalize: entity inheritance across modules — hard to refactor, flag as a blocker for splits
  • layout: purely structural, always acceptable

Use Case 4: Community Analysis (Bounded Context Validation)

-- What communities exist, how large are they, which modules do they span?
SELECT CommunityId, Label, Size, Modules
FROM CATALOG.COMMUNITY_SUMMARY
ORDER BY Size DESC

-- Which community does a specific element belong to?
SELECT c.AssetName, c.CommunityId, cs.Label, cs.Size
FROM CATALOG.COMMUNITIES c
JOIN CATALOG.COMMUNITY_SUMMARY cs ON c.CommunityId = cs.CommunityId
WHERE c.AssetName LIKE 'MyModule.%'
ORDER BY c.CommunityId

-- Elements from your module that landed in a foreign community
-- (indicates tight coupling to that community's domain)
SELECT c.AssetName, cs.Label AS CommunityLabel
FROM CATALOG.COMMUNITIES c
JOIN CATALOG.COMMUNITY_SUMMARY cs ON c.CommunityId = cs.CommunityId
WHERE c.AssetName LIKE 'MyModule.%'
  AND cs.Label != 'MyModule'
ORDER BY cs.Label

What to look for:

  • If your module's elements are split across multiple communities, the module spans more than one bounded context — consider splitting it.
  • If elements from module A consistently land in module B's community, module A has a hidden dependency on B's domain.
  • Two communities both labeled the same marketplace module (e.g. AgentCommons appears twice) signals a natural internal split within that module.

Use Case 5: Finding Bridges (Centrality)

-- Top microflows by betweenness in your custom modules
-- High betweenness = bridge; breaking it disconnects subsystems
SELECT AssetName, PageRank, Betweenness
FROM CATALOG.GRAPH_CENTRALITY
WHERE AssetName LIKE 'MyModule.%'
   OR AssetName LIKE 'AnotherModule.%'
ORDER BY Betweenness DESC
LIMIT 20

-- God nodes by PageRank (most influential, not just most-referenced)
SELECT Asset, ObjectType, ModuleName, InDegree, OutDegree, Degree
FROM CATALOG.GRAPH_GOD_NODES
WHERE ModuleName IN ('MyModule1', 'MyModule2')
ORDER BY Degree DESC
LIMIT 20

Betweenness vs Degree:

  • Degree (InDegree + OutDegree): raw connection count. High degree = popular or knows-too-much.
  • Betweenness: fraction of shortest paths in the graph that pass through this node. High betweenness = bridge between clusters. A node can have low degree but high betweenness (a narrow connector between two large clusters).
  • PageRank: recursive importance — being depended on by important things matters more than being depended on by many small things.

Use betweenness to find microflows where an interface change would require coordinating across many callers simultaneously.


Use Case 6: Entity Hotspots

-- Entities used by the most microflows, and across the most modules
SELECT Entity, UsedByFlows, AcrossModules
FROM CATALOG.GRAPH_ENTITY_HOTSPOTS
WHERE Entity LIKE 'MyModule.%'
ORDER BY UsedByFlows DESC

An entity appearing in AcrossModules with 3+ module names is a candidate for an explicit service layer — instead of every module reading it directly, route access through a DS_ or SUB_ microflow in the owning module.


Use Case 7: Dependency Cycles

-- All cycles: self-references (size 1) and mutual references (size 2+)
SELECT AssetName, ModuleName, CycleId, CycleSize
FROM CATALOG.GRAPH_CYCLES
ORDER BY CycleSize DESC, CycleId

Size 1: self-referencing element (e.g. a workflow that references its own context entity — usually harmless). Size 2: mutual reference between two elements — e.g. workflow A calls workflow B which triggers workflow A. Investigate before assuming it's intentional; these can cause infinite loops at runtime. Size 3+: a dependency ring — must be broken before the module can be split or properly layered.

Module cycles are a different query, not a rollup

GRAPH_CYCLES is document-level. Two modules referencing each other almost never means two documents do — Administration calls something in Atlas_Core from one page while Atlas_Core reaches back from another — so GRAPH_CYCLES is correctly empty for a genuinely circular pair of modules. Reading it as "no circular dependencies" was mendixlabs/mxcli#1060. Ask the module question of the module table:

SELECT ModuleName, CycleSize, RefKinds
FROM CATALOG.GRAPH_MODULE_CYCLES
ORDER BY CycleSize DESC, ModuleName

RefKinds names the kinds on that module's edges into the rest of the cycle — the references to go and break, as opposed to everything else the module points at.

The two also read different edges. GRAPH_MODULE_CYCLES uses every reference kind, matching GRAPH_MODULE_COUPLING; the computed asset pass (GRAPH_CYCLES/COMMUNITIES/GRAPH_LAYERS/GRAPH_CENTRALITY) is restricted to the structural kinds so navigational edges do not blur the clustering. On a stock app that is about a third of the edges. GRAPH_ANALYSIS_SCOPE reports the split per kind, which is the query to run when coupling shows an edge and the computed tables act as though it were not there:

SELECT RefKind, Edges, InAssetGraph FROM CATALOG.GRAPH_ANALYSIS_SCOPE
ORDER BY InAssetGraph, Edges DESC

Use Case 8: Monolith-to-Multi-App Planning

For splitting a project into separate Mendix apps connected via OData, REST, or Business Events:

# Use coarse resolution for candidate app groupings
./mxcli -p app.mpr -c "REFRESH CATALOG COMMUNITIES resolution 0.6"
-- Each cross-community edge becomes an integration contract after a split
-- RefKind tells you what protocol would be needed
SELECT * FROM CATALOG.GRAPH_INTEGRATION_SURFACE
ORDER BY SourceCommunity, TargetCommunity

-- 'generalize' edges are blockers — entity inheritance cannot cross app boundaries
SELECT * FROM CATALOG.GRAPH_INTEGRATION_SURFACE
WHERE RefKind = 'generalize'

RefKind to integration protocol mapping (matches the Mechanism column the view computes):

RefKindMechanism labelProtocol after split
associateOData / shared entityOData / shared entity
retrieveOData readOData (read)
create, changeevent / REST writeREST or Business Events
callREST (published microflow)REST (synchronous) or Business Events (async)
generalizeBLOCKER: inheritance across boundaryBlocker — cannot cross app boundaries; must restructure
anything else (e.g. datasource, layout)reviewInspect manually — layouts are UI-only and duplicate per app; others case-by-case

Topological Layer Reference

GRAPH_LAYERS assigns each element a layer number via topological sort (Kahn's algorithm on the dependency DAG):

LayerTypical elements
0Entities, associations — pure data, no outgoing calls
1Leaf microflows: tool callbacks, event handlers, simple helpers
2–3Business logic: workflow triggers, process microflows
4–6Orchestration: agent calls, composites
7+Startup / configuration: ASU chain, import pipelines

Elements at the same layer can be parallelised safely. A microflow calling something at a higher layer than itself indicates a layering violation (upward dependency).


Quick Reference: Which Table Answers What

QuestionTable
How many things depend on X?GRAPH_GOD_NODES (InDegree)
Is X a bridge between subsystems?GRAPH_CENTRALITY (Betweenness)
What layer is X in?GRAPH_LAYERS
What community (bounded context) is X in?COMMUNITIES + COMMUNITY_SUMMARY
Which modules are tightly coupled?GRAPH_MODULE_COUPLING
Is module M self-contained?GRAPH_MODULE_COHESION
What is unused / dead?GRAPH_DEAD_ASSETS
Are there circular dependencies between documents?GRAPH_CYCLES
Are there circular dependencies between modules?GRAPH_MODULE_CYCLES
Why isn't an edge I see in coupling affecting the cycles/layers?GRAPH_ANALYSIS_SCOPE
Which entities are hotspots?GRAPH_ENTITY_HOTSPOTS
What contracts would a split require?GRAPH_INTEGRATION_SURFACE
What reference types cross module boundaries?GRAPH_MODULE_DEPENDENCIES

Related Skills

Signals

GitHub stars
122
Forks
49
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
graph-analysis
Source
github.com/mendixlabs/mxcli