Skip to main content
Glama

Thirty seconds

git clone https://github.com/ShAInyXYZ/Dia-GramV.git && cd Dia-GramV
npm install && npm run build
node packages/mcp/bin/dgv.mjs doctor                        # checks Node + the build, prints the lines below with your path
claude mcp add dgv -s user -- node "$PWD/packages/mcp/bin/dgv.mjs" mcp
ln -s "$PWD/skill" ~/.claude/skills/dgv                     # optional: teaches the agent the workflow

Then, in any project, tell the agent:

Map this system in DGV before we start.

It reads the catalog, writes dgv/<name>.dgv.json, gets a lint report back on every write, repairs what it broke, lays the diagram out and opens it at http://127.0.0.1:7710. From then on the file is the map: every later session reads it before it reads code.

Needs Node 20.19+ or 22.12+. npm install fetches everything (~100 MB, nothing global); npm run build compiles the viewer once. Skip the build if you only want the MCP tools — everything works without it except dgv_open.

Related MCP server: mermaid-mcp-server

What's new · v0.2 — flags and history

The agent can now flag an architecture problem on the exact node, wire or frame it is about — a ⚑ bubble on the canvas with what is wrong, why, and the fix — and every change to the diagram, by the agent or by you, lands in a history you open from the bottom of the canvas. Three new MCP tools: dgv_flag, dgv_resolve, dgv_history.

Lint says whether the graph is valid. It cannot say whether the design is right. Reviewing a real project through its diagram, the agent found six things no rule would ever fire on — a process that was a dead end for settings (every change was a restart), plugins loaded three times across the map, a spawned child with no death-pact — and had nowhere to put them but a chat message that scrolls away. Now it has two places: a flag on the element, and a record of what changed.

How you use it. After the map exists, ask for a review rather than a fix:

Read the diagram, then audit the architecture for incoherences lint can't see. Verify each against the code. Pin every real one on its element with what's wrong, why, and the fix. Don't fix anything yet.

Open the viewer: every flag is a ⚑ on its card, filled and ringing until read. Click one to read the note; resolve the ones you disagree with (the history keeps the fact that it was raised), leave the rest. Then: "fix the open flags on chainx, resolve each as you go" — and the history pill turns 3 new when the agent's writes land, with a mark on every card it touched. Layout moves are not recorded; architecture is.

Where it lives. Flags sit on the element in the file ("flags": [ { "id", "kind", "title", "note", "fix", "by", "at" } ]) and lint reports each one — flag/issue counts as a warning, flag/idea and flag/question as info — so the problems panel, the rail counter and the report dgv_apply returns all carry them. ack never silences a flag; only resolving does. History is computed by the server on every save, by diffing the file on disk against the one being written, and kept in the file as history (the last 300 changes). Nobody has to remember to log anything, and a save from the browser records the same way as one from the agent. Existing diagrams need nothing — the fields are optional and appear on the first save.

Every new command.

where

command

does

MCP

dgv_flag

name, on (node / edge / frame id), title, note, fix, kind issue · idea · question. Raises one flag; returns the open count

MCP

dgv_resolve

name, on, optional flag id — needed only when the element carries several; the error names them

MCP

dgv_history

name, optional on, limit. Newest first: { at, by, node|edge|frame, change }

MCP

dgv_apply

unchanged, plus: accepts flags on any element (replaced wholesale — prefer the two above) and returns recorded, the history entries the write produced

MCP

dgv_read

unchanged, plus: under flagged elements, ## flags: N open, and ## recent changes at the end — the session-start hook prints the same

CLI

dgv history <name> [--on id] [--limit n]

the history in the terminal

viewer

H

open / close the history

viewer

click a ⚑

read the note; resolve removes the flag

viewer

inspector → + flag

raise a flag by hand on the selected element

What it is

