Viewert Graph Format (VGF)
VGF is the open, JSON-based standard for defining node relationships in a graph. It separates what a graph means from how it looks — making graphs portable, AI-queryable, and permanently versionable.
The Problem VGF Solves
Every diagram tool invents its own format. Draw.io produces XML that only Draw.io understands. Figma exports JSON that is purely visual — it tells you where a box is, but not what it means. Mermaid is text-only with no visual layer at all. None of them are designed to be stored in a database, queried by an API, or consumed by an AI. The result: your system architecture diagram lives in a .drawio file on someone's Desktop. It goes stale the moment the system changes. It can't be versioned, diffed, searched, or reasoned about by a machine. VGF fixes this. It is a single, open JSON format that encodes topology, visual layout, and semantic meaning together — designed for production storage, API transport, and AI consumption from day one.
Three Layers, One Document
Every VGF document holds three orthogonal layers with a strict hierarchy of authority. You can strip any one layer without losing the others.
node types · relationship kinds · technology · domain · criticality
nodes · edges · groups · children · layerId
x · y · width · height · color · strokeStyle · zIndex
The Document Structure
A VGF file is a single JSON object. The top-level keys are fixed — everything else composes from there.
document
graph
* required field
format + version
"format": "vgf" identifies the file type. "version": "1.1" enables parsers to handle future schema changes with a clear upgrade path. Both are required on every document.
document — Metadata envelope
Identity and provenance: document ID (ULID), title, description, creation/update timestamps, author, tags, revision number, and source tool. Revision increments on every save — enabling optimistic concurrency and a full edit history.
graph — The topology and visual data
Contains nodes[], edges[], groups[], ports[], and layers[]. nodes[] and edges[] hold individual elements; groups[] holds containment relationships (the canonical topology store); layers[] holds visibility filters.
views, styles, resources — Optional richness
views[] define named camera positions (zoom + pan) for saved perspectives. styles holds a design token system for reusable visual themes. resources holds embedded markdown or Vellum references attached to specific nodes.
A Minimal VGF Document
The smallest valid VGF document — two nodes connected by one directed edge.
{
"format": "vgf",
"version": "1.1",
"document": {
"id": "01HZ7K2P3Q4R5S6T7U8V9W0XY1",
"title": "Auth to Database",
"revision": 1
},
"graph": {
"nodes": [
{
"id": "node-api",
"type": "service",
"label": "Auth Service",
"semantic": { "technology": "Go / Fiber" },
"visual": {
"x": 80, "y": 120,
"width": 160, "height": 64,
"color": "#06b6d4"
}
},
{
"id": "node-db",
"type": "database",
"label": "Users DB",
"semantic": { "technology": "PostgreSQL" },
"visual": {
"x": 360, "y": 120,
"width": 160, "height": 64,
"color": "#10b981"
}
}
],
"edges": [
{
"id": "edge-01",
"from": "node-api",
"to": "node-db",
"directed": true,
"label": "reads/writes",
"visual": {
"strokeStyle": "solid",
"arrowEnd": "arrow"
}
}
],
"groups": [],
"layers": [
{
"id": "default",
"name": "Default",
"color": "#06b6d4",
"visible": true
}
]
}
}Why Groups Are the Key Innovation
Most diagram formats treat grouping as a visual concept — a box drawn around other boxes. VGF treats groups as a topology concept: a named relationship between nodes that persists regardless of how the canvas is laid out. Group membership is encoded in graph.groups[].children (the authoritative record) and mirrored as node.groupId (a derived index for O(1) canvas lookups). Writers must keep both in sync. Readers derive groupId from groups[] on load.
// canonical topology
"id": "group-backend",
"label": "Backend Tier",
"children": [
"node-payment",
"node-events"
]✓ Source of truth — read first on load
// O(1) canvas lookup
"id": "node-payment",
"type": "service",
"groupId":
"group-backend"
// ↑ populated at loadDerived from groups[ ] on load — not authoritative
Invariant: For any node n and group g: n.groupId === g.id iff g.children.includes(n.id). Writers must keep both in sync. Readers derive groupId from groups[] on load.
The Full Node Schema
Every node carries all three layers as distinct objects within a single record. The semantic and visual objects are cleanly separated.
{
// stable identity — never regenerate
"id": "node-01",
// controlled vocabulary (see below)
"type": "service",
// display name, max 128 chars
"label": "Auth Service",
// SEMANTIC LAYER — what it means
"semantic": {
"technology": "Go / Fiber",
"description": "Handles JWT issuance",
"domain": "identity",
"criticality": "high"
},
// VISUAL LAYER — how to render it
"visual": {
"x": 200, "y": 150,
"width": 160, "height": 64,
"color": "#06b6d4",
"zIndex": 1
},
// derived topology index (see §Groups)
"groupId": "group-backend",
// visibility layer reference
"layerId": "layer-backend"
}
// Node type vocabulary (partial):
// service · database · api · queue · cache
// cdn · ai_model · worker · external · client
// storage · note · group · postgresql · redis
// openai · kubernetes · docker · github ...The Full Edge Schema
Edges encode directed or undirected relationships. Asynchronous relationships (event buses, queues) use dashed strokes; synchronous calls use solid.
{
"id": "edge-01",
"from": "node-api",
"to": "node-db",
// required — always set explicitly
"directed": true,
"label": "reads/writes",
"semantic": {
// calls · publishes · subscribes · depends-on
"relationshipType": "calls",
"protocol": "SQL/TLS",
"async": false
},
"visual": {
// solid | dashed | dotted
"strokeStyle": "solid",
// arrow | none | both
"arrowEnd": "arrow",
"color": "#06b6d4"
}
}Groups Schema
Groups are first-class topology entities in graph.groups[]. They are not just visual boxes — they define which nodes belong to a named domain, tier, or team.
// In graph.groups[] — authoritative record
{
"id": "group-backend",
"type": "group",
"label": "Backend Tier",
// canonical membership list
"children": [
"node-payment-svc",
"node-event-bus"
],
"visual": {
"x": 200, "y": 140,
"width": 480, "height": 280
},
"semantic": {
"kind": "domain",
"description": "All backend services"
}
}
// On each child node — derived index
{
"id": "node-payment-svc",
"type": "service",
"label": "Payment Service",
// populated at load from groups[]
"groupId": "group-backend"
}Layers: Visibility Filters
Layers are named visibility filters — not Z-order stacking (that is node.visual.zIndex). A layer groups nodes by architectural concern so entire tiers can be shown or hidden independently.
// graph.layers[] — visibility filter definitions
[
{ "id": "layer-edge",
"name": "Edge",
"color": "#f59e0b", "visible": true },
{ "id": "layer-backend",
"name": "Backend",
"color": "#06b6d4", "visible": true },
{ "id": "layer-data",
"name": "Data",
"color": "#10b981", "visible": true },
{ "id": "layer-ai",
"name": "AI",
"color": "#f97316", "visible": true }
]
// On a node — reference the layer by id
{ "layerId": "layer-backend" }
// In a view — override layer visibility
{
"id": "view-backend-only",
"name": "Backend Services",
"layerVisibility": {
"layer-edge": false,
"layer-backend": true,
"layer-data": true,
"layer-ai": false
}
}AI Integration: Semantic-First Design
VGF is designed for AI consumption from the ground up. The semantic layer makes graphs machine-understandable without visual parsing. An AI can read graph.nodes[].semantic to understand what each node is and does, graph.edges[].semantic.relationshipType to understand data flow, and graph.groups[].children to understand domain boundaries. VGF supports a semantic-only projection that strips all visual data, reducing token count by ~50%:
// Semantic-only projection
// strips visual layer for AI consumption
{
"format": "vgf",
"version": "1.1",
"projection": "semantic",
"graph": {
"nodes": [
{
"id": "node-api",
"label": "Auth Service",
"semantic": {
"kind": "service",
"technology": "Go",
"domain": "identity"
}
},
{
"id": "node-db",
"label": "Users DB",
"semantic": {
"kind": "relational-db",
"technology": "PostgreSQL"
}
}
],
"edges": [
{
"id": "edge-01",
"from": "node-api",
"to": "node-db",
"semantic": {
"relationshipType": "calls"
}
}
],
"groups": [
{
"id": "group-backend",
"label": "Backend",
"children": ["node-api", "node-db"]
}
]
}
}Editor Data Flow
The Viewert graph editor is fully VGF-canonical. The VGF document is the authoritative state — the canvas is a projection of it.
How VGF Compares to Other Formats
VGF is the only format that holds all three layers simultaneously while remaining portable, versionable, and AI-friendly.
Mermaid / DOT — Topology only
Great for text-based diagram generation. No visual layer (you cannot save positions), no semantic layer (no machine-readable types or relationships), not designed for database storage or API transport.
Excalidraw / draw.io — Visual only
Rich visual layer, some topology. No semantic layer — a box labeled "Auth Service" carries no machine-readable meaning. Not designed for querying, AI reasoning, or long-term versioned storage.
Neo4j / graph databases — Semantic + topology
Excellent semantic and topology representation. No visual layer — you cannot store a layout. Not a document format — not portable as a single file, not embeddable in an API response.
VGF — All three layers
Topology (nodes, edges, groups), visual (x/y/width/height/color), and semantic (type, technology, relationship kind) in one portable JSON file. Versioned, diffable, queryable, storable, AI-consumable.
Versioning and Revision Control
Every VGF document carries a revision integer in document.revision that increments on every save. It enables optimistic concurrency, change tracking, and future collaboration via operational transforms.
{
"document": {
"id": "01HZ7K2P3...",
"title": "Payment Architecture",
// increments on every save
"revision": 14,
"createdAt": "2026-03-01T10:00:00Z",
"updatedAt": "2026-03-16T20:00:00Z",
// AI-generated graphs — provenance
"provenance": {
"generatedBy": "viewert-ai-v1",
"model": "claude-opus-4-5",
"generatedAt": "2026-03-16T20:00:00Z"
}
}
}File Format and API Transport
VGF files use the .vgf extension and the MIME type application/vnd.viewert.graph+json. The backend stores the full document as a JSONB column — no normalization, no transformation.
# File extension and MIME type
.vgf
application/vnd.viewert.graph+json
# Import validation checklist
✓ format === "vgf"
✓ version is a valid MAJOR.MINOR string
✓ graph.nodes and graph.edges are arrays
✓ graph.groups is present (may be empty)
✓ All node IDs are unique
✓ Edge from/to reference existing nodes
✓ Group children reference existing nodes
✓ No circular group containment
✓ String fields sanitized (no raw HTML)
✓ Document size ≤ 5MB
✓ Node count ≤ 2000