# How the Architecture Analyzer Identifies API, Service, Data, UI, and Utility Layers in Understand Anything

> Discover how Architecture Analyzer identifies API, Service, Data, UI, and Utility layers in Understand Anything using directory patterns, import graphs, and semantic heuristics. Enhance your code understanding.

- Repository: [Yuxiang Lin/Understand-Anything](https://github.com/Lum1104/Understand-Anything)
- Tags: architecture
- Published: 2026-06-06

---

**The Architecture Analyzer** in *Understand Anything* detects architectural layers by combining directory pattern matching, import graph topology, and semantic heuristics to classify files into logical groups like API, Service, Data, UI, and Utility.

The analyzer lives in [`understand-anything-plugin/agents/architecture-analyzer.md`](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/agents/architecture-analyzer.md) and operates as a two-phase pipeline that transforms raw file nodes and import edges into a structured [`layers.json`](https://github.com/Lum1104/Understand-Anything/blob/main/layers.json) output. This process discovers classic layered architectures automatically without manual configuration.

## Two-Phase Layer Detection Workflow

The architecture analyzer processes repository structure through distinct structural and semantic phases to produce deterministic layer assignments.

### Phase 1 – Structural Graph Analysis

**Directory grouping** clusters files by the first directory segment after common prefixes like `src/` or `lib/`. This creates initial boundaries for where code lives within the repository structure.

**Node-type grouping** categorizes all nodes by their type—`file`, `config`, `document`, `service`, `pipeline`, and others. This exposes non-code artifacts that often become separate layers such as *Infrastructure*, *Documentation*, or *Configuration*.

**Import adjacency and fan-in/fan-out** metrics build an adjacency list for every file, counting how many files it imports (fan-out) and how many import it (fan-in). The analyzer aggregates these metrics per directory group to produce an **inter-group import matrix** that reveals dependency patterns between clusters.

**Pattern matching** compares directory names against a curated table of architectural patterns. Known mappings include `routes` → **api**, `services` → **service**, `models` → **data**, `components` → **ui**, and `utils` → **utility**. File-level glob patterns like `*.test.*`, `*.d.ts`, or `Dockerfile` provide additional classification hints.

**Cross-category edges** count relationships between non-code node types (such as `config` → `file` or `service` → `file`) to identify *Infrastructure*, *CI/CD*, and *Documentation* layers.

**Density and dependency direction** calculations determine intra-group import density (high density indicates a cohesive layer) and establish the dominant import direction between groups, creating a **dependency hierarchy** where top layers depend on lower layers.

### Phase 2 – Semantic Layer Assignment

Using the structural output, the analyzer selects 3–10 layers and assigns every node to exactly one.

Directory groups become layer candidates. If a group matches a pattern label, that label becomes the layer name. **Intra-group density** exceeding 0.3 forces the group into its own layer because tightly coupled files indicate a distinct architectural boundary.

**Inter-group import asymmetry** identifies foundational layers (such as **utility**, **types**, or **data**) that are heavily imported by other groups but import few others themselves. **Dependency direction** orders the layers logically—UI depends on Service, which depends on Data.

Non-code node types generate dedicated layers automatically when present. Dockerfiles create an *Infrastructure* layer, `.github/workflows/` files create *CI/CD*, README files create *Documentation*, and `*.sql` files create *Data* layers.

Fallback heuristics using file summaries and tags resolve ambiguous cases, particularly in flat `src/` directory structures. The final output writes to [`.understand-anything/intermediate/layers.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/intermediate/layers.json) with each layer containing an `id` (e.g., `layer:api`, `layer:service`), human-readable name, description, and exact node IDs.

## Pattern Matching and Directory Heuristics

The analyzer recognizes architectural layers through deterministic mapping rules rather than machine learning.

### Directory-to-Layer Mappings

The system maintains a pattern table that maps conventional directory names to architectural layers:

- **`routes/`** → **API Layer**: Exposes HTTP endpoints and request handling
- **`services/`** → **Service Layer**: Contains core business logic
- **`models/`** or **`db/`** → **Data Layer**: Database access and storage logic
- **`components/`** or **`ui/`** → **UI Layer**: User interface elements
- **`utils/`** or **`helpers/`** → **Utility Layer**: Shared helper functions

### Cohesion Thresholds

When intra-group import density exceeds **0.3**, the analyzer automatically elevates that directory group to layer status regardless of naming conventions. This threshold captures tightly coupled modules that represent genuine architectural boundaries even when directory names are unconventional.

## Running the Architecture Analyzer

Invoke the analyzer through the generated script at [`.understand-anything/tmp/ua-arch-analyze.js`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/tmp/ua-arch-analyze.js):

```bash

# Create input JSON with file nodes and import edges

cat > .understand-anything/tmp/ua-arch-input.json <<'EOF'
{
  "fileNodes": [
    {"id":"file:src/routes/index.ts","type":"file","name":"index.ts","filePath":"src/routes/index.ts","summary":"API entry point","tags":["api-handler"]},
    {"id":"file:src/services/auth.ts","type":"file","name":"auth.ts","filePath":"src/services/auth.ts","summary":"Auth business logic","tags":["service"]},
    {"id":"file:src/utils/format.ts","type":"file","name":"format.ts","filePath":"src/utils/format.ts","summary":"Utility helpers","tags":["utility"]},
    {"id":"service:Dockerfile","type":"service","name":"Dockerfile","filePath":"Dockerfile","summary":"Container definition","tags":["infrastructure"]}
  ],
  "importEdges": [
    {"source":"file:src/routes/index.ts","target":"file:src/services/auth.ts","type":"imports"},
    {"source":"file:src/services/auth.ts","target":"file:src/utils/format.ts","type":"imports"}
  ],
  "allEdges": [
    {"source":"file:src/routes/index.ts","target":"file:src/services/auth.ts","type":"imports"},
    {"source":"file:src/services/auth.ts","target":"file:src/utils/format.ts","type":"imports"},
    {"source":"service:Dockerfile","target":"file:src/index.ts","type":"deploys"}
  ]
}
EOF

# Execute analysis

node .understand-anything/tmp/ua-arch-analyze.js \
  .understand-anything/tmp/ua-arch-input.json \
  .understand-anything/tmp/ua-arch-results.json

```

The semantic assignment phase processes these results and writes the final layer definitions to [`.understand-anything/intermediate/layers.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/intermediate/layers.json):

```json
[
  {
    "id": "layer:api",
    "name": "API Layer",
    "description": "Exposes HTTP endpoints and request handling",
    "nodeIds": ["file:src/routes/index.ts"]
  },
  {
    "id": "layer:service",
    "name": "Service Layer",
    "description": "Contains core business-logic services",
    "nodeIds": ["file:src/services/auth.ts"]
  },
  {
    "id": "layer:utility",
    "name": "Utility Layer",
    "description": "Shared helper functions used across the codebase",
    "nodeIds": ["file:src/utils/format.ts"]
  },
  {
    "id": "layer:infrastructure",
    "name": "Infrastructure",
    "description": "Container and deployment configuration",
    "nodeIds": ["service:Dockerfile"]
  }
]

```

## Summary

- The **Architecture Analyzer** uses a two-phase pipeline combining structural graph analysis and semantic assignment to identify layers.
- **Directory patterns** map conventional folder names like `routes/`, `services/`, and `utils/` to API, Service, and Utility layers.
- **Import density thresholds** (> 0.3) automatically detect cohesive architectural boundaries even with unconventional naming.
- **Fan-in/fan-out metrics** reveal dependency hierarchies and foundational layers that are imported frequently but import few others.
- Non-code artifacts like Dockerfiles and CI/CD configurations generate dedicated **Infrastructure**, **CI/CD**, and **Documentation** layers.
- Final output persists to [`.understand-anything/intermediate/layers.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/intermediate/layers.json) with standardized IDs like `layer:api` and `layer:data`.

## Frequently Asked Questions

### How does the analyzer distinguish between Service and Utility layers?

Service layers contain business logic imported by API routes and UI components, showing high fan-in from presentation layers. Utility layers demonstrate even broader usage patterns—imported by Services, Data access layers, and other Utilities—while maintaining minimal dependencies on other project-specific code. The analyzer detects this through **inter-group import asymmetry**, where Utilities show high fan-in but low fan-out to domain-specific modules.

### What happens when directory names don't match known patterns?

When directories lack conventional names, the analyzer relies on **import density calculations**. If a directory group's intra-group import density exceeds 0.3, indicating tight internal coupling, it automatically becomes a distinct layer regardless of naming. Fallback heuristics using file summaries and tags provide additional classification signals for flat `src/` structures or ambiguous naming conventions.

### How does the analyzer handle non-code files like Dockerfiles?

The **Architecture Analyzer** treats non-code artifacts as first-class nodes. Files like `Dockerfile`, `.github/workflows/*.yml`, or [`README.md`](https://github.com/Lum1104/Understand-Anything/blob/main/README.md) receive node types such as `service`, `config`, or `document`. Cross-category edges (e.g., `service:Dockerfile` → `file:src/index.ts` with type `deploys`) trigger the creation of dedicated **Infrastructure**, **CI/CD**, or **Documentation** layers in the final [`layers.json`](https://github.com/Lum1104/Understand-Anything/blob/main/layers.json) output.

### Can the analyzer detect custom architectural patterns?

Yes. The system combines pattern matching with structural metrics, allowing it to surface custom architectures. Even without matching the built-in directory patterns, groups exhibiting high **intra-group density** and distinct **fan-in/fan-out profiles** become layer candidates. The semantic assignment phase uses these structural signatures to generate project-specific layer descriptions, accommodating hexagonal, onion, or domain-driven architectures without explicit configuration.