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

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, 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 (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 (lines 18-23), which writes the entire fingerprint store to .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 (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) 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 (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:

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 generates fingerprints by parsing files via Tree-Sitter and extracting public API elements.
  • Fingerprints are stored in .understand-anything/fingerprints.json via saveFingerprints in 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 for incremental change detection.

How does Understand Anything distinguish between cosmetic and structural changes?

The compareFingerprints function in 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 in the project root by the saveFingerprints function in 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 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →