# How Understand Anything's Incremental Update System Uses Structural Fingerprints to Detect File Changes

> Understand Anything uses structural fingerprints to detect file changes by comparing API hashes, enabling efficient incremental knowledge graph updates. Learn how it works!

- Repository: [Egonex/Understand-Anything](https://github.com/Egonex-AI/Understand-Anything)
- Tags: internals
- Published: 2026-06-28

---

**Understand Anything detects file changes by generating SHA-256 hashed structural fingerprints of each source file's public API, comparing them against stored versions to classify changes as NONE, COSMETIC, or STRUCTURAL, enabling selective knowledge graph updates.**

The Understand Anything (UA) codebase analyzer avoids expensive full-project rescans by implementing an incremental update system powered by structural fingerprints. This mechanism parses source files into concise API signatures and content hashes, allowing the tool to distinguish between trivial formatting changes and meaningful architectural modifications. By leveraging Tree-Sitter parsing and persistent fingerprint storage, UA rebuilds only the affected portions of its knowledge graph rather than reprocessing entire repositories.

## What Are Structural Fingerprints?

A structural fingerprint is a serialized representation of a source file's public API surface combined with a cryptographic hash of its contents. According to the Understand Anything source code in [`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts), each fingerprint captures functions, classes, imports, and exports alongside a SHA-256 content hash. This dual-layer approach enables precise change detection by separating cosmetic modifications from API-level alterations.

## Fingerprint Generation and Parsing

### Tree-Sitter Integration

UA generates fingerprints by first parsing files through Tree-Sitter using the plugin registry system. The registry's `analyzeFile` function produces a `StructuralAnalysis` object describing the file's syntactic structure. This abstraction allows UA to support multiple languages while maintaining a uniform fingerprinting interface.

### The extractFileFingerprint Function

The core generation logic resides in `extractFileFingerprint` within [`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts) (lines 75-122). This function transforms the `StructuralAnalysis` into a fingerprint object containing:

- Public API signatures (functions, classes, imports, exports)
- SHA-256 hash of the file content
- Metadata for tracking and versioning

## Persistent Storage Architecture

Fingerprints are persisted to disk using `saveFingerprints` in [`packages/core/src/persistence/index.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/persistence/index.ts) (lines 18-23), which writes the entire fingerprint store to [`.understand-anything/fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/.understand-anything/fingerprints.json). On subsequent runs, `loadFingerprints` retrieves this data from the same location, enabling comparison between the previous and current state of the codebase.

## Change Detection and Classification

### The compareFingerprints Algorithm

When the filesystem reports potential changes, UA invokes `compareFingerprints` in [`fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprint.ts) (lines 124-246). This function performs a hierarchical comparison:

- **NONE**: Content hash identical—no changes detected
- **COSMETIC**: Hash differs but API signatures remain identical (e.g., whitespace changes, comments)
- **STRUCTURAL**: API signatures differ (e.g., function parameters changed, classes added, imports modified)

### Aggregating Project-Wide Changes

The `analyzeChanges` function (lines 286-385 in [`fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprint.ts)) orchestrates the detection process. It iterates through changed files, builds fresh fingerprints using the plugin registry, and compiles results into a `ChangeAnalysis` object. This aggregation tracks which files require reanalysis and the severity of modifications across the project.

## From Detection to Update Decisions

### The classifyUpdate Matrix

The `classifyUpdate` function in [`packages/core/src/change-classifier.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/change-classifier.ts) (lines 12-88) converts change analysis into actionable update strategies:

- **SKIP**: All files are NONE or COSMETIC—no rebuild necessary
- **PARTIAL_UPDATE**: Limited STRUCTURAL changes detected—reanalyze only affected files
- **ARCHITECTURE_UPDATE**: Significant structural changes or directory-level modifications detected
- **FULL_UPDATE**: Structural changes exceed thresholds (>30 files or >50% of project)

## Implementation Workflow

The following TypeScript example demonstrates the complete incremental update workflow:

```typescript
import { loadFingerprints, saveFingerprints } from "./persistence/index.js";
import { buildFingerprintStore, analyzeChanges } from "./fingerprint.js";
import { classifyUpdate } from "./change-classifier.js";

/** 1️⃣ Load the previously saved fingerprints */
const oldStore = loadFingerprints(projectRoot);

/** 2️⃣ Scan the repository to get the current file list (e.g. via glob) */
const allFiles = await getProjectFilePaths(projectRoot);

/** 3️⃣ Build a fresh fingerprint store for the whole project */
const newStore = buildFingerprintStore(
  projectRoot,
  allFiles,
  pluginRegistry,
  currentGitCommitHash,
);

/** 4️⃣ Determine which files actually changed on disk */
const changedFiles = await getChangedFilesSinceLastRun(projectRoot);

/** 5️⃣ Produce a detailed change analysis */
const analysis = analyzeChanges(
  projectRoot,
  changedFiles,
  oldStore,
  pluginRegistry,
);

/** 6️⃣ Decide what level of rebuild is required */
const decision = classifyUpdate(analysis, allFiles.length, allFiles);

/** 7️⃣ Persist the new fingerprints for the next incremental run */
saveFingerprints(projectRoot, newStore);

/* decision now tells the rest of the pipeline:
   - SKIP → nothing to do
   - PARTIAL_UPDATE → re‑run only the files listed in decision.filesToReanalyze
   - ARCHITECTURE_UPDATE / FULL_UPDATE → trigger full graph rebuild
*/

```

## Summary

- Understand Anything uses **structural fingerprints** combining SHA-256 content hashes with API signatures to detect file changes incrementally.
- The `extractFileFingerprint` function in [`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts) generates fingerprints by parsing files via Tree-Sitter and extracting public API elements.
- Fingerprints are stored in [`.understand-anything/fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/.understand-anything/fingerprints.json) via `saveFingerprints` in [`packages/core/src/persistence/index.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/persistence/index.ts) and retrieved using `loadFingerprints`.
- `compareFingerprints` classifies changes into **NONE**, **COSMETIC**, or **STRUCTURAL** based on hash and signature comparisons.
- `analyzeChanges` aggregates per-file results into a `ChangeAnalysis` object consumed by `classifyUpdate`.
- The update classifier determines whether to **SKIP**, perform a **PARTIAL_UPDATE**, **ARCHITECTURE_UPDATE**, or **FULL_UPDATE** based on thresholds (>30 files or >50% structural changes).

## Frequently Asked Questions

### What is a structural fingerprint in Understand Anything?

A structural fingerprint is a data structure generated by `extractFileFingerprint` that captures a source file's public API signatures—functions, classes, imports, and exports—alongside a SHA-256 hash of the file's raw content. This fingerprint serves as a compact, comparable representation of the file's structural identity, stored in [`.understand-anything/fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/.understand-anything/fingerprints.json) for incremental change detection.

### How does Understand Anything distinguish between cosmetic and structural changes?

The `compareFingerprints` function in [`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts) implements a two-tier comparison: if the SHA-256 content hash differs but the extracted API signatures (function names, parameters, class definitions) remain identical, the change is classified as **COSMETIC**. If any signature differs, including added or removed functions or modified imports, the change is classified as **STRUCTURAL**, triggering targeted reanalysis.

### Where are fingerprints stored in an Understand Anything project?

Fingerprints are persisted to [`.understand-anything/fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/.understand-anything/fingerprints.json) in the project root by the `saveFingerprints` function in [`packages/core/src/persistence/index.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/persistence/index.ts) (lines 18-23). This JSON file stores the entire fingerprint store, mapping file paths to their respective structural fingerprints and content hashes for retrieval on subsequent analysis runs.

### What triggers a full update versus a partial update in Understand Anything?

The `classifyUpdate` function in [`packages/core/src/change-classifier.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/change-classifier.ts) triggers a **FULL_UPDATE** when structural changes exceed configured thresholds—specifically when more than 30 files change or when structural modifications affect over 50% of the project. Below these thresholds, the system may issue a **PARTIAL_UPDATE** to reanalyze only affected files, or **SKIP** if changes are purely cosmetic.