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

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. 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.

// 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.

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, 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 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 (or 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.

// 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.

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—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

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:

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 uses saveGraph and loadGraph to write and read JSON from .understand-anything/knowledge-graph.json, automatically creating the hidden directory and removing absolute paths.
  • The dashboard server in 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 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 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.

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 →