# How Egonex-AI Implements Incremental Code Analysis with File Fingerprints

> Discover how Egonex-AI implements incremental code analysis using file fingerprints. Understand Anything achieves O(Δ) performance by only re-analyzing changed files with SHA-256 hashes and AST signatures.

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

---

**Egonex-AI's *Understand Anything* toolchain performs incremental code analysis by generating cryptographic file fingerprints that combine SHA-256 content hashes with structural AST signatures, enabling O(Δ) performance by re-analyzing only changed files.**

The Egonex-AI/Understand-Anything repository solves the scalability problem of large codebase analysis by avoiding full re-scans on every run. Instead, it implements an **incremental code analysis** system using **file fingerprints** that persist across sessions in [`fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprints.json). This approach allows the tool to distinguish between cosmetic edits and structural modifications, ensuring downstream agents process only files that have meaningfully changed.

## The Fingerprint Architecture

At the core of the system is the `FileFingerprint` object, which captures two distinct dimensions of a source file. First, a **SHA-256 content hash** provides a deterministic checksum of the raw file text. Second, a **structural signature** records extracted symbols—functions, classes, imports, exports, and their signatures—via Tree-Sitter parsing.

This dual-layer approach lives in [[`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts)](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts). The fingerprint generation process handles both fully-parsable files and unsupported file types through a graceful fallback mechanism.

## Building the Fingerprint Store

### Structural Signature Extraction

When a project is first scanned, `buildFingerprintStore` walks the entire file tree and invokes `extractFileFingerprint` for each path. This function converts Tree-Sitter's `StructuralAnalysis` output into a lightweight, serializable format that records:

- Function signatures and class members
- Import and export declarations
- Line count and file metadata

According to the [source implementation](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L75-L122), the structural extraction preserves only the API surface and dependencies, ignoring whitespace and comments that would trigger false positives in a pure hash-based system.

### Content Hashing

Simultaneously, the system computes a `contentHash` using Node.js `crypto.createHash('sha256')` to produce a deterministic digest of the raw file text ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L66-L71)).

