关于 Treering
Treering 在本机为代码库建立结构图,并按提交保存快照,便于开发者查看模块、类型及依赖随时间的变化。它读取 SCIP 索引,不使用 LLM,并可通过网页界面、命令行和 MCP 工具查询。
主要功能
- 01绘制模块、命名空间和类型关系图
- 02按快照比较依赖变化
- 03查看类型成员、调用方与调用关系
- 04增量更新索引并定时监视变化
- 05通过命令行和网页浏览代码结构
适用场景
- 01定位某个类型的调用方及其依赖
- 02比较两个快照间新增或移除的依赖
- 03跟踪类型调用方随时间的增长
- 04让 Agent 查询导入项目的符号与变更
MCP 相关
运行 `treering mcp` 可启动 stdio MCP 服务,提供项目列表、符号查找、调用方、子图、变更和快照查询工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Treering
English | 한국어
Treering 为你的代码库绘制地图,并为每次提交保存一份副本,让你查看结构的变化:上周哪些类型开始相互依赖,或者某个类从什么时候开始积累调用者。它完全在你的机器上运行,不会通过网络发送任何内容。它不使用大模型,因此相同的代码总会生成相同的图。

点击方框即可进入其中;你打开的部分会框出它所包含的内容。然后返回上层,查看同一张图纸的芯片布局图。

