关于 Mirofy
Mirofy 将代码仓库映射为带来源引用的交互式 HTML 图表,面向开发者和技术团队。其证据图记录文件、行号和提交信息,并明确报告无法检查的内容,而不补猜缺失部分。
主要功能
- 01映射仓库结构和依赖关系
- 02按文件、行号和提交引用证据
- 03报告未读取文件和未知项
- 04搜索并检查交互式图表
- 05渲染和验证图表文档
- 06提供命令行、Agent 技能和 MCP 服务
适用场景
- 01追踪代码库中的依赖关系
- 02核查图表连线的证据来源
- 03找出扫描未覆盖的文件
- 04创建或验证架构图
MCP 相关
Claude Code 插件包含 MCP 服务和技能。README 未说明该服务开放的工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
为系统绘制图表,标明信息来源,并说明哪些内容无法看到。
这就是产品的全部:一个 HTML 文件,在浏览器中打开。其中的每种颜色
都代表系统自身的分类——后端、数据库、云、安全、消息总线、外部服务——
仅此而已。颜色绝不表示箭头的去向,只表示事物是什么。
打开这个文件 ↗ —
点击任意节点即可查看其证据、追踪哪些内容会到达该节点、搜索和演示。
它是什么
让 Mirofy 扫描一个代码仓库。它会将代码读取为证据图, 根据该图构建一个模型,再将模型编译成一个 HTML 文件,供你打开、搜索、分享和核查。
它绘制的每种关系都能回答一个问题:这项关系有什么证据? 每项关系都附有 来源文件、行范围和对应的提交。如果某些信息未知,图表会明确说明, 而不是擅自填补空白。
在此代码仓库上运行,就能得到下面这张图——不是样图,也不是手工绘制的:
这里的每个方框颜色都相同,这正是重点。这十二个方框代表
同一种事物——根据清单生成的软件包——因此没有需要用颜色表达的区别,
颜色也就没有表达任何区别。顶部的图之所以色彩丰富,是因为那个系统确实包含六种类型。
如果工具为了让图更生动而给这些方框着色,就会凭空捏造它并未发现的区别。
打开在线版本 ↗ — 点击任意
节点即可查看其背后的文件、行范围和提交。
无需安装——只需一条命令,即可打开图表:
npx mirofy-cli map . # YOUR repository, mapped, in one command
npx mirofy-cli demo # a finished artifact, to see what this produces
npx mirofy-cli init # a starter document of your own to edit
npx mirofy-cli render architecture architecture.json
也可以交给你的 Agent——只需一行命令,即可为 Claude Code、Cursor、Gemini CLI、Amp 和其他十多个工具安装技能:
npx skills add Hasan-Laraib/Mirofy
然后提出请求:绘制此仓库的架构图。你的 Agent 会读取
SKILL.md,并运行同一个 CLI。
在 Claude Code 中,插件同时包含技能和 MCP 服务:
/plugin marketplace add Hasan-Laraib/Mirofy
/plugin install mirofy@mirofy
以上每种方式使用的都是同一个软件包。Agent 不会绘制图表——它运行的就是你会运行的 CLI,因此它报告的内容不会与 CLI 的报告产生偏差。
map 会在你指定的目录中运行整个流水线——扫描、建模、编译、布局、渲染——并在代码旁边写入 architecture.html。
map --out <dir> 会将图表和中间文件写入该目录,避免任何文件落入你的仓库;不指定该参数时,中间文件会写入 <target>/scan。如果指定了输出路径,则始终以该路径为准。即使仓库没有声明工作区,它也能正常运行:没有可绘制的软件包时,它会对源代码目录及其间的导入关系进行建模。
或从你自己的代码中调用
mirofy-cli/api 提供了与库相同的流水线——无需 argv、无需 process.exit,也无需解析 stderr:
import { render, validate, map } from 'mirofy-cli/api';
const html = await render('architecture', diagram); // one HTML string
const { ok, diagnostics } = await validate('architecture', diagram);
const { html, drawn, coveragePath } = await map('.'); // the whole pipeline
如果文档未通过验证,就会抛出一个 MirofyRenderError,其中包含 .diagnostics——渲染器提供的结构化报告;每个条目都包含 code、subject、作为依据的 evidence,以及支持的修复方法。validate 会返回这份报告,而不是抛出异常,因为“此文档无效”本身就是一个答案;检查一百份文档也不应该需要一百个 try/catch 代码块。
map 需要一个 git 仓库:每条事实都与某个修订版本关联,因此没有提交记录的目录没有可供引用的证据,它会明确说明这一点,而不是等到后续步骤再失败。
它读取什么
JavaScript 和 TypeScript 导入 · Python 导入 · Go 导入 ·
Java 导入 · Rust 导入 · Kotlin 导入 ·
package.json 工作区 · Express 和 Next 路由 · docker-compose。
这就是完整列表,而这份列表本身就是重点。其他所有内容都会被
报告,而不是跳过:coverage.md 会按类型列出每个没有被任何适配器打开的文件;如果未读取的文件多于已读取的文件,map 也会在退出前说明这一点。把它指向一个 Ruby 仓库,你会得到一个诚实的空结果,其中列出每个未读取的 .rb 文件——而不是从 examples/ 文件夹中的两个 JavaScript 文件推断出一个看似可靠、实则范围很小的结果。
Python 根据文件是否存在来解析,而不是依靠惯例:相对导入相对于导入文件所在目录解析,绝对导入则相对于仓库根目录,以及实际包含包的任何目录解析。若一个说明符匹配两个源码根目录,就会将两者都列为缺口,因为最终选择哪个取决于 sys.path,这是配置决定的,不是源码决定的。
Go 根据 go.mod声明的模块路径解析,并按照工具链的方式判断标准库——路径的第一段若包含一个点,就是域名;域名表示从某处获取的模块。Java 根据文件声明的 package 语句构建索引,而不是根据目录布局:Maven 惯例会将 com.acme.store 放在 src/main/java/com/acme/store 下;但惯例不总是可靠,编译器读取的是声明。
Rust 会从右侧逐步剥离 use 路径,直到找到实际文件,因为 use crate::a::b::C 并未说明 a、b 或 C 中哪一个是文件。它会从 Cargo.toml 读取 crate 名称和源码根目录——包括声明的 [lib] path,因为 src/ 只是默认值——并且知道 Cargo 会将 tests、benches 和 examples 的每个直接子项都编译为独立 crate。
Kotlin 会根据声明本身构建类型索引,其中包括 class、interface、object、typealias 和 fun interface,而不是依据文件名;Kotlin 文件不必以其中的类型命名,而且可以声明多个类型。它与 Java 共用该索引:两者编译到同一个命名空间,也可以自由地相互导入,因此,一个扩展的索引会把指向另一个扩展中缺失类型的实际边报告为缺失。
在以上每种语言中,导入若指向此仓库内部不存在的内容,就是一个缺口——绝不会被视为依赖于已发布的自身副本。
如果你不确定想要哪种图表,npx mirofy-cli guide "show an API request with a cache miss" 会替你选择图表类型。
作为你保留使用的 CLI——npm install -g mirofy-cli。它安装的命令是
mirofy;包名带有 -cli 后缀,是因为 npm 拒绝了过于接近现有 minify 的裸名称。
从源码运行——完全无需安装,因为根本没有东西需要安装:
git clone https://github.com/Hasan-Laraib/Mirofy.git
node Mirofy/packages/core/bin/mirofy.mjs demo
即使在没有运行 npm install 的干净检出目录中,这也能正常工作,因为这里的每个包都没有运行时依赖。
作为 Agent 技能——构建技能包,并将其复制到 Agent 查找的位置:
git clone https://github.com/Hasan-Laraib/Mirofy.git
cd Mirofy && npm install && npm run build:skill
cp -r dist/mirofy ~/.claude/skills/ # Claude Code
cp -r dist/mirofy ~/.agents/skills/ # Codex CLI, opencode
然后提出请求:Use mirofy to map this repository's runtime architecture.
技能包大小为 2.8 MB,名称取自其中的技能——如果改为复制 packages/core,安装的技能就会名为 core,但其自身的 frontmatter 却称它为 mirofy,而且还会连同测试套件一起带上。在写入技能包之前,build:skill 会将它复制到一个不包含仓库的目录中并渲染图表:只能在自身检出目录中运行的包,称不上真正的包。
运行时不会下载任何内容,也不会向外发送任何信息——没有更新检查,因为一个会访问网络来介绍自己的工具,就是一个会访问网络的工具。
分步了解整个流水线
mirofy map 按顺序执行以下五个步骤。如果你只想要中间产物,
mirofy map . out.html --out ./scan 会将每一步的产物——证据图、
模型、视图和布局完成的文档——都写入该目录。
如果要单独运行某个步骤,或将其输出到其他位置,你需要检出代码库; 这些是代码库自带的 npm 脚本,并非已安装的软件包提供的命令:
npm run scan # repository → evidence graph
npm run model -- --from-graph --graph scan/evidence-graph.json
npm run compile # model → a bounded view
npm run layout # view → positioned document
node packages/core/bin/mirofy.mjs render architecture scan/diagram.json out.html --repo-root .
在此代码库上运行时,它会记录 1,227 条事实,覆盖 223 个文件, 其中有 17 个无法读取的缺口;推导出 19 个组件和 21 个 关系——每个关系都注明了来源文件和行号——并绘制出十二个, 同时记录了省略的内容及原因。
这些数据经过核验,并非凭记忆写下——请参阅下方的 本页中的数字。
这些命令会重现本页顶部的图表。图表作为文档存放在 assets/ 下;
交互式产物只在构建时生成,不会存储。
没有代码库?可以编写 JSON 文档,或转换 Mermaid 图表:
node packages/core/bin/mirofy.mjs import mermaid design.mmd
node packages/core/bin/mirofy.mjs render architecture design.json out.html
node packages/core/bin/mirofy.mjs validate architecture design.json --json
你会得到什么
展开任意一条边,它都会告诉你为什么它会出现在图表中:关系、
来源类别、来源文件和行号,以及核验所依据的提交。下方展示的是许多工具
遗漏的一半——扫描器无法确定的内容,都被记录下来,而非靠猜测。
这份记录真实存在,取自此代码库。这个缺口也一样。
关于下方图示的三项说法,每项都有相应依据,确保内容准确。
颜色表示节点类型,绝不表示箭头方向。
六种预设,支持浅色和深色。 |
五种图表类型,一个模式,一个验证器。
architecture · workflow · sequence · dataflow · lifecycle——它们背后
共用同一套带类型的 IR。
|
一个文件。无需服务,也不依赖网络。
图表、证据、搜索和所有交互都在这个文件中。它唯一会向互联网请求的内容是
一种网络字体,它不会等待该字体,也不需要它;即使没有字体,
也会回退到你的系统等宽字体。
每次运行都会由 scripts/check-readme-claims.mjs 检查,
一旦发现可能阻碍首次绘制或改变图表内容的引用,就会导致构建失败——如果这句话
夸大了产物实际获取的内容,也同样会导致构建失败。
三十个图表全部在线 ↗——五种类型 × 六种 预设,每次提交后都会重新构建。
### 实际使用中的查看器不是模型图。下面的每一帧都是已发布查看器的截图,由 scripts/build-screenshots.mjs 通过真实点击驱动——如果某个控件被重命名或面板无法打开,它会直接失败,而不会复用旧图片;如果某项功能没有实际效果,它也不会保存该功能的截图。
查找任何内容。输入 |
询问节点的来源。 |
追踪事物之间的关联。 |
对比整个系统中的角色。Semantic Lens 会一次性为每个节点回答来源和类型,而不是每次只看一个节点。 |
它能做到而图表工具做不到的事
它不会猜测
扫描器无法解析的文件会被记录为缺口,绝不会悄无声息地略过。每条事实都会标注六种来源类别之一,因此 source-backed 和 inferred 看起来绝不会一样。
当证据无法确定某项决策时,也遵循同样的规则。派生组件的类型是 package——扫描器知道清单存在,却不知道某个东西是不是“后端”。Node 内置模块的 878 个导入会被计数并命名,不会绘制出来,也不会悄无声息地丢弃。在 Python 中,计算得出的 importlib.import_module(name) 会连同所在行一起记为缺口;解析前会清除文档字符串——否则,写满示例导入的文档字符串会变成代码中并不存在的边,还会被引用为散文。没有固定提交可供验证的引用会被丢弃,而不是显示出来,因为无人能核查的引用比没有引用更糟——map 会从你的 origin 远程仓库读取提交;如果没有可读取的远程仓库,则使用 --repo-url 和 --revision。
护照最多列出三个来源,因为四十三条链接称不上护照。达到上限时会显示 “显示 43 个引用来源中的 3 个”,因此绘制数量的上限绝不会被误认为是对证据的描述。
它能回答有关系统的问题
mirofy explain callers api # what points at api
mirofy explain impact api # what is downstream of it
mirofy explain find payment # id, label, kind or metadata match
mirofy explain gaps # what the scan could not read
每个答案都会列出可能改变答案的未读取文件。“没有任何内容调用 PaymentService”,只有在扫描器读取了所有内容时才有用;如果有六个文件解析失败,这句话就很不可靠——因此,空结果表示未找到,绝不表示不存在。
impact 回答的是可达性,不会超出这一范围。哪些内容相互关联是关于图的事实;变更是否会导致故障,则是关于运行中系统的判断,而 Mirofy 没有证据作出这种判断。
你的 Agent 也可以提问
通过 MCP 执行相同的查询——11 个工具、同一套引擎,而不是可能与 CLI 结果不一致的另一套实现。这里也有 assert 和 timeline,因为“这项更改是否允许”和“这里有什么变化”是 Agent 编辑时会提出的问题;如果它还得通过 shell 才能询问,就根本不会问:
{ "mcpServers": { "mirofy": { "command": "npx", "args": ["-y", "mirofy-cli", "mcp"] } } }
让任意 MCP 客户端连接到它即可。它会相对于客户端启动时所在的目录读取 ./scan——也就是上次 map --out ./scan 写入的内容;--model 和 --graph 可用于覆盖设置。无需克隆,也无需预先安装任何内容。
完整性警告会出现在 Agent 读取的正文中,而不只是 JSON 里。大多数客户端会把文本提供给模型,并丢弃其余内容。
它会检查架构规则——结果有三种,而不是两种
mirofy assert # reads architecture-rules.json
pass、fail 和 unproven。如果扫描中有文件未读取,而规则没有发现违规,就不能说该规则已被证实成立,因此绝不能算作通过。把缺失的信息变成绿色勾号,正是这个项目要避免的唯一失败。
有些缺失的信息是永久性的——如果动态导入的基础路径是变量,不靠猜测就无法解析。对于这些情况,可以逐个路径地确认,引用缺失信息的原因,并附上书面说明。针对动态导入编写的确认,一旦该文件解析失败,就不再适用。而基于一项确认而通过的规则也会明确说明:
[ok ] no-cycles — No violation. 8 unread file(s) are acknowledged as unable
to hide one; this rests on that judgement, not on a complete scan.
2 passed, 0 failed, 0 unproven of 2
2 of those rule(s) rest on acknowledged gaps, not on evidence.
它会告诉你有哪些变化
mirofy timeline # cited-file churn, newest first
mirofy drift --base a.json --head b.json # what two scans say differently
漂移报告只报告变化的事实,不包含其他内容——没有评分、风险标签或合并建议。它会在每个拉取请求上运行,而且绝不会导致拉取请求失败。
我们宁愿不公开的数字
基准测试只问一个问题:给模型一份书面需求,它生成的图有多大概率第一次就能用?
目前,在 Claude Code 编写的 8 份需求中:2 份能用。
node scripts/benchmark.mjs --author "<your command>" --model "<id>" --keep benchmarks/corpus/mine
node scripts/benchmark.mjs --replay benchmarks/corpus/mine
这个数字并不好看,但它是真实的。即便如此,仍有三点值得将它公布出来。
能用意味着没有问题,而不是被接受。 警告意味着图表在告诉你需要再检查一遍;而这正是首次生成成功率应该排除的情况。在这组样本中,还有两份文档通过验证且没有错误,但仍不计入成功数。
测量基于已保存的样本集,而不是重新生成的样本。 --keep 会保存模型生成的内容;--replay 会针对这些完全相同的文档重新运行工具,而不再次调用模型。如果不将两者分开,每次重新运行都会同时改变文档和工具,任何变化都可能归因于其中一方——这就是成功率连续几周为零,却没人能说清问题出在哪里的原因。重放甚至无法声称换了作者:模型信息会从已保存的清单中读取,如果 --model 与之不一致,就会被拒绝。
成功率变化的原因是可以明确指出的。 最近一次布局引擎更新让相同的 8 份文档从 0/8 提升到 2/8,组合错误总数也从 121 降到 34。此前,一条诊断信息要求作者“缩短标签或增大尺寸”,实际上是在要求作者重命名系统的一部分,以适应渲染器选定的框。现在,渲染器会加宽这个框。
如果你要将这个数字与其他地方公布的数据比较,请先确认测量的是什么。如果 Agent 能调用验证器并修复自己的输出,最后再由人工审查,那么它的成功率与盲测的单次生成模型是不同的测量方式——不是更差,而是不同。我们采用的是后者。
工件内部
- 节点查找器、语义透镜、语义雷达 — 搜索、筛选并概览大到无法一次读完的图表
- 路径探测器 — 解析有向路径,并查看它逐跳呈现
- 语义通行证 — 点击节点查看其类型、标签和引用证据;凡是有固定提交版本作为依据的内容,都会显示已验证来源标记
- 你的代码与其他人的代码分开绘制 — 你编写的模块显示为实线,第三方软件包显示为虚线。这不是颜色:色觉障碍友好预设已将七种色调用于七种语义角色,因此第八种颜色只会让部分读者看出区别
- 引导视图、演示模式、动效调节器和
?embed=1 - 三种导出方式,可直接复制到剪贴板:
- 导出 → 分享卡片 — 使用当前主题和预设的 1200×630 PNG
- 导出 → 路径分享卡片 — Route Probe 解析出的确切路径
- 导出 → 可达性分享卡片 — 可达性查询返回的集合
卡片展示的是读者实际执行的操作。它们都不会声称内容已经过验证,也不会根据没有返回结果的查询生成。
npm run gallery # every type in every preset → preview/index.html
npm run build:site # the same, plus this repo's self-model → site/
第二个是 CI 每次提交时发布到 hasan-laraib.github.io/Mirofy 的版本。仓库中不会提交任何内容:网站会根据其所描述提交版本中的代码构建,因此不会悄悄继续描述旧版本。
带到其他地方
交互式文件约为 720 KB,这是有价值的。但 README、拉取请求或 Notion 页面都无法保留这些内容,因为它们都会移除脚本。因此:
# 19 KB standalone SVG: no scripts, no stylesheet needed
node packages/core/bin/mirofy.mjs render architecture in.json out.svg --format svg-static
# or open it in an editor you already own — from a checkout; the export
# package is not bundled into the published CLI
npm run export -- drawio architecture in.json
npm run export -- excalidraw architecture in.json
| 放置位置 | 方式 |
|---|---|
| README、拉取请求、Notion、Confluence | svg-static |
| Figma、Canva、Illustrator、Sketch | svg-static — 样式写入属性中,因此导入后会保留颜色 |
| diagrams.net · draw.io VS Code 扩展 | drawio — 实际形状和连接线 |
| Excalidraw · Obsidian · VS Code | excalidraw — 绑定箭头、可移动方框 |
SVG 以两种方式携带样式:既写在样式表中,也写在元素上。在 SVG 中,样式表的优先级高于属性,因此浏览器会根据 CSS 渲染;只有在 CSS 被忽略时才会采用属性——Figma、Canva 和 Illustrator 恰好就是如此。如果没有这些属性,导入的图表形状正确,却没有颜色。
这两种编辑器导出都会准确说明丢失了什么,而且说明内容是根据你的文档计算得出,并非照搬免责声明。只能在生成它的工具中编辑的图表,就是被挟持的图表。
已证明的内容
一致性矩阵共有 105 行。其中 85 行无需浏览器即可证明;另外 19 行需要无头 Chrome(MIROFY_CHROME),总计 104 行。
npm run check # lint, types, 1,000+ tests, golden parity, conformance, size, audit
每一行都列出一个测试,标题必须逐字符完全匹配——如果证明文件通过了,但对应测试本身已被重命名,该行就算未证明,绝不算通过。其中一行(6.10,确定性 ZIP 打包)尚未证明,并如实计入,而不是悄悄删掉。
跳过不等于通过。 除非浏览器实际运行,否则浏览器测试行绝不会计入已证明总数。
此页面上的数字也会经过检查:
node scripts/check-readme-claims.mjs
该检查会统计矩阵行数,读取 MCP 服务提供的工具列表,渲染工件以测量其大小,并重新运行基准测试。之所以加入这项检查,是因为一次审查发现页面上有三个数字同时出错——它们都不是故意造假,只是在写下时正确,却被仓库遗留至今。一个主张应核查陈述的页面,不该自己也写下未经核查的陈述。
证据与来源
六种类别,绝不混淆:
| 类别 | 含义 |
|---|---|
authored | 由人工编写 |
source-backed | 从引用的文件及行范围中读取 |
statically-derived | 未运行代码,而是从代码计算得出 |
config-derived | 从清单中读取——属于配置,而非代码 |
runtime-observed | 在实际运行中观察到 |
inferred | 一种猜测,并明确标注为猜测 |
源代码引用会在渲染前,于真实的本地检出副本中对照固定的 40 字符提交进行验证。若某路径在该版本中不存在,就会报错,而不会显示为失效链接。
可以同时声明多个代码库,引用中会注明所属代码库。若只对照“某个”代码库,而不是“正确的那个”进行验证,就会让来自相邻代码库的路径冒充此处的证据。
软件包
| 软件包 | 功能 |
|---|---|
scanner | 将代码库读取为事实与缺漏的适配器 |
evidence | 仅追加的证据图、查询、真实覆盖情况 |
model | 系统模型:稳定 ID、证据引用、人工覆盖项 |
compile | 视图编译器与规划器接口 |
explain | 图查询、架构规则、漂移、时间线 |
mcp | 将模型作为 Agent 上下文 |
import | 将 Mermaid 转为类型化文档 |
export | draw.io 和 Excalidraw 应急方案 |
layout | 约束布局:从意图到坐标(开发时使用) |
judge | 可选:向 System One 模型询问缺漏,并保留回执 |
core | 渲染器、架构、验证器、CLI |
viewer | 交互式查看器,构建到一个模板中 |
benchmark | 基于已保存语料库测得的首轮可用率 |
conformance | 矩阵,以及每一行指定的测试 |
所有软件包均无运行时依赖。产物只包含它自身。
packages/core/assets/template.html 由 packages/viewer/ 生成。切勿直接编辑它——应编辑源文件并运行 npm run build:template。npm run check:template 会从源文件重新构建,并在已提交文件出现偏差时失败。
署名
每个产物都会说明由什么工具生成。查看器页脚可关闭——图表属于你,而无法关闭的横幅是对他人文档的强加。分享卡片则带有永久署名,因为卡片会脱离上下文传播,出现在没有任何信息说明其来源的地方。
署名会标明工具名称,不对图表作任何声称,也不包含 URL:嵌入每个分享产物的链接,存续时间可能超过它指向的地址。
MIT。packages/core/LICENSE 原样保留了导入的渲染核心所需的第三方版权声明;根目录的 LICENSE 涵盖本项目自身的工作。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。