Sprinter Docs

Entity Graph

Interactive relationship graph visualization using @xyflow/react and D3 force-directed layout, with filtering, search, focus mode, and embeddable block support.

Entity Graph

The Entity Graph renders all entity records and their relationships as an interactive node-link diagram. Nodes represent entities (colored by type), edges represent relations, and the layout is computed via a D3 force-directed simulation. The graph supports filtering by type and relation, searching by title, focusing on a single entity's neighborhood, and embedding as a block in entity detail views.

Overview

The graph is accessible at /graph as a full-page experience and can be embedded in entity detail pages via the entity-graph block type. The module lives in features/graph/ and uses @xyflow/react for pan/zoom canvas rendering with custom node components. The layout engine uses d3-force for physics-based positioning, running synchronously to convergence before rendering.

Key Concepts

GraphNode -- A node in the graph: id, title, type (human-readable type name), typeSlug, and optional icon.

GraphEdge -- A directed edge: id, source (entity ID), target (entity ID), and label (relationship type string).

GraphData -- The container type holding arrays of GraphNode and GraphEdge.

GraphConfig -- Controls what the graph shows and how:

  • focusEntityId -- center on this entity and highlight its neighborhood
  • typeFilter -- array of entity type slugs to include
  • relationFilter -- array of relationship types to include
  • searchQuery -- highlights matching nodes
  • limit -- max nodes to display (default 50, API max 1000)
  • showToolbar -- whether to show filter/search controls
  • showLegend -- whether to show the type color legend
  • compact -- smaller nodes for sidebar/block use
  • height -- CSS height override

SimNode / SimLink -- Extended types used by the D3 force simulation, adding position (x, y), velocity, and connectionCount to GraphNode.

NodeSummary -- Lightweight identity passed through selection callbacks: title, typeSlug, typeName.

How It Works

Data Fetching

The GET /api/graph route supports two modes:

  1. Neighborhood mode (?entityId=...) -- fetches the specified entity and all entities one hop away via entity_relations. Returns a compact subgraph.

  2. Full graph mode (optional ?types=...&limit=...) -- fetches up to limit entities (default 500, max 1000), optionally filtered by comma-separated type slugs. Relations are fetched with a limit of 3x the entity limit.

Both modes are tenant-scoped and require authentication.

Force-Directed Layout

The computeForceLayout() function in features/graph/lib/force-layout.ts runs a D3 force simulation synchronously:

  • Charge force -- repulsion between nodes (default -300 strength)
  • Link force -- attraction along edges (default 120px distance)
  • Center force -- pulls the graph toward the viewport center
  • Collision force -- prevents overlap, with radius scaled by connection count
  • Centering forces -- gentle X/Y forces prevent drift

The simulation runs for 300 ticks by default, producing settled positions without animation. Node radius scales with connection count: max(20, 20 + sqrt(connections) * 6).

Rendering Pipeline

  1. computeForceLayout() produces positioned SimNode[] and SimLink[]
  2. buildFlowNodes() and buildFlowEdges() convert these to @xyflow/react Node[] and Edge[], applying interaction state (hover highlighting, search matches, focus dimming, selection)
  3. GraphCanvas renders via ReactFlow with custom GraphNode components
  4. Interaction: hovering a node highlights it and its neighbors, dims everything else. Clicking navigates to the entity detail page.

Graph Utilities

The features/graph/lib/graph-utils.ts file provides pure functions:

  • buildConnectionCounts(nodes, edges) -- counts connections per node
  • buildAdjacency(edges) -- builds an undirected adjacency map
  • aggregateNodeTypes(nodes) -- groups nodes by type with counts, sorted descending
  • filterGraphData(nodes, edges, typeFilter?, relationFilter?) -- applies type and relation filters
  • capGraphData(data, focusEntityId?, maxNodes?) -- caps node count for performance, keeping the focus entity and most-connected nodes

Graph Variants

ComponentUse Case
FullGraphFull-page /graph experience with toolbar, legend, and detail panel
GraphCanvasReusable canvas component with pan/zoom
MiniGraphCompact version for sidebar or embedded use
EntityGraphBlockViewBlock renderer for embedding in entity detail views

API Reference

API Route

EndpointMethodParameters
/api/graphGETentityId? (neighborhood mode), types? (comma-separated slugs), limit? (1-1000)

Core Types

TypeLocationPurpose
GraphNodefeatures/graph/types.tsNode data
GraphEdgefeatures/graph/types.tsEdge data
GraphConfigfeatures/graph/types.tsDisplay configuration
GraphDatafeatures/graph/types.tsContainer for nodes + edges
SimNode, SimLinkfeatures/graph/types.tsForce simulation types

Key Functions

FunctionLocationPurpose
computeForceLayout(nodes, edges, options)features/graph/lib/force-layout.tsD3 force simulation
nodeRadius(connectionCount)SameCompute node size
buildFlowNodes(ctx)features/graph/lib/build-flow-elements.tsConvert to xyflow nodes
buildFlowEdges(ctx)SameConvert to xyflow edges
filterGraphData(...)features/graph/lib/graph-utils.tsApply type/relation filters
capGraphData(data, focusId?, max?)SameCap nodes for performance
getTypeColor(typeSlug)features/graph/lib/colors.tsConsistent color per type

Barrel Exports

The features/graph/index.ts barrel exports: FullGraph, GraphCanvas, MiniGraph, EntityGraphBlockView, useGraphData, getTypeColor, getTypeBgColor, and all core types.

For Agents

Agents interact with graph data indirectly through entity and relation tools:

  • searchEntities -- find nodes
  • getEntity -- get entity details
  • createRelation -- add edges to the graph
  • listEntityTypes -- understand the type landscape

The graph visualization is a read-only rendering of the entity-relation data that agents create and modify through these tools.

  • Entity System (features/entities/) -- provides the data (entities + relations)
  • Block System (features/blocks/) -- entity-graph block type embeds the graph in views
  • Views (features/views/) -- graph blocks can be included in detail and workspace views

On this page