One file. dgv/<name>.dgv.json holds frames (boundaries), nodes (components) and edges (connections). Every node has a kind from a fixed catalog — ui, service, api, db, queue, bridge, external… — and can declare ports. Every edge names the port it lands on and the protocol it speaks. Plain JSON, in your repository, next to the code it describes.

Two ways in. The MCP server is the agent's: it creates, changes and reads the file, and on every write gets a lint report — a stable code, the element, and concrete fixes. The viewer is yours: a Svelte Flow canvas where kinds have shapes and wires carry their protocol, with an inspector for every field and the same lint live in a side panel. When the agent changes the file, the page reloads.

Why it matters when an AI writes the code

The drawing is the least important part. What matters is that the model of the system is a file a program can read, check and change.

If you vibecode, the system grows faster than you can keep it in your head, and the shape you think it has drifts from the shape it has. DGV gives that shape a place to live, and a linter that objects when it stops making sense.

If you develop with an AI beside you, the diagram is where you state intent the code cannot express yet — the worker consumes the queue; the API never writes to the bucket directly — once, in a form every later session inherits.

If you are the agent, this is the difference between grepping and knowing. In an unfamiliar repository you rebuild the picture by opening files. dgv_read hands you the picture. Its complete output for the notes app below, verbatim:

# Notes app
frames 3 · nodes 6 · edges 5 · updated 2026-08-27

## frame browser: Browser
- web [ui] Notes UI — SvelteKit
## frame server: Server · one process
- api [api] HTTP API — /api/notes ports: rest:http/in
- jobs [worker] Job runner — thumbnails, exports
## frame data: Data
- pg [db] Postgres — notes, users ports: sql:sql/in
- redis [queue] Job queue — Redis lists ports: jobs:redis/in
- s3 [storage] Object store — uploads ports: put:s3/in

## edges
- web-api: web → api [sync http] fetch ports ·→rest
- api-pg: api → pg [data sql] ports ·→sql
- api-redis: api → redis [async redis] enqueue ports ·→jobs
- jobs-redis: jobs → redis [async redis] consume ports ·→jobs
- jobs-s3: jobs → s3 [data s3] ports ·→put

An agent that can read api → pg [data sql] ·→sql does not invent a REST endpoint on the database. Two hundred tokens replace a tour of the tree.

What it does — four cases

1 · Plan before you build, and be told when the plan cannot work

The agent describes a small notes app in one dgv_apply. Two ordinary mistakes are in it: the object store's port is called put on the node and upload on the edge, and a database is calling back into the API.

dgv_apply({ name: "notes-app",
  nodes: [ { id: "s3", kind: "storage", label: "Object store", frame: "data",
             ports: [ { id: "put", protocol: "s3", dir: "in" } ] }, … ],
  edges: [ { id: "jobs-s3", source: "jobs", target: "s3", kind: "data", protocol: "s3", targetPort: "upload" },
           { id: "pg-api",  source: "pg",   target: "api", kind: "sync", protocol: "http", label: "notify on change" }, … ] })

The write goes through, and the report comes back in the same turn:

{ "ok": false, "lint": { "error": 1, "warning": 2, "info": 0 },
  "diagnostics": [
    { "code": "port/undeclared", "severity": "error",
      "message": "edge \"jobs-s3\" uses target port \"upload\" but node \"s3\" does not declare it",
      "subject": { "type": "edge", "id": "jobs-s3", "field": "targetPort" },
      "fixes": [ "add port {id:\"upload\"} to node \"s3\"", "point the edge at one of: put" ] },
    { "code": "kind/store-initiates", "severity": "warning",
      "message": "\"pg\" is a db; stores do not initiate sync calls to \"api\"",
      "subject": { "type": "edge", "id": "pg-api" },
      "fixes": [ "reverse the edge and mark it kind:\"data\"",
                 "if it is a trigger/CDC stream, add a worker or queue between them" ] }, … ] }

The same report in the viewer — the failing wire is red, and every entry jumps to its element:

The first mistake is a typo that would have become a bug. The second is an architecture an agent would have implemented without a second thought. Both come back as an id, a code and a fix, so the plan is repaired before any code exists:

dgv_apply({ name: "notes-app",
            edges: [ { id: "jobs-s3", targetPort: "put" } ],       // partial: id + the field that changes
            remove: { edges: [ "pg-api" ] } })
→ { "ok": true, "lint": { "error": 0, "warning": 0, "info": 0 } }

2 · Map a system you already have

Point the agent at a repository — map Cerveau's architecture in DGV, from the code — and it reads entrypoints, listeners, clients and config, then writes what it found. The local AI harness below is 13 components in four boundaries: a panel and a phone driving a Go core, a llama.cpp server, Typesense for memory, a Python embedding sidecar.

At full size — Cerveau itself, 35 components across 7 boundaries, every call bound to a declared port:

Press S and every frame folds into one node, with the wires that crossed it merged into a single labelled link. Same file; there is no second overview diagram to keep in step with the first:

3 · Track the build on the same diagram

A node can carry a statustodo wip done blocked failed update. Press 2 and the canvas colours by status instead of kind; the file is now the build board. An agent picks up where the last session stopped by reading what is still todo, and a note on a blocked node says why:

4 · Know when it stops being true

Lint says the plan is coherent. It cannot say the plan is true — that the code on disk is still the code the diagram describes. Give a node a path (a file, a directory, a glob, a list) and dgv_drift walks the project — git ls-files, so .gitignore is respected — and reports a path that matches nothing (drift/missing), a directory of code that belongs to no node (drift/unclaimed), and two nodes claiming the same file (drift/shared).

This repository keeps its own architecture that way, every node with a path:

The first time drift ran on it, it found something:

$ node packages/mcp/bin/dgv.mjs drift dia-gramv
warning drift/unclaimed  packages/mcp/ — 1 of 5 files belong to no node
        fix: add a node with this path | widen an existing node's path to cover it | add it to meta.driftIgnore if it is not part of the system

packages/mcp/package.json, claimed by nobody, because the MCP node's path was one file. Widened, and clean.

Two optional Claude Code hooks close the loop (hooks/; doctor prints the settings block with your path):

  • SessionStart prints the outline of every diagram in ./dgv into context, with its drift summary — the first thing the agent knows is the shape of the system and whether the map is stale.

  • Stop runs drift after each turn and, only when there is something to say, leaves one line: DGV · app: 1 node path no longer exists (old). It never blocks.

The viewer

node packages/mcp/bin/dgv.mjs servehttp://127.0.0.1:7710 — or dgv_open from the agent.

Flags. Lint catches what a rule can catch. The agent (or you) catches the rest — a process that is a dead end for settings, plugins loaded three times across the map, a child process with no death-pact — and pins it on the element with dgv_flag. On the canvas it is a ⚑ bubble on the card, the frame label or the wire, filled and ringing until you open it; the note says what is wrong, why, and the concrete fix, with a resolve button. Open flags sit in the problems list too (flag/issue counts as a warning), and in the outline every session starts with.

History. The pill at the bottom centre — history · 3 new — opens upward into what changed: per element (chainx · 4 changes · 2m ago, click to see them and jump to the card) or as a timeline. Every save that changes the architecture lands there, whether it came from dgv_apply (agent) or from this page (you): a status flipped, a port added, a node renamed, a flag raised or resolved. Dragging cards around does not count. It is computed on the server by diffing the file on every write, kept in the file (capped), and readable from the agent with dgv_history. Cards changed since you last looked carry a small green mark.

Drag a node into a frame and it joins it; frames grow to fit. Ctrl+Z undoes. Ctrl+S saves — and if the agent changed the file while you had unsaved edits, the page says so and lets you choose. L cycles the wire style: floating bezier, routed around cards, straight. Shift+S saves what is on screen as a self-contained SVG, which is how every diagram in this README was made.

A / double-click

add a node, choosing its kind

drag from a node's right handle

connect; drop on a port chip to bind the edge to that port

G

wrap the selection in a new frame

1 / 2

colour by kind / by status

L

wire style: floating, routed, straight

S

fold every frame into one node; again to unfold. Hover a single frame to fold just that one

Shift+S

save what is on screen as SVG

H

the change history

F fit · I inspector · P problems · Esc close · Del delete · Ctrl+S save · Ctrl+Z undo

The folded view keeps its own arrangement per diagram in your browser, never in the file.

Reference

tool

does

dgv_catalog

the node kinds (shape and meaning), edge kinds, protocols and statuses — read once per session

dgv_list

the diagrams in the directory, with counts

dgv_read

one diagram: mode: "summary" (the outline above, default) or mode: "json"

dgv_create

a new, empty diagram

dgv_apply

upsert frames, nodes and edges by id; remove by id; places new nodes; returns the lint report. Partial: to change one field on an existing element, send its id and that field

dgv_lint

the diagnostics: code, severity, subject, fixes

dgv_drift

does the diagram still describe the code? every path must exist, every directory of code must belong to a node

dgv_flag

pin an architecture judgement on a node, edge or frame — title, note (why), fix (the change); kind issue / idea / question. Shown as a bubble in the viewer, listed by lint until resolved

dgv_resolve

remove a flag once it is fixed; the history keeps both ends

dgv_history

who changed what: every architecture change per element, agent or viewer, newest first

dgv_layout

dagre layout, TB or LR; overwrites positions

dgv_open

starts the viewer if it is not running and opens the diagram

dgv_export

markdown (tables), mermaid, summary (the outline), or svg

Diagrams go to ./dgv under the directory the agent was started in; DGV_DIR puts them elsewhere.

Shape first (schema/invalid), then references (ref/missing-node, ref/missing-frame, ref/duplicate-id), then the rules below. Errors block ok; warnings and info are advice.

Errors — fix before moving on.

code

fires when

port/undeclared

an edge names a port the node does not declare

port/protocol-mismatch

the edge's protocol is not the port's protocol

port/direction

an edge enters an out port, or leaves an in port

graph/import-cycle

modules import each other in a loop

frame/nested

a frame has a parent — frames do not nest; one level keeps folding, layout and the file simple

Warnings — the plan probably has a hole.

code

fires when

port/unbound

the target declares ports and a call edge names none

contract/unspecified

an edge between different kinds has neither a protocol nor a label

kind/store-initiates

a database, cache or bucket is the source of a call

kind/import-across-programs

an import crosses a frame boundary — two processes cannot share one

kind/api-unused

an API that nothing calls

kind/bridge-one-sided

a bridge touching fewer than two other nodes

graph/orphan

a node with no edges

layout/overlap, layout/outside-frame

cards overlap, or sit outside their frame — dgv_layout fixes both

Info — worth a look, silent in the counts: kind/store-access, kind/module-loose, kind/external-inside, graph/shared-store, layout/unplaced.

Flags — not rules but judgements, raised with dgv_flag: flag/issue is a warning, flag/idea and flag/question are info. They are never acknowledged away; they are resolved.

A warning that is intentional gets ack: "<reason>" on its element: it becomes info with the reason attached, and the reason travels with the file. Errors cannot be acknowledged.

{ "dgv": 1,
  "meta":   { "title": "Notes app", "description": "…", "colorBy": "kind", "edgeStyle": "routed" },
  "frames": [ { "id": "server", "label": "Server · one process", "tone": "amber",
                "position": { "x": 480, "y": 60 }, "size": { "width": 380, "height": 300 } } ],
  "nodes":  [ { "id": "api", "kind": "api", "label": "HTTP API", "sublabel": "/api/notes",
                "frame": "server", "status": "done", "path": "src/api", "position": { "x": 520, "y": 120 },
                "ports": [ { "id": "rest", "protocol": "http", "dir": "in" } ] } ],
  "edges":  [ { "id": "web-api", "source": "web", "target": "api",
                "kind": "sync", "protocol": "http", "targetPort": "rest", "label": "fetch",
                "flags": [ { "id": "f1", "kind": "issue", "title": "no death-pact on the child", "fix": "PR_SET_PDEATHSIG", "by": "agent", "at": "2026-08-28T12:15:00Z" } ] } ],
  "history": [ { "at": "2026-08-28T12:15:00Z", "by": "agent", "type": "edge", "id": "web-api", "op": "flag", "flag": { "id": "f1", "kind": "issue", "title": "no death-pact on the child" } } ] }

flags may sit on any frame, node or edge; history is written by the store on every save (never by hand) and holds the last 300 architecture changes.

kind is required on a node. On an edge it is inferred from the protocol when omitted — data for sql redis s3 fs smb, async for kafka nats amqp mqtt sse ws, otherwise sync. Positions are saved, so an arrangement you made stays made. The full catalog — every kind, protocol and lint code — is in skill/references/format.md.

node packages/mcp/bin/dgv.mjs serve  [--dir d] [--port p] [--no-open]      # viewer, default http://127.0.0.1:7710
node packages/mcp/bin/dgv.mjs lint   <name|file> [--json]
node packages/mcp/bin/dgv.mjs layout <name|file> [--direction TB|LR]
node packages/mcp/bin/dgv.mjs export <name|file> [--format markdown|mermaid|summary|svg]
node packages/mcp/bin/dgv.mjs drift  <name|file> [--root dir] [--json]
node packages/mcp/bin/dgv.mjs history <name|file> [--on id] [--limit n]
node packages/mcp/bin/dgv.mjs list | catalog | doctor | open <name>

path

what

packages/core

plain ESM, no DOM: catalog, schema, lint, dagre layout, orthogonal wire router, fold, exports, drift, history, file store

packages/mcp

the dgv CLI, the MCP server, and the local HTTP/SSE server behind the viewer

packages/viewer

Svelte 5 + Svelte Flow: shaped nodes, frames, folding, inspector, live problems, flag bubbles, change history

skill/

a Claude Code skill (SKILL.md) that teaches the workflow

hooks/

SessionStart and Stop hooks for Claude Code

dgv/

this repository's own diagram, drift-checked

examples/

notes-app · notes-app-broken · shop-platform · local-ai-harness

npm test — core: schema, lint rules, patch semantics, layout containment, folding, exports, SVG, drift.

Limits

DGV does not parse your source. Lint can tell you the plan is coherent; drift can tell you every node still points at code that exists and every directory of code has a node. Neither can tell you that the calls the diagram draws are the calls the code makes — that is still read by a person, or by the agent, and the file living in the repo is what makes that reading reviewable.

Not here: collaboration or hosting, sequence and lifecycle diagrams, discovery of a repository's structure. The format is versioned (dgv: 1) so those can be added without breaking existing files.

Where it came from

Cerveau is a local-first agentic coding harness. Its docs folder held a private draft called arch-viewer: a Svelte Flow canvas reading a Diagram.json of its architecture — 99 nodes, 127 edges, nodes with a kind, edges with a label. Nothing but a browser could read it, so the agent doing the building never saw it. DGV keeps the canvas, the frames and the layout, and puts a contract underneath: a catalog, ports and protocols, declared membership, a linter, and an MCP so the agent reads and writes the same file. archify supplied the idea of a typed intermediate representation with repairable diagnostics.

MIT © Mounir Belahbib

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Generates Excalidraw architecture diagrams with support for 60+ components including GCP, Kafka, and AI/Agentic shapes. Provides MCP tools for creating, modifying, and converting diagrams from structured input or Mermaid syntax.
    4
    1
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ShAInyXYZ/Dia-GramV'

If you have feedback or need assistance with the MCP directory API, please join our Discord server