将示例项目的模块作为示意图,与一个月前进行比较。绿色表示新增:现在有一个 Billing 模块实现了支付接口。红色虚线表示已移除:以前网页会直接调用数据库。
![]() | ![]() |
| 地图。 模块以气泡表示,模块之间的调用以连线表示。新增连线为绿色,断开的连线为红色。 | 蓝图。 以方框分层展示某一层级,每个方框都标明其角色,以及其他部分如何使用它。 |
![]() | ![]() |
| 模块内部。 你打开的模块会框出它所包含的内容;连线从图纸边缘的端口穿过。 | 一个类。 它的字段和方法、它所使用的类型,以及关联它们的成员。 |
![]() | |
| 芯片。 展示代码量分布:每个区域的大小与其代码量相当,库则像焊盘一样排列在边缘。 |
以上所有内容都是 Treering 自带的示例项目(treering sample),一个虚构的小商店。
Treering 仍在开发中,不同版本之间的数据库格式可能会发生变化。设计说明见 treering-plan.md(韩语)。
安装
Windows(PowerShell):
irm https://raw.githubusercontent.com/RedholeTechnologies/Treering/main/install.ps1 | iex
Linux(x86-64):
curl -fsSL https://raw.githubusercontent.com/RedholeTechnologies/Treering/main/install.sh | sh
每个脚本都会从 Releases 下载最新构建版本,根据已发布的校验和进行验证,并将 treering 添加到 PATH。在 Windows 上,它还会将 Treering 添加到“开始”菜单。两者都不需要管理员权限,重新运行脚本即可更新 Treering。如果你不想运行脚本,可以从 Releases 下载 zip 或 tarball,并解压到任意位置。
然后运行 treering,或从“开始”菜单打开它。它会启动服务,并在浏览器中打开 http://127.0.0.1:7377。如果 Treering 已在运行,则只会打开浏览器。
若要先浏览一下再导入任何内容,请在第一个屏幕上选择 Or look around a sample project first。这会添加 acme-shop,一个虚构的在线小商店,包含一个月的历史记录。也可以从命令行运行 treering sample 添加它。
安装索引器
Treering 不会自行解析源代码。它会读取各语言索引器生成的 SCIP 索引。请为你使用的语言安装索引器:
dotnet tool install --global scip-dotnet # C#
npm install -g @sourcegraph/scip-typescript # TypeScript and JavaScript
npm install -g @sourcegraph/scip-python # Python
导入代码仓库
treering import /path/to/repo
treering serve
import 会检查代码仓库包含哪些语言,并使用所需的标志运行各个索引器。对于 C#,它会索引根目录下的解决方案;如果没有解决方案,则索引各个项目。对于 TypeScript,它会索引每个顶层的 package.json;对于 Python,则索引每个 pyproject.toml。图谱存储在你的用户文件夹中,不会放在代码仓库内;treering projects 会列出你已导入的项目。
treering serve 会在 http://127.0.0.1:7377 打开地图。如果没有指定数据库参数,它会提供所有已导入项目的地图,你可以通过页面顶部的菜单在项目间切换。
你也可以从页面导入。打开项目菜单,选择 Import…,然后选择 Choose a folder…。服务器会打开系统的文件夹选择器(Windows 上为 Explorer,macOS 上为标准对话框,Linux 上为 zenity 或 kdialog),因为浏览器不会向页面提供文件夹的完整路径。你也可以直接输入路径。选择文件夹后便会开始导入,对话框会显示各个索引器的运行情况。如果某个索引器失败,它会说明原因以及建议的处理方法。
导入和文件夹端点只接受页面自身发送的 JSON 请求,因此,浏览器中打开的其他网站无法启动导入或打开窗口。
查看地图
地图会将模块、命名空间和类型显示为节点,并将它们之间的引用显示为边。
- 点击节点即可进入其中。进入的节点会留在屏幕上,作为环围住其内容。点击空白处、右键单击该环,或按 Esc 即可返回上层,地图会标记你刚离开的节点。
- 颜色表示代码的归属:你自己的每个模块都有一种颜色,库则显示为灰色。大小表示节点的使用频率。
- Shape 菜单提供同一张图的五种布局:Constellation、Orbit、Ring、Layers 和 Tree。Layers 会从上到下排列依赖项,并将循环依赖放在一起。Tree 会逐个分支展示包含关系。
- 侧边栏会介绍你当前所在的位置,或你点击的类型:其成员、它注入的内容及注入位置、它实现的接口、调用它的对象以及它调用的对象。侧边栏中的每个名称都链接到对应节点。
- 按
/或Ctrl+K可搜索。选择搜索结果后,地图会带你前往该节点所在的位置。 - At 和 Compare 可以显示某个快照中的图谱,或两个快照之间新增和移除的边。
- Scope 可在全部内容和 Our code 之间切换。如果索引中包含某个符号的定义,该符号就会被视为你的代码,因此无需根据名称猜测即可排除库。在 Acme.Shop 中,这会将模块数从 38 个减少到 4 个,将类型数从 829 个减少到 401 个。
- Theme 提供 Light、Dark、Slate、Skyfall 和 Obsidian 主题;Language 可在英语和韩语之间切换。
- 如果系统设置为减少动态效果,装饰性动画就会停止。
保持最新
treering update /path/to/repo
treering watch /path/to/repo # every 10 minutes
treering watch /path/to/repo 30 # every 30 minutes
update 只会重新索引文件已更改的项目。每个已更改的文件都会被分配到最近的项目(.csproj、package.json 或 pyproject.toml 和 setup.py),并交由相应语言的索引器处理,因此,包含多种语言的代码仓库会使用各自的工具更新每个部分。如果缺少索引器,Treering 会打印安装它的命令。
watch 会定时运行 update,并且只在内容发生变化时添加快照,因此你工作时历史记录也会不断更新。它会从上一个快照记录的提交开始运行,因此你可以停止后再重新启动,而不会丢失任何内容;它也会统计未提交的更改和提交。
通常你无需自己运行 watch:treering serve 会在运行期间对每个已导入的项目执行同样的操作。它每 10 分钟重新索引发生更改的内容并添加快照;如果你正在查看最新快照,页面会自动切换到新快照。如果重新索引后图谱没有变化,就不会添加快照。使用 --no-watch 或在页面的 Settings 中关闭此功能,使用 --watch-minutes N 更改间隔,使用 --port N 选择其他端口。
直接使用索引
你可以自行运行索引器并加载其输出。对于 C#:
scip-dotnet index YourSolution.slnx --allow-global-symbol-definitions --output index.scip
treering load index.scip graph.db
treering serve graph.db
treering callers graph.db OrderRepository
treering map graph.db type --own
始终向 scip-dotnet 传入 --allow-global-symbol-definitions。如果不传入,符号就不会带有包名;一旦你分别为项目建立索引或添加快照,一个符号就会变成多个。在一次测试中,记录为新增的符号有 6,784 个,记录为删除的有 6,790 个。
若要比较不同时期的情况,请加载更多快照:
treering snap index-new.scip graph.db 1
treering diff graph.db 0 1
treering growth graph.db InvoiceModel
diff 会列出两个快照之间新增和移除的依赖项,growth 则会显示某个类型的调用方何时增加。
在 Agent 中使用
treering mcp
这会通过 stdio 为你已导入的项目运行一个模型上下文协议(MCP)服务。它提供六个工具:list_projects、find_symbol、callers_of、subgraph、changed_since 和 snapshots。每个工具都接受一个 project(来自 list_projects 的名称或 ID);如果留空,则会使用最近导入的项目。它们运行与页面相同的查询,并采用相同的大小限制。如果结果过大,响应会说明省略了哪些内容,以便 Agent 缩小问题范围后再次查询。treering mcp graph.db 只会针对该数据库作答。
要将其添加到 Claude Code:
claude mcp add treering -- treering mcp
在其他宿主中,命令为 treering,参数为 mcp。每个版本还包含 MCP bundle(treering-win-x64.mcpb、treering-linux-x64.mcpb),供可一步安装 MCPB 的宿主使用;同时也会以 io.github.RedholeTechnologies/treering 的名称发布到 MCP Registry。
性能
在 Acme.Shop 上(4 个项目,632 个 .cs 文件):
| 步骤 | 结果 |
|---|---|
| 建立索引(scip-dotnet) | 89 秒 |
| 加载到图中 | 2.6 秒,峰值内存 53 MB |
| 数据库大小 | 5.9 MB,原始 index.scip 为 8.2 MB |
| 第二个快照的开销 | 增加 27%(从 5.9 MB 增至 7.5 MB) |
| 全图查询 | 按模块查询需 29 毫秒,按命名空间查询需 30 毫秒,查询所有类型需 48 毫秒 |
| 下钻查询 | 182 毫秒(384 个类型,2,933 条边) |
| 增量更新 | 17 秒,其中 16.6 秒用于建立索引 |
在大型 C# 代码库中(11,385 个 .cs 文件):
| 步骤 | 结果 |
|---|---|
| 建立索引 | 3 分 28 秒,索引大小为 34.5 MB |
| 符号和边 | 43,932 个和 185,266 条 |
| 扫描期间的内存占用 | 41.6 MB,与 8.2 MB 索引的情况相同 |
| 加载 | 11 到 15 秒,103 MB,数据库大小为 40.3 MB |
| 全图查询 | 查询 115 个模块需 26 毫秒,查询 406 个命名空间需 48 毫秒,查询所有类型需 210 毫秒(上限为 2,000 个) |
扫描时的内存占用不会随索引大小增加;在这个规模下,每种全图视图的耗时都低于 300 毫秒。这是因为索引加载时会按模块、命名空间和类型汇总边,而不是在每次查询时汇总。采用这一改动后,模块图的耗时从 327 毫秒降至 26 毫秒。
语言
C#、TypeScript 和 Python 均可端到端运行。由于输入是 SCIP,添加一种语言主要就是添加它的索引器:TypeScript 无需对 Treering 做任何更改;模块级别成为 npm 包,命名空间则成为独立文件夹。构造函数注入可通过 .ctor、<constructor>、__init__ 和 <init> 识别。update 和 watch 也支持 TypeScript;在 ShopWeb 上,一个包中有 19 个文件发生更改,用时 52s。
scip-python 0.6.6 无法在 Windows 上启动:它根据路径分隔符构建正则表达式,而单独的 \ 不是有效模式。Treering 会在 scip-python 运行前加载一个小脚本,对这个模式进行转义。它还会为 scip-python 查找 pip,先检查代码库的 .venv,然后检查 py 启动器知道的任何 Python。如果没有 pip,它会使用空的包列表进行索引,这只会导致无法获取第三方包的名称。在 python-sample 上,这生成了 1,800 个符号和 6,564 条边,用时 51.6s。
每种语言都有自己的特点。TypeScript 生成的继承边很少,因为采用结构化类型时,索引器很少会输出 implements。此外,14.8% 的 TypeScript 引用无法归属到定义,相比之下 C# 为 1.4%;这是因为导入和模块级代码出现在文件中的任何定义之前。
已知限制
SCIP 会记录引用的位置,但不会记录它所属的符号(enclosing_symbol 为空)。Treering 会将每个引用归属到它之前最近的定义。在类型层面,这种做法很可靠,因为文件中的引用属于该文件定义的类型。在方法层面,遇到嵌套类型、lambda、本地函数、属性访问器和字段初始化器时就会出错,因此页面和 MCP 工具会将这些边标记为推断结果。
C# 顶级语句(如今通常位于 Program.cs)之前没有任何定义。scip-dotnet 仍会将 args 写为编译器生成的 Program.<Main>$ 的参数,因此 Treering 会将这些调用归入项目的 Program。这就是服务的启动注册会显示在图谱上的原因。如果这些语句从未使用 args,则不会收录其中的调用。
更新至少需要约 10 秒,几乎全部时间都花在索引器上。最小的 C# 项目在 scip-dotnet 中耗时 16.6s,而 scip-typescript 为 ShopWeb 的单个包耗时 50s。Treering 自身用于比较和加载的部分耗时不到半秒。
不在范围内
Treering 不会包含:
- 自有语言解析器,因为 SCIP 索引器会负责解析
- 大模型、嵌入或向量搜索,因为图谱必须可复现
- 云同步、账户或遥测
- 代码编辑
构建
dotnet test
dotnet publish src/Treering.Cli -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
这会生成一个约 52 MB 的单一可执行文件。网页已嵌入其中,运行时无需安装其他任何内容,甚至不需要 Node。若未启用 IncludeNativeLibrariesForSelfExtract,e_sqlite3.dll 会放在可执行文件旁边。
NativeAOT 目前尚不可用,因为 JSON 序列化使用了反射,而 MCP SDK 会扫描程序集。
为什么叫“Treering”
树木年轮是一年生长的痕迹,层层围绕着此前的年轮;锯开树干就能一眼看到它的完整历史。Treering 对代码也做同样的事。它会为每次更新保存一份结构快照,让你回顾模块、类型及其依赖关系是如何演变的。这个名字用一个词点出了它与其他代码图谱的区别:时间。它也呼应了代码本就由树构成这一点,从语法树到模块、命名空间和类型组成的树。
徽标描绘的是锯开的原木端面:偏心髓心周围是不规则的年轮,一道干裂从树皮向内延伸,最外侧的年轮代表此刻,并以强调色呈现。
许可证
Apache-2.0。已发布可执行文件中捆绑的组件及其许可证,列于 THIRD-PARTY-NOTICES.md。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。




