Architecture of the Graph Module in Hivemind: Virtual Filesystem Implementation

The graph module in activeloopai/hivemind implements a read-only virtual filesystem (VFS) that exposes repository code graphs as synthetic files under ~/.deeplake/memory/graph/, using a three-layer architecture comprising snapshot generation, path dispatching, and text rendering.

The graph module serves as the intelligence layer behind Hivemind's code understanding capabilities. According to the source code in activeloopai/hivemind, this module creates a virtual filesystem interface that lets agents query code graphs as if they were ordinary files. The architecture cleanly separates expensive graph construction from fast read operations through a deterministic snapshot pipeline.

Three-Layer Architecture of the Graph Module

The implementation in src/graph/ follows a strict separation of concerns across three distinct layers: data extraction and storage, request routing, and output generation.

Snapshot Generation and Storage Pipeline

The foundation of the system is a canonicalized JSON snapshot that captures symbols and relations from source files. This pipeline executes in distinct phases:

  • Extraction: Language-specific extractors in src/graph/extract/**/*.ts parse TypeScript, JavaScript, Python, and Rust files to emit GraphNode and GraphEdge objects (defined in src/graph/types.ts).
  • Cross-file resolution: src/graph/resolve/cross-file.ts performs Phase 1.5 resolution, using ImportBinding and RawCall data to link calls across module boundaries.
  • Canonicalisation: src/graph/snapshot.ts sorts nodes and edges, strips volatile fields, and writes a deterministic NetworkX-compatible JSON file. The stable portion (graph, nodes, links) contributes to a SHA-256 hash used for de-duplication, while the observation field (capturing branch, timestamp, and build context) is explicitly excluded from this hash.
  • Persistence: src/graph/cache.ts and src/graph/last-build.ts store snapshots under ~/.hivemind/graphs/<repo-key>/snapshots/ and track the most recent build per worktree.

Virtual Filesystem Dispatcher

The core entry point for VFS reads is src/graph/graph-command.ts. It receives rewritten shell commands where paths are already mapped to the /graph/ root. The parseReadTargetPath function isolates single file reads (e.g., cat, head, tail), while tryGraphRead validates traversal safety and checks for ls /graph listings.

The actual routing logic lives in src/graph/vfs-handler.ts, which exports the handleGraphVfs(subpath: string, cwd: string): GraphVfsResult function. This dispatcher normalizes the incoming path, loads the appropriate snapshot via loadSnapshotOrError(), and delegates to the correct renderer based on the first path component (index.md, find/, show/, query/, etc.).

Renderers and Helper Functions

Each virtual endpoint has a dedicated renderer that consumes a GraphSnapshot and returns plain text:

Endpoint Renderer Source File
index.md renderIndex vfs-handler.ts
find/<pattern> renderFind vfs-handler.ts
show/<key> renderShow vfs-handler.ts
query/<pattern> renderQuery vfs-handler.ts
impact/<pattern> renderImpact render/impact.ts
neighborhood/<file> renderNeighborhood render/neighborhood.ts
layers renderLayers render/layers.ts
tour renderTour render/tour.ts
path/<from>/<to> renderPath render/path.ts

All renderers share utilities including dirListing() for static directory views and saveHandles() / loadHandles() for persisting numeric shortcuts returned by find/ for later show/ calls.

How the VFS Intercepts File Requests

When a user runs a command like cat ~/.deeplake/memory/graph/find/HttpClient, the request flows through a specific interception chain:

  1. Path rewriting: CLI hooks in src/hooks/graph-on-stop.ts rewrite the host path ~/.deeplake/memory/graph/ to /graph/ before the VFS sees it.
  2. Command parsing: tryGraphRead() in graph-command.ts identifies this as a graph VFS read.
  3. Dispatch: handleGraphVfs("find/HttpClient", cwd) loads the most recent snapshot for the current working directory.
  4. Rendering: renderFind() executes a substring search via findMatches() over snapshot.nodes, persists the numeric handle table via saveHandles(), and returns a formatted list.
  5. Output: The synthesized string is printed to stdout as if it were a physical file, though no real files exist under the memory graph path.

