Diagram Loom
一套桌面應用程式,管理系統的部署與連線資訊,檢查有沒有漏掉的連線,並產出 C4 Model 圖。
專案簡介
畫架構圖的工具已經很多了,但真正的痛點不在畫圖:當一套系統有數百條連線時,怕的是漏掉其中一條。所以 Diagram Loom 的核心不是畫布,而是連線的完整性管理與 Linting——圖只是這份資料的其中一種呈現方式。
它刻意不做 code → diagram 的逆向工程,也不掃描真實環境做自動發現。資料由人維護,工具負責在存檔時告訴你「這個環境還缺什麼」。
核心概念:兩層模型
邏輯層是母版,環境層是分身。邏輯層定義「有哪些服務、誰要連誰」(Container、Relationship);環境層填「實際跑在哪台機器、IP 是什麼、幾個節點」(ContainerInstance、Connection)。
通則只有一條:邏輯層有的東西,每個環境都必須實現,沒實現就 lint 報錯。命名全面對齊 C4——這裡的 Container 是服務(Redis、Consul),機器叫Deployment Node,F5 這類 VIP 設備叫 Infrastructure Node。
架構亮點
- 規則在 Rust,畫面與檔案格式在 JavaScript —— 領域模型、lint、Excel 匯入、三方對帳的判斷都在 Rust;Vue 負責畫面、畫布與
.drawio讀寫。判斷標準是「這是規則還是轉接」。 - Hexagonal,但只畫該畫的那條線 ——
loom-core不相依tauri,核心不知道自己被誰呼叫,因此大部分邏輯都能用cargo test驗證。這條紀律由一個 CI 檢查守著。 - 自己的 maxGraph 畫布 —— 一開始是內嵌 draw.io 的 iframe,實測後換成自己跑 maxGraph:同一個文件、同一套事件,不再隔著 postMessage。
.drawio留下來當檔案格式,讀寫兩邊都自己寫。 - 自動排版 —— elkjs,只用
layered;實測下來只有它處理得了巢狀容器加上跨容器的邊。2480 個節點排版約 6 秒,數百節點不到 1 秒。 - 三方對帳 —— 圖是人手改過的,模型也會變。存檔時比對「圖/模型/上次的 base 快照」三方,逐項判斷哪邊動了。JS 說「圖上有什麼」,Rust 說「這代表什麼」。
- 給 AI Agent 的 MCP 端點 —— 八支工具、三種形狀(讀
{scope, select, detail}、寫{scope, items, dry_run}、刪{scope, targets, cascade, confirm}),讓 Agent 不必把整份專案倒出來就能問「prod 的 redis 建好了沒」。
Lint:這個專案的靈魂
目前 14 條規則(L001–L014),分 Error / Warning / Info 三級。幾條代表性的:
- L001 —— 邏輯層元素在某環境沒有任何實現。
- L002 —— 某條連線在某環境走不通(可達性斷裂,例如 F5 設了但後面沒接)。用 BFS 檢查。
- L004 / L005 —— 萬用字元的實際數量與
expect不符,或根本沒註明expect。 - L006 —— Endpoint 缺少實際位址(IP / port / URL / 路徑)。
- L013 —— 契約的目標端是人。人只能當來源,他沒有接點也不會被部署。
每一條會叫的 lint,面板上都要有對應的操作能就地修好——這是刻意的要求,不是加分項。
資料怎麼存
一個 Project 就是一個資料夾,內含多個 YAML 檔:logical/放邏輯層,environments/ 一個環境一個檔,diagrams/放圖。全部是純文字,可以進版控、可以 diff、可以 code review。元素用 UUID 當身分證、slug 當顯示名。
技術棧
開發狀態
主動開發中。領域模型、lint、Excel 匯入、表格與 lint 面板、編輯與復原、資源 CRUD、MCP 端點、圖的節點/連線/篩選/標註/存檔都已完成。下一步是對帳面板的 UI——三方比對的判斷已經在 Rust 做完了,缺的是讓人逐項裁決差異的那個畫面,也是這個專案最難的一塊。
連結
- github.com/lanyitin/diagram-loom—— 原始碼:Rust 的
loom-core與loom-mcp、Tauri 殼、Vue 前端。設計文件與決策紀錄目前還放在本機的 workspace 裡,尚未公開。
Diagram Loom
A desktop app that manages a system's deployment and connectivity data, lints it for missing links, and produces C4 Model diagrams.
Overview
There is no shortage of diagramming tools, but the real pain isn't drawing: when a system has hundreds of connections, what you fear is missing one of them. So the core of Diagram Loom isn't the canvas — it's completeness management and linting over the connections. Diagrams are just one way to render that data.
It deliberately does not reverse-engineer code into diagrams, and it does not scan live environments for discovery. People maintain the data; the tool's job is to tell you, on save, what this environment is still missing.
The Core Idea: Two Layers
The logical layer is the master; each environment is a copy of it. The logical layer declares what services exist and who must talk to whom (Container, Relationship); the environment layer fills in which machine it actually runs on, what the IP is, and how many nodes there are (ContainerInstance, Connection).
There is exactly one rule: everything in the logical layer must be realized in every environment, or lint reports it. Naming follows C4 throughout — aContainer here is a service (Redis, Consul), machines areDeployment Nodes, and VIP appliances like F5 areInfrastructure Nodes.
Architecture
- Rules in Rust, views and file formats in JavaScript — the domain model, lint, Excel import, and the three-way reconciliation verdict all live in Rust; Vue owns the UI, the canvas, and
.drawioread/write. The test is whether something is a rule or an adapter. - Hexagonal, but only where it earns its keep —
loom-coredoes not depend ontauri; the core doesn't know who calls it, so most of the logic is verifiable with plaincargo test. A CI check guards that boundary. - Our own maxGraph canvas — it started as an embedded draw.io iframe, then moved to running maxGraph directly: one document, one event system, no postMessage in between.
.drawiostays as the file format, with both sides hand-written. - Automatic layout — elkjs,
layeredonly; in testing it was the only algorithm that handled nested containers plus edges crossing them. 2,480 nodes lay out in about 6 seconds; a few hundred take under a second. - Three-way reconciliation — diagrams get edited by hand and the model moves too. On save, the diagram, the model, and the previous base snapshot are compared so each difference can be adjudicated. JS says what's on the diagram; Rust sayswhat that means.
- An MCP surface for AI agents — eight tools in three shapes (read
{scope, select, detail}, write{scope, items, dry_run}, delete{scope, targets, cascade, confirm}), so an agent can ask "is redis set up in prod yet?" without dumping the whole project first.
Lint: The Heart of It
Fourteen rules today (L001–L014) across Error / Warning / Info. A representative few:
- L001 — a logical element is not realized at all in some environment.
- L002 — a relationship is unreachable in some environment (e.g. the F5 is configured but nothing sits behind it). Checked with BFS.
- L004 / L005 — a wildcard's actual count doesn't match its
expect, or has noexpectat all. - L006 — an endpoint has no concrete address (IP / port / URL / path).
- L013 — a contract targets a person. People can only be a source; they have no endpoints and don't get deployed.
Every lint that can fire must have a corresponding fix in the panel — that's a requirement, not a nice-to-have.
Storage
A project is a folder of YAML files: logical/ for the logical layer, environments/ with one file per environment, diagrams/ for the diagrams. All plain text — versionable, diffable, reviewable. Elements carry a UUID as identity and a slug as display name.
Tech Stack
Status
Under active development. The domain model, lint, Excel import, the table and lint panels, editing and undo, resource CRUD, the MCP endpoints, and the diagram work (nodes, edges, filtering, annotation, saving) are all done. Next up is the reconciliation panel UI — the three-way comparison already works in Rust; what's missing is the screen where a human adjudicates each difference, and it's the hardest part of the project.
Links
- github.com/lanyitin/diagram-loom— the source: the
loom-coreandloom-mcpRust crates, the Tauri shell, and the Vue front end. The design docs and decision records still live in a local workspace and aren't public yet.