Git-friendly filesystem graph database with one-file-per-entity storage for minimal diffs.
- π One file per entity - Nodes stored as
nodes/{id}.json, edges asedges/{from}__{type}__{to}.json - π Deterministic JSON - Sorted keys and consistent formatting for clean git diffs
- π― Confidence levels - Support for EXTRACTED (AST), INFERRED (LLM), and AMBIGUOUS relationships
- π Pluggable storage -
Storeinterface for custom backends - β Schema validation - Validate nodes, edges, and referential integrity
- π Graph traversal - BFS, DFS, and path finding algorithms
- π Graph analysis - Hub detection, community detection (Louvain), graph diff
go get github.com/plexusone/graphfsimport (
"github.com/plexusone/graphfs/pkg/graph"
"github.com/plexusone/graphfs/pkg/store"
)
// Create a filesystem store
fs, err := store.NewFSStore(".graphfs")
if err != nil {
panic(err)
}
// Create nodes
node := &graph.Node{
ID: "func_main",
Type: graph.NodeTypeFunction,
Label: "main",
Attrs: map[string]string{"package": "main"},
}
fs.WriteNode(node)
// Create edges
edge := &graph.Edge{
From: "func_main",
To: "func_helper",
Type: graph.EdgeTypeCalls,
Confidence: graph.ConfidenceExtracted,
}
fs.WriteEdge(edge)g, err := fs.LoadGraph()
if err != nil {
panic(err)
}
fmt.Printf("Nodes: %d, Edges: %d\n", g.NodeCount(), g.EdgeCount())import "github.com/plexusone/graphfs/pkg/schema"
validator := schema.NewValidator()
validator.AllowedNodeTypes = []string{"function", "file", "package"}
if err := validator.ValidateNode(node); err != nil {
fmt.Printf("Invalid node: %v\n", err)
}
// Validate entire graph
errs := validator.ValidateGraph(g)
for _, err := range errs {
fmt.Printf("Error: %v\n", err)
}import "github.com/plexusone/graphfs/pkg/query"
// Create a traverser from a graph
traverser := query.NewTraverser(g)
// BFS traversal from a node
result := traverser.BFS("func_main", query.Outgoing, 3, nil)
fmt.Printf("Visited %d nodes\n", len(result.Visited))
// Find path between nodes
path := traverser.FindPath("func_main", "func_helper", nil)
fmt.Printf("Path: %v\n", path.Visited)
// DFS with edge type filter
result = traverser.DFS("func_main", query.Both, 5, []string{"calls"})import "github.com/plexusone/graphfs/pkg/analyze"
// Find hub nodes (most connected)
hubs := analyze.FindHubs(nodes, edges, 10, []string{"package", "file"})
for _, hub := range hubs {
fmt.Printf("%s: %d connections\n", hub.Label, hub.Total)
}
// Detect communities using Louvain algorithm
result := analyze.DetectCommunities(nodes, edges)
fmt.Printf("Found %d communities, modularity: %.3f\n",
len(result.Communities), result.Modularity)
// Compare two graph snapshots
diff := analyze.DiffGraphs(oldNodes, newNodes, oldEdges, newEdges)
fmt.Printf("Changes: %s\n", diff.Summary).graphfs/
nodes/
func_main.json
func_helper.json
pkg_mypackage.json
Each node file contains:
{
"attrs": {
"package": "main"
},
"id": "func_main",
"label": "main",
"type": "function"
}.graphfs/
edges/
func_main__calls__func_helper.json
Each edge file contains:
{
"confidence": "EXTRACTED",
"from": "func_main",
"to": "func_helper",
"type": "calls"
}| Constant | Value |
|---|---|
NodeTypeFunction |
function |
NodeTypeMethod |
method |
NodeTypeClass |
class |
NodeTypeStruct |
struct |
NodeTypeFile |
file |
NodeTypePackage |
package |
NodeTypeModule |
module |
NodeTypeVariable |
variable |
NodeTypeConstant |
constant |
NodeTypeInterface |
interface |
| Constant | Value |
|---|---|
EdgeTypeCalls |
calls |
EdgeTypeImports |
imports |
EdgeTypeImplements |
implements |
EdgeTypeExtends |
extends |
EdgeTypeUses |
uses |
EdgeTypeContains |
contains |
EdgeTypeDependsOn |
depends_on |
EdgeTypeReferences |
references |
EdgeTypeInjects |
injects |
EdgeTypeHandlesRoute |
handles_route |
EdgeTypeHasMany |
has_many |
EdgeTypeBelongsTo |
belongs_to |
EdgeTypeAnnotatedWith |
annotated_with |
EdgeTypeMethodOf |
method_of |
| Level | Description |
|---|---|
EXTRACTED |
Directly extracted from source (AST, imports) |
INFERRED |
Inferred by LLM or heuristic with confidence score |
AMBIGUOUS |
Uncertain relationship requiring human review |
MIT