How the Architecture Analyzer Identifies API, Service, Data, UI, and Utility Layers in Understand Anything
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 and operates as a two-phase pipeline that transforms raw file nodes and import edges into a structured 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 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 handlingservices/→ Service Layer: Contains core business logicmodels/ordb/→ Data Layer: Database access and storage logiccomponents/orui/→ UI Layer: User interface elementsutils/orhelpers/→ 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:
# 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:
[
{
"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/, andutils/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.jsonwith standardized IDs likelayer:apiandlayer: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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →