Find cyclic package dependencies

The problem

Have you ever tried to refactor a package and realised, three imports deep, that you couldn't touch it without also touching the package that depended on it, which depended on the one you started with? That's a cycle. It started with one "convenient" import added under deadline pressure. It ends with two (or ten) packages that can never be understood, compiled, or refactored in isolation.

Why it matters

Cycles don't announce themselves. They accumulate. A domain package picks up a single reference to a persistence helper. The persistence helper already imports a shared model. The shared model, well, now it imports the domain. No single developer added a cycle on purpose. But one day you try to extract the domain layer into its own module and discover it drags half the codebase with it. Finding cycles early, and tracking which direction they cross architectural layers, is the difference between a refactor that takes a day and one that takes a quarter.

Where to start

Begin with the Topology Graph with the Cycles section enabled.

Step by step

  1. Open the Topology Graph.

    Choose Analyze → Analyze with AtlasArc, or open the AtlasArc right tool window and run Analyze Project, to build the dependency graph. Directed edges show dependency evidence between the analyzed architecture units.

  2. Enable the Cycles section.

    Open "Cycles" in the left sidebar, enable Only cycles, and keep Hide isolated on. Existing deliberate graph filters remain in place. Packages involved in cycles are highlighted immediately. Each node's header shows its cycle-group number so you can see at a glance which packages share a cycle.

  3. Inspect each cycle group.

    Click any highlighted package to select its cycle group. The sidebar shows all members of the group, the depth of the cycle path, and the dependency edges that form it. Use the cycle-group navigator to step through groups one at a time.

  4. Inspect the closing evidence.

    For each group, click a participating package and inspect the concrete dependency examples. When source navigation is available, open the reference that closes the loop before deciding how the cycle should be treated.

  5. Choose the first response.

    AtlasArc treats an ungoverned dependency cycle as an architectural violation. Refactor it when it conflicts with the architecture you want. Record a precise Intentional or Debt decision when you want classification, rationale, an optional ticket, search, and lifecycle review. Use a Safe Haven when cycles through a broad known package or source-folder area should stay out of your workspace cycle view.

  6. Keep the decision local, or share it.

    Cycle governance is already useful locally. Commit .atlasarc/governance/cycles.json when you want to share and version those decisions or apply them in AtlasArc.io CI. Safe Havens remain remembered workspace decluttering rather than repository policy.

Interpreting results

Architectural is not vague marketing language here. Red architectural cycles, orange aggregation cycles, and yellow nested cycles are distinct AtlasArc classifications. Every ungoverned dependency cycle is an architectural violation; your intended design tells you which one to tackle first. Start with cycles that cross a boundary you care about, then inspect the concrete edge that closes the loop. The cycle-group count in the metrics bar gives you a clean baseline for the next review.

Export & share

Use Export → PNG to capture the current graph with cycle groups highlighted. The export respects all active filters, so you can zoom into the affected area and export just that region for a code-review discussion or architecture decision record.