Tilth:让代码阅读从“搜到这个词”前进到“看懂这个符号”
排查一个陌生仓库时,rg 很快,但它只回答“这段文字出现在哪里”。一个函数名可能藏在注释、字符串、同名实现和真正调用点里;接着往往是打开大文件、猜一个上下文范围、再搜一轮。对人是注意力切换,对 agent 则是多次工具调用和一堆重复 token。真正想知道的通常是更结构化的问题:定义在哪?谁调用它?这个文件依赖谁?这次改动到底动了哪些函数?
今天看的是 jahala/tilth。它是一个用 tree-sitter 解析源码的单二进制工具,同时提供 CLI 和 MCP server。它不需要预建索引:小文件直接返回,大文件先给带行号范围的大纲;搜索会把 definition 排在 mention 前面,并可展开相邻符号、调用关系和源码。tilth diff 则按函数报告变更,而不是只罗列文本行。
按 GitHub repository、README、LICENSE、main 最新提交和 Releases 在 2026-09-21 10:00 Asia/Shanghai 可核验的信息,jahala/tilth 有 350 stars、28 forks,主要语言为 Rust,license 是 MIT。仓库创建于 2026-02-09 17:27:39 UTC;main 最新 HEAD 为 9ecdc04,最新 push/提交时间为 2026-09-19 12:02:44 UTC,提交内容为为页面增加可点击 host 以查看对应安装命令。最新 GitHub Release 是 v0.10.1,发布于 2026-08-30 21:26:45 UTC。项目还在快速打磨阶段,正适合先在一个真实仓库和一个具体排查任务上验证,而不是把它当作完整语言服务器的替代品。
项目概览
| 属性 | 详情 |
|---|---|
| 仓库 | jahala/tilth |
| 定位 | 基于 tree-sitter 的代码阅读 CLI 与 MCP server |
| Stars / Forks | 350 / 28 |
| 主要语言 | Rust |
| 许可证 | MIT |
| 创建时间 | 2026-02-09 17:27:39 UTC |
| Latest push / main HEAD | 2026-09-19 12:02:44 UTC / 9ecdc04 |
| 最新 Release | v0.10.1,2026-08-30 21:26:45 UTC |
| 索引需求 | 无需预建 index 或额外 setup |
先把文件压成可导航的轮廓
README 中最容易理解的入口是直接把文件交给它:
tilth fastapi/dependencies/utils.py
tilth fastapi/dependencies/utils.py --section 218-232
小文件会完整返回;大文件会先得到 imports、函数与行号区间组成的 outline,再用 --section 只取需要的部分。这对代码审查或刚接手的模块很实用:先看轮廓决定往哪钻,而不是先把上千行塞进上下文。它也能按 Markdown 标题取文档片段,因此不只是给编程语言源文件用。
搜索是另一个很实际的差异。tilth get_typed_signature --scope fastapi --expand=1 会优先展示 definition,并把同一作用域的周边符号、可选的源码展开和 callees 放在一起。需要沿调用链往回查时,加 --callers;需要一次追多个概念时,可用逗号分隔的多符号查询。对于 agent,MCP 模式还会记住已展开的 definition,后续结果标记为已展示过,避免反复传同一个函数体。
安装后先用在一个具体问题上
安装路径很轻:
cargo install tilth
# 或
npx tilth
如果主要在 Codex、Claude Code、Cursor 等 MCP host 中阅读代码,README 也提供了按 host 写配置的安装子命令;例如 tilth install codex 会写入 Codex 的 MCP 配置。通用配置本质上只有把 tilth --mcp 作为 server 启动,不需要先跑一次耗时的全仓库 indexing。
我会建议从一个具体问题开始,例如:“这个鉴权检查是谁调用的?”或“这次 PR 实际改到了哪些函数?”先在 CLI 中跑 --callers、grok 或 diff HEAD~1,确认输出与当前语言、目录结构相符,再接给 agent。它的价值不在于凭空取代 rg,而在于让文本匹配之后的结构确认不必每次靠人工拼图。
边界正是它值得留意的地方
Tilth 解析语法,不解析类型;调用者和文件依赖按名字匹配。因此不同 module 里同名函数可能混淆,它也无法可靠跟踪 dynamic dispatch。没有对应 tree-sitter grammar 的语言会退回文本搜索和普通文件读取。这些限制使它不适合单独承担重构安全证明或类型级导航。
不过,它也因此保持了一个很好的取舍:一个二进制、没有索引数据库、输出围绕读代码的下一步动作。对经常需要在陌生代码库里给 agent 补上下文,或不想为临时排查启动一整套语言服务的人,先试一次定义优先搜索与函数级 diff,可能就能判断它是否会成为日常工具箱的一部分。
总结
tilth 把“搜到一个字符串”与“理解一个符号在代码里的位置”之间那段重复劳动,做成了轻量且可组合的 CLI/MCP 工作流。它不能替代类型系统,也不承诺解决动态分发;但在定义、调用者、依赖和函数级 diff 这些高频阅读任务上,tree-sitter 给出的结构足够让人少开几次文件、让 agent 少转几轮。对 Rust、Go、Python 等多语言仓库的日常探索,这种不用预热的结构化阅读很值得放进试用清单。
项目地址:https://github.com/jahala/tilth diff —git a/src/content/posts/ja/2026-09-21-tilth-tree-sitter-code-reading.md b/src/content/posts/ja/2026-09-21-tilth-tree-sitter-code-reading.md new file mode 100644