Integration with CLI Hooks

Two critical hooks bridge the shell environment and the graph module:

  • src/hooks/graph-on-stop.ts: Invoked after command completion, it may inject synthetic VFS reads and rewrites user paths to the VFS root.
  • src/hooks/graph-pull-worker.ts: Runs asynchronous pulls of remote graph snapshots, enabling hivemind graph pull to fetch teammate-generated graphs.

Both hooks rely on tryGraphRead from graph-command.ts to obtain synthesized output before the shell proceeds.

Practical Usage Examples

Querying the Graph from Shell


# List the virtual graph directory structure

cat ~/.deeplake/memory/graph/index.md

# Search for symbols containing "HttpClient" (returns numbered handles)

cat ~/.deeplake/memory/graph/find/HttpClient

# Show details of the first handle from the previous search

cat ~/.deeplake/memory/graph/show/1

# Combined find-and-expand for the top 5 matches

cat ~/.deeplake/memory/graph/query/HttpClient

Programmatic API Usage

import { handleGraphVfs } from "hivemind/src/graph/vfs-handler.js";

const cwd = process.cwd();

// Read the virtual index file
const result = handleGraphVfs("index.md", cwd);
if (result.kind === "ok") {
  console.log(result.body);   // Renders markdown from the snapshot
}

Building the Graph Snapshot


# Generate a fresh snapshot for the current commit

hivemind graph build

# Pull a remote snapshot from a teammate

hivemind graph pull

After a successful build, the VFS becomes immediately reachable; snapshots persist under ~/.hivemind/graphs/<repo-key>/snapshots/.

Summary

  • The graph module implements a read-only virtual filesystem in src/graph/ that exposes code graphs through synthetic files.
  • Snapshot pipeline (src/graph/snapshot.ts, src/graph/resolve/cross-file.ts) extracts symbols, resolves cross-file calls, and writes deterministic JSON with SHA-256 de-duplication.
  • VFS dispatcher (src/graph/graph-command.ts, src/graph/vfs-handler.ts) rewrites shell paths, loads snapshots, and routes to specific renderers.
  • Renderers (src/graph/render/*.ts, vfs-handler.ts) generate human-readable text for endpoints like find/, show/, and impact/.
  • CLI hooks (src/hooks/graph-on-stop.ts) intercept file reads to ~/.deeplake/memory/graph/ and redirect them to the VFS engine without creating physical files.

Frequently Asked Questions

What is the file path format used by the graph module's virtual filesystem?

The graph module intercepts accesses to paths under ~/.deeplake/memory/graph/ and rewrites them internally to /graph/*. Valid subpaths include index.md, find/<pattern>, show/<key>, query/<pattern>, impact/<pattern>, neighborhood/<file>, layers, tour, and path/<from>/<to>. These paths are parsed by parseReadTargetPath in src/graph/graph-command.ts and routed by handleGraphVfs in src/graph/vfs-handler.ts.

How does the graph module resolve relationships between different source files?

Cross-file resolution occurs in Phase 1.5 of the snapshot pipeline via src/graph/resolve/cross-file.ts. This module analyzes ImportBinding and RawCall data to resolve function calls and symbol references across module boundaries, ensuring that the final GraphSnapshot contains accurate GraphEdge connections between nodes in different files.

Where are graph snapshots stored on the local filesystem?

Snapshots are persisted under ~/.hivemind/graphs/<repo-key>/snapshots/ as managed by src/graph/cache.ts and src/graph/last-build.ts. The last-build.ts component tracks the most recent build for each worktree, while the cache handles the actual JSON file storage. The snapshots are de-duplicated using SHA-256 hashes of their stable content (excluding the volatile observation metadata).

How does the VFS generate content without creating physical files?

The VFS is strictly read-only and synthetic. When tryGraphRead detects a graph path, it loads the relevant GraphSnapshot into memory via loadSnapshotOrError(), executes the appropriate renderer (such as renderFind or renderShow), and returns the resulting string directly to the shell. This happens in src/graph/vfs-handler.ts—no files are ever written to ~/.deeplake/memory/graph/; the directory exists only as a namespace for the virtual filesystem.

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 →