How to Customize Architectural Layer Detection in Understand-Anything: A Complete Guide
Understand-Anything automatically categorizes files into architectural layers by matching paths against a configurable heuristic list in packages/core/src/analyzer/layer-detector.ts, which you can modify and rebuild to fit your specific project structure.
The open-source Understand-Anything toolkit analyzes codebases and visualizes them as interactive architectural graphs. By default, it groups files into logical layers like "API Layer" or "Data Layer" using pattern-based detection. If your repository uses non-standard directory names or requires additional architectural categories, you can customize this detection logic to ensure the dashboard accurately reflects your system's design.
Where Layer Detection Lives in the Source Code
The architectural layer assignment logic resides in packages/core/src/analyzer/layer-detector.ts. This module exports two primary mechanisms: a fast heuristic matcher that runs locally, and an optional LLM-based refinement system. The heuristic approach uses a static constant called LAYER_PATTERNS to categorize files based on their directory paths, while the LLM integration can propose additional layers through the buildLayerDetectionPrompt function.
When you run an analysis, the detectLayers function iterates over every file node in the knowledge graph, calls matchFileToLayer for each path, and constructs a Layer array containing IDs, names, descriptions, and the grouped node references.
How the Heuristic Detection Works
The static detection system operates on a "first match wins" principle. The LAYER_PATTERNS constant defines an ordered array of objects, each specifying:
patterns– directory names (singular or plural) to matchlayerName– the display label shown in the UIdescription– tooltip text explaining the layer's purpose
The matchFileToLayer function normalizes file paths by converting backslashes to forward slashes and lowercasing the string. It then splits the path into segments and checks each segment against the patterns array:
function matchFileToLayer(filePath: string): string | null {
const normalizedPath = filePath.replace(/\\/g, "/").toLowerCase();
const segments = normalizedPath.split("/");
for (const { patterns, layerName } of LAYER_PATTERNS) {
for (const segment of segments) {
for (const pattern of patterns) {
if (segment === pattern || segment === pattern + "s") {
return layerName;
}
}
}
}
return null;
}
If no patterns match, the file falls into a default Core layer. Because the array order determines priority, placing specific patterns before generic ones prevents misclassification.
Customizing Layer Patterns in Three Steps
1. Edit LAYER_PATTERNS in layer-detector.ts
Open packages/core/src/analyzer/layer-detector.ts and locate the LAYER_PATTERNS constant. Add, remove, or reorder entries to match your project structure. For example, to recognize a custom "Job Scheduler" layer for files in jobs/ or scheduler/ directories, insert this entry before more generic patterns:
{
patterns: ["jobs", "scheduler"],
layerName: "Job Scheduler Layer",
description: "Cron jobs, scheduled tasks, and background workers",
},
2. Rebuild the Core Package
After modifying the source, compile the changes so the dashboard can consume them. From the repository root, run:
pnpm --filter @understand-anything/core build
Alternatively, run the full build pipeline with pnpm install && pnpm build to ensure all dependencies are synchronized.
3. Re-run the Analysis
Execute your standard Understand-Anything command to regenerate the knowledge graph with the new layer mappings:
understand --full
Or, if using the Claude Code integration: /understand --full.
Extending Detection Without Forking Core Files
If you prefer to keep the original layer-detector.ts untouched, create an extension module that exports additional patterns and import it into the detector file. Create packages/core/src/analyzer/my-extensions.ts:
export const EXTRA_LAYER_PATTERNS = [
{
patterns: ["analytics", "metrics"],
layerName: "Analytics Layer",
description: "Data collection, reporting, and metrics aggregation",
},
];
Then modify layer-detector.ts to merge the arrays:
import { EXTRA_LAYER_PATTERNS } from "./my-extensions.js";
export const LAYER_PATTERNS = [
// ... original entries ...
...EXTRA_LAYER_PATTERNS,
];
This approach preserves the original order while appending your custom definitions, allowing you to maintain a clean diff when updating the repository.
Leveraging LLM-Assisted Layer Detection
Beyond static patterns, Understand-Anything can invoke a language model to suggest architectural layers. The system builds a prompt via buildLayerDetectionPrompt, which requests a JSON array of layer objects. The LLM response is parsed by parseLayerDetectionResponse and merged with heuristic results through applyLLMLayers (used downstream in the analysis pipeline).
To customize the LLM behavior, modify the prompt string in buildLayerDetectionPrompt. For instance, to request up to 10 layers instead of the default 3-7, or to ask for file extension-based categorization:
export function buildLayerDetectionPrompt(graph: KnowledgeGraph): string {
const filePaths = /* gather from graph */;
const fileListStr = /* format as string */;
return `You are a software architecture analyst.
From the file list below, propose **up to 10** logical layers.
For each layer provide:
- "name"
- "description"
- "filePatterns" (example path prefixes)
Ensure every file appears in exactly one layer.
Respond ONLY with a JSON array.
Files:
${fileListStr}`;
}
After changing the prompt, rebuild the core package and re-run the analysis. The LLM-generated layers supplement, rather than replace, your heuristic patterns, filling gaps for files that don't match static directory rules.
Summary
packages/core/src/analyzer/layer-detector.tscontains theLAYER_PATTERNSconstant andmatchFileToLayerfunction that drive architectural layer assignment.- The heuristic matcher evaluates patterns in array order, assigning the first matching layer or defaulting to "Core".
- To customize: edit
LAYER_PATTERNS, runpnpm --filter @understand-anything/core build, and re-run the analysis command. - You can extend patterns from external modules to avoid modifying core source files directly.
- The
buildLayerDetectionPromptfunction controls LLM-based layer suggestions, which are merged with heuristic results viaparseLayerDetectionResponseandapplyLLMLayers.
Frequently Asked Questions
What happens if a file doesn't match any pattern in LAYER_PATTERNS?
When matchFileToLayer returns null for a given path, the file is automatically assigned to the Core layer. This fallback ensures that every file appears in the architectural visualization even if it resides outside recognized directory conventions.
Can I customize layer detection based on file extensions or naming conventions instead of directories?
Yes. While the default matchFileToLayer implementation checks directory segments, you can modify the function to analyze file extensions, prefixes, or even content signatures. Replace the segment-matching logic with checks like filePath.endsWith('.test.ts') or regex patterns, then rebuild the core package to apply your custom detection logic.
How do I prevent the LLM from overriding my heuristic layer assignments?
The LLM-generated layers merge with heuristic results rather than replacing them. The applyLLMLayers function (used downstream) combines both sources, with heuristic matches typically taking precedence for files already categorized. To exclude LLM suggestions entirely, simply don't trigger the LLM analysis phase or remove the call to buildLayerDetectionPrompt from your analysis workflow.
Where is the layer information stored after detection?
The detectLayers function constructs Layer objects containing id, name, description, and nodeIds arrays. This data flows into packages/dashboard/src/store.ts, which persists the layer mappings for UI rendering. The layer IDs follow a kebab-case format like layer:api-layer (generated by toLayerId), allowing the dashboard to apply consistent coloring and filtering across the visualization.
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 →