The complete fingerprint store is then serialized to [`fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprints.json), including the current Git commit hash to detect repository resets. The [persistence logic](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L48-L55) handles versioning and atomic writes to prevent corruption during interrupted scans.

### Example: Initializing a Project Store

```typescript
import { buildFingerprintStore } from '@understand-anything/core/fingerprint';
import { defaultPluginRegistry } from '@understand-anything/core/plugins/registry';
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';

const projectRoot = '/path/to/project';
const allFiles = ['src/index.ts', 'src/utils.ts', 'src/parser.ts'];
const gitHash = 'abcdef1234567890';  // from git rev-parse HEAD

const store = buildFingerprintStore(
  projectRoot,
  allFiles,
  defaultPluginRegistry,
  gitHash,
);

writeFileSync(
  join(projectRoot, 'fingerprints.json'), 
  JSON.stringify(store, null, 2)
);

```

## Detecting and Classifying Changes

### The Comparison Algorithm

On subsequent runs, `analyzeChanges` accepts a list of files from Git's diff output (via `git diff --name-only`) and loads the previous fingerprint store from disk. For each changed path, it reconstructs a fresh fingerprint and delegates to `compareFingerprints` to determine the modification severity ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L96-L144)).

The comparison logic implements three distinct change levels:

- **NONE**: Identical content hash indicates the file is byte-for-byte unchanged.
- **COSMETIC**: Content differs, but structural signatures (function signatures, class members, imports/exports) remain identical. This captures formatting changes, comment edits, or whitespace adjustments.
- **STRUCTURAL**: Any modification to the API surface, including added or removed symbols, signature changes, or import/export modifications. Files lacking Tree-Sitter support are conservatively labeled **STRUCTURAL** on any change ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L124-L132)).

The `compareFingerprints` function returns a detailed `ChangeLevel` result including a `details` array describing specific modifications ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L124-L150)).

### Aggregating Change Analysis

The `analyzeChanges` function aggregates per-file results into a `ChangeAnalysis` object that categorizes the codebase into:

- **New files**: Paths present in the current scan but missing from the store.
- **Deleted files**: Paths present in the store but missing from disk.
- **Unchanged files**: Files with **NONE** change level (skipped for analysis).
- **Cosmetic-only files**: Files with **COSMETIC** changes (may skip deep analysis depending on agent configuration).
- **Structurally-changed files**: Files requiring full re-analysis.

### Example: Running Incremental Analysis

```typescript
import { analyzeChanges, ChangeAnalysis } from '@understand-anything/core/fingerprint';
import { readFileSync } from 'node:fs';
import { defaultPluginRegistry } from '@understand-anything/core/plugins/registry';
import { join } from 'node:path';

const projectRoot = '/path/to/project';

// Load persisted fingerprints
const previousStore = JSON.parse(
  readFileSync(join(projectRoot, 'fingerprints.json'), 'utf-8')
);

// Files returned by git diff --name-only <prevHash>..HEAD
const changedFiles = ['src/parser.ts', 'src/index.ts'];

const analysis: ChangeAnalysis = analyzeChanges(
  projectRoot,
  changedFiles,
  previousStore,
  defaultPluginRegistry,
);

console.log('Files needing deep analysis:', analysis.structurallyChangedFiles);
console.log('Cosmetic-only changes:', analysis.cosmeticOnlyFiles);
console.log('Unchanged (skipped):', analysis.unchangedFiles);

```

## Key Design Decisions

The fingerprint system optimizes for accuracy and performance through several specific implementation choices:

- **Graceful degradation for unsupported languages**: Files without Tree-Sitter parsers receive a hash-only fingerprint with `hasStructuralAnalysis: false`. Any subsequent content change is treated as **STRUCTURAL**, ensuring conservative correctness ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L124-L132)).

- **O(Δ) complexity**: Only files returned by `changedFiles` are re-analyzed. All other files are retrieved from the existing store, making the analysis time proportional to the number of changes rather than the total codebase size.

- **Git-aware invalidation**: The fingerprint store includes a `gitCommitHash` field. If the repository is reset to an earlier commit or the history is rewritten, the system detects the mismatch and rebuilds the entire store to prevent false assumptions about file states.

- **Deterministic hashing**: The SHA-256 implementation uses Node.js native crypto to ensure consistent fingerprints across different platforms and Node.js versions.

## Summary

Egonex-AI implements **incremental code analysis with file fingerprints** through a three-stage pipeline:

- **Fingerprint generation** combines SHA-256 content hashes with Tree-Sitter structural signatures to create unique file identifiers stored in [`packages/core/src/fingerprint.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/fingerprint.ts).
- **Change detection** compares previous and current fingerprints using `compareFingerprints` to classify edits as NONE, COSMETIC, or STRUCTURAL.
- **Selective re-analysis** processes only structurally changed or new files, providing O(Δ) performance for large repositories.

The system persists data in [`fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprints.json) and integrates with Git workflows to ensure accurate incremental scanning across development sessions.

## Frequently Asked Questions

### What is the performance benefit of using file fingerprints for incremental analysis?

**File fingerprints reduce analysis complexity from O(N) to O(Δ), where N is the total file count and Δ represents changed files.** By persisting structural and content signatures in [`fingerprints.json`](https://github.com/Egonex-AI/Understand-Anything/blob/main/fingerprints.json), the system skips unchanged files entirely. For a repository with 10,000 files where only 50 have changed, the tool analyzes just those 50 files rather than the entire codebase, achieving near-instant incremental updates.

### How does the system handle files in languages without Tree-Sitter support?

**Unsupported files receive a hash-only fingerprint with `hasStructuralAnalysis: false`.** According to the [fallback implementation](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L124-L132), any content change in these files is conservatively classified as **STRUCTURAL**. This ensures the system never assumes a change is cosmetic when it cannot parse the code structure, maintaining correctness at the cost of potentially re-analyzing formatting-only changes in unsupported languages.

### What data is stored in the fingerprints.json file?

**The JSON file contains a `FingerprintStore` object with two primary fields:** a `gitCommitHash` string tracking the repository state at creation time, and a `fingerprints` object mapping relative file paths to `FileFingerprint` records. Each fingerprint includes the SHA-256 `contentHash`, structural metadata (functions, classes, imports), line count, and a boolean flag indicating whether structural analysis was available for that file type.

### How does the system distinguish between cosmetic and structural code changes?

**The `compareFingerprints` function implements a two-tier comparison algorithm.** First, it compares SHA-256 content hashes; if identical, the level is **NONE**. If hashes differ, it compares the extracted structural signatures—function names, signatures, class members, and import/export declarations. If these match exactly, the change is **COSMETIC** (formatting/comments only). Any difference in the structural signature or lack thereof results in a **STRUCTURAL** classification ([source](https://github.com/Egonex-AI/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/fingerprint.ts#L124-L150)).