# How the Knowledge Graph Is Stored and Loaded in the .understand‑anything Directory

> Discover how the Knowledge Graph is stored and loaded in the .understand-anything directory. Learn about JSON encoding, persistence layers, and Vite middleware for efficient data serving.

- Repository: [Yuxiang Lin/Understand-Anything](https://github.com/Lum1104/Understand-Anything)
- Tags: internals
- Published: 2026-06-06

---

**The Understand-Anything tool persists JSON-encoded knowledge graphs to a hidden `.understand-anything/` folder via the core persistence layer, then serves sanitized versions to the dashboard through a custom Vite middleware that discovers files across multiple candidate paths.**

The Understand-Anything repository maintains code intelligence as a structured knowledge graph that lives in your project's hidden `.understand-anything/` directory. This article traces the exact persistence and retrieval mechanisms, examining how the core package writes graph data to disk and how the dashboard development server discovers and streams that data to the browser while sanitizing sensitive paths.

## Core Persistence Layer in `packages/core`

All disk operations for graph storage live in **[`packages/core/src/persistence/index.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/persistence/index.ts)**. This module encapsulates the logic for creating the hidden directory, serializing graph data, and retrieving it with optional schema validation.

### Saving the Graph with `saveGraph`

The **`saveGraph`** function handles the atomic write of a `KnowledgeGraph` object to `<projectRoot>/.understand-anything/knowledge-graph.json`. Before writing, it invokes `ensureDir` to create the hidden folder if it does not exist, then strips absolute file paths to prevent directory information leakage.

```typescript
// From packages/core/src/persistence/index.ts
function ensureDir(projectRoot: string): string {
  const dir = join(projectRoot, ".understand-anything");
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
  return dir;
}

export function saveGraph(projectRoot: string, graph: KnowledgeGraph): void {
  const dir = ensureDir(projectRoot);
  const sanitised = sanitiseGraph(graph, projectRoot); // Removes absolute paths
  writeFileSync(
    join(dir, GRAPH_FILE), 
    JSON.stringify(sanitised, null, 2), 
    "utf-8"
  );
}

```

The sanitisation step ensures that `filePath` properties in graph nodes contain only relative paths or base filenames, preventing private directory structures from being committed to JSON.

### Loading and Validation with `loadGraph`

Retrieval is handled by **`loadGraph`**, which reads the JSON file, parses it, and optionally validates the structure against the schema defined in [`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts).

```typescript
import { loadGraph } from "@understand-anything/core/persistence";

const graph = loadGraph(process.cwd(), { validate: true });
if (!graph) {
  console.error("No knowledge graph – run `/understand` first");
  process.exit(1);
}
console.log(`Graph contains ${graph.nodes.length} nodes`);

```

The function signature accepts a `validate` boolean that triggers JSON-schema validation using the definitions from **[`packages/core/src/schema.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/schema.ts)**, ensuring data integrity before the graph is consumed by downstream tools.

## Dashboard Data Streaming Architecture

When you run `pnpm dev:dashboard`, the Vite development server defined in **[`packages/dashboard/vite.config.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/dashboard/vite.config.ts)** locates the persisted graph and exposes it via HTTP endpoints, applying additional runtime sanitization.

### File Discovery and Resolution

The server attempts to locate [`knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/knowledge-graph.json) (or [`domain-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/domain-graph.json)) across three candidate locations: an explicit `GRAPH_DIR` environment variable, the current working directory, or a relative path three levels up from the dashboard package.

```typescript
// From packages/dashboard/vite.config.ts
function graphFileCandidates(fileName: string): string[] {
  const graphDir = process.env.GRAPH_DIR;
  return [
    ...(graphDir ? [path.resolve(graphDir, `.understand-anything/${fileName}`)] : []),
    path.resolve(process.cwd(), `.understand-anything/${fileName}`),
    path.resolve(process.cwd(), `../../../.understand-anything/${fileName}`),
  ];
}

```

This multi-path resolution allows the dashboard to find the graph whether it is running from a monorepo sub-package or a standalone project root.

### Path Sanitization Middleware

Before streaming the JSON to the browser, the middleware sanitizes any remaining absolute paths, converting them to project-relative strings. This mirrors the server-side sanitization but adds an extra security layer for the dev server.

```typescript
const raw = JSON.parse(fs.readFileSync(candidate, "utf-8"));
const projectRoot = projectRootFromGraphFile(candidate);

if (Array.isArray(raw.nodes)) {
  raw.nodes = raw.nodes.map(node => {
    if (typeof node.filePath !== "string") return node;
    const abs = node.filePath;
    const rel = abs.startsWith(projectRoot)
      ? abs.slice(projectRoot.length).replace(/^[\\/]/, "")
      : path.isAbsolute(abs) ? path.basename(abs) : abs;
    return { ...node, filePath: rel };
  });
}

res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(raw));

```

The endpoint is protected by a one-time access token (`?token=…`) query parameter to prevent unauthorized reads during development.

## Directory Structure and Auxiliary Files

The `.understand-anything/` directory stores multiple JSON artifacts beyond the main knowledge graph:

```

project/
├─ src/
├─ .understand-anything/
│  ├─ knowledge-graph.json   # Main graph data

│  ├─ meta.json              # Generation metadata

│  ├─ config.json            # Plugin configuration

│  └─ domain-graph.json      # Domain-specific views

└─ …

```

Additional persistence helpers in **[`packages/core/src/persistence/index.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/persistence/index.ts)**—**`saveMeta`**, **`loadMeta`**, **`saveConfig`**, **`loadConfig`**, **`saveDomainGraph`**, and **`loadDomainGraph`**—manage these auxiliary files using the same `ensureDir` safety guarantees and path sanitization logic.

## Practical Implementation Examples

### Saving a Graph from a Custom Analyzer

```typescript
import { saveGraph } from "@understand-anything/core/persistence";
import type { KnowledgeGraph } from "@understand-anything/core/types";

async function generateAndPersist(root: string) {
  const graph: KnowledgeGraph = await myAnalyzer(root);
  saveGraph(root, graph); // Auto-creates .understand-anything/ and sanitizes paths
}

```

The `saveGraph` call automatically creates the hidden folder if absent and ensures no absolute paths leak into the serialized JSON.

### Fetching Data in the Browser

When the dashboard is running, client-side code can retrieve the sanitized graph:

```javascript
fetch(`/knowledge-graph.json?token=YOUR_TOKEN`)
  .then(r => r.json())
  .then(data => console.log('Nodes loaded:', data.nodes.length));

```

The middleware guarantees that `filePath` entries contain only relative paths safe for client-side consumption.

## Summary

- **The core persistence layer** in [`packages/core/src/persistence/index.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/persistence/index.ts) uses `saveGraph` and `loadGraph` to write and read JSON from [`.understand-anything/knowledge-graph.json`](https://github.com/Lum1104/Understand-Anything/blob/main/.understand-anything/knowledge-graph.json), automatically creating the hidden directory and removing absolute paths.
- **The dashboard server** in [`packages/dashboard/vite.config.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/dashboard/vite.config.ts) resolves the graph file from multiple candidate paths and serves it through a sanitizing middleware that converts absolute paths to relative ones.
- **Auxiliary data** like metadata, configuration, and domain-specific views are stored alongside the main graph using the same persistence utilities.
- **Security measures** include path sanitization at both persistence and serving layers, plus token-based access control for the development server endpoint.

## Frequently Asked Questions

### Where is the knowledge graph file physically located?

The knowledge graph is stored at `<projectRoot>/.understand-anything/knowledge-graph.json` relative to your project's root directory. The `saveGraph` function in [`packages/core/src/persistence/index.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/core/src/persistence/index.ts) automatically creates the `.understand-anything/` hidden folder if it does not exist, ensuring the directory structure is ready before writing the JSON file.

### How does the dashboard find the graph in different project structures?

The dashboard uses the `graphFileCandidates` function in [`packages/dashboard/vite.config.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/packages/dashboard/vite.config.ts) to check three locations in order: the path specified by the `GRAPH_DIR` environment variable, the current working directory's `.understand-anything/` folder, and a relative path three levels up from the dashboard package itself. This allows the dev server to locate the graph whether running from a monorepo sub-package or a standalone installation.

### Why are absolute file paths removed before saving and serving?

Absolute paths are stripped to prevent sensitive directory information from leaking into version control or browser network logs. The `sanitiseGraph` function used by `saveGraph` removes absolute prefixes at persistence time, and the dashboard middleware performs additional sanitization at serve time, converting absolute paths to relative project paths or base filenames only.

### Can I load the graph programmatically outside the dashboard?

Yes. Import `loadGraph` from `@understand-anything/core/persistence` and pass the project root and an optional validation flag. The function returns a typed `KnowledgeGraph` object or `null` if the file is missing, allowing you to build custom analysis tools, CI scripts, or reporting utilities that consume the graph data directly without running the web dashboard.