关于 graft
graft 是面向编码 Agent 的命令行技能,通过带源码位置的图谱笔记和调用关系帮助理解代码库。它支持定位代码、查看文件 API,以及评估修改影响。
主要功能
- 01排序检索代码与概念
- 02穷举索引文本搜索
- 03快速查看文件 API 签名
- 04追踪调用与引用关系
- 05浏览代码库结构
- 06检查图谱是否过期
适用场景
- 01查找某项行为的实现位置
- 02列出某个符号的所有出现处
- 03修改函数前检查调用方
- 04熟悉陌生代码库
MCP 相关
连接 graft MCP 服务后,可通过它使用检索、搜索、文件 API、调用追踪、代码库映射和新鲜度检查工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trailhq/ trail-code --skill graft安装后在 Claude Code 中输入/graft确认已加载。
详细介绍
graft
graft/ 存放着本仓库的图谱:其中包含一些简短的 Markdown 节点,每个节点都用文字说明一个部分,并标出其涵盖的确切 file:line 范围;此外还有一张连接图,展示谁调用了什么。查询一个节点只需几百个 token;通过阅读源码来重建这些理解则要花费数千个 token,还会遗漏连接关系。
下面的每条命令都是 $0,无需 API 密钥,且会在一秒内返回结果。一共有六条。选择适合当前任务的命令,运行并根据结果采取行动;不要为了获得更多信息而串联调用工具。大多数任务只需调用一次。
工具
1 · graft ask "<question>" --source:定位并理解(默认选项)
对图谱进行排序检索,自动在文字节点和连接图之间路由,并返回排名靠前的结果及确切的 file:line。
--source会在每个命中结果中内嵌代码,也就是每个定义不超过 8 行的关键代码,因此结果本身就是你需要的代码,无需再读取文件。仅当关键代码过短、无法采取行动时才添加--full。--in <path>会先将检索范围缩小至某个子树,再进行排序;-n N会限制结果数量(默认值为 8)。- 适用场景: 问题涉及概念或定位,例如:“身份验证如何运作”“在哪里处理速率限制”“是什么组装了请求处理管线”。
- 通常一次 ask 就能解答问题。真正包含多个部分的问题,需要针对每个不同的子问题分别调用一次 ask,绝不要只是换一种说法重复询问同一个问题。命中结果很少或相关性较弱时,应改用其他工具(grep / skeleton / callers),不要再次提问。
2 · graft grep "<pattern>":全面查找
在每个已索引文件中进行正则表达式搜索(使用 --fixed 可按字面值搜索),命中结果会按所属符号分组,并按耦合程度排序;它还会报告无法读取的文件。
- 适用场景: 需要查找所有匹配项,例如所有调用点、常量的所有用法或所有提供方。
ask只返回排序靠前的 N 个结果,会漏掉部分实例;grep 不会。一次 grep 可代替大量 ask。 - 搜索较短的符号名称或字面值,不要使用猜测的完整签名:过于具体的正则表达式(
func (s *Server) GenerateHandler)即使代码已被索引,也会返回空结果。如果 grep 没有命中,放宽搜索条件(去掉接收者和签名,只保留名称),然后重试graft grep——不要改用原始grep -rn,它速度较慢且不会排序。 -i不区分大小写;--in <path>将搜索范围限制在某个子树内。仅当文件确实未被 graft 索引(文档、配置文件、刚创建的文件)时,才使用原始grep -rn。
3 · graft skeleton <file>:快速查看文件 API
仅显示单个文件的签名视图(每个函数 / 方法 / 类型及其范围),约需 200 个 token,成本约为读取文件的 1/10。
- 适用场景: 编辑文件或接入该文件之前,需要了解“此文件包含什么 / 可以在这里调用什么”。一个 skeleton 就能完整回答某个文件的问题;不要对同一文件重复运行 skeleton,也不要对
map已列出的每个文件都运行 skeleton。
4 · graft callers <symbol>:确切的连接关系
查询预先计算的调用 / 引用关系,而非进行文本搜索。符号可以是裸名称(Foo)、限定名称(Class.method)或包限定名称(pkg.Fn)。
- 默认
--direction in:查询谁调用 / 引用了该符号;重命名、删除或更改其签名之前应先运行。 --direction out:查询该符号本身调用 / 依赖的内容(旧版callees)。--depth N:按传递关系向外遍历 N 跳,查看完整影响范围(旧版impact);--depth 2通常用于回答“修改它会造成什么影响”。--depth all:查看完整的连通闭包——通过这些连接可到达的所有源文件。进行重构、重命名或任何涉及多个文件的更改之前,请使用此选项:它会显示单文件修改可能遗漏的同级文件和下游文件(平台变体、必须拆分出去的模块)。
5 · graft map:快速了解陌生代码库或区域
按令牌预算生成导览:目录集群、各目录的中心节点,以及全局热点,直接来自连线图。
- 适用场景:刚接触一个代码库,或有人让你介绍“架构”时。单独使用
map就够了:阅读它列出的中心节点卡片;不要接着用skeleton,也不要逐个询问它列出的所有子系统。--max-dirs N可扩大范围。
6 · 生命周期:graft build / graft check
以上每个工具在回答前都会刷新图谱本身,因此这些工具返回的内容始终反映当前代码状态——包括你刚刚做出但尚未提交的编辑。编辑后无需运行 build。
但有一点需要注意:如果你直接对 graft/ 下的 Markdown 执行 grep,这些卡片是图谱的投影,会在每轮结束时重建,而不是每次查询时重建,因此编辑后可能会滞后。以上工具不会滞后——优先使用它们;如果本轮编辑过某个文件,就应将该文件的卡片范围视为过时。
build 用于 LLM 层(--deep 会添加概念图;除非有人要求,否则跳过);check 会在 graft/ 过时的时候失败,适用于 CI。
场景:完成编码任务的最短路径
| 当你…… | 使用 | 调用次数 |
|---|---|---|
| 入门 / “解释一下这个代码库” | graft map,然后阅读列出的中心节点卡片 | 1 |
| 理解某个流程(“X 是如何工作的”) | graft ask "<flow>" --source | 1 |
| 查找应该在哪处修改 | graft ask "where is <behavior>" --source | 1 |
| 编辑一个你已经知道名称的符号 | graft grep "<symbol>",然后在 file:line 处编辑(跳过 ask——你已经知道位置) | 1 |
| 重命名 / 删除 / 更改签名 | 先运行 graft callers <sym> --depth 2 | 1 |
| 重构 / 多文件修改(编辑前) | 运行 graft callers <sym> --depth all——梳理每个关联文件,不要找到第一个就停 | 1 |
| “它依赖什么?” | graft callers <sym> --direction out | 1 |
| 查找某个模式的所有匹配项 | graft grep "<literal>" | 1 |
| “这个文件的 API 是什么?” | graft skeleton <file> | 1 |
| 调试区域 X 中的故障 | graft ask "<symptom>" --source,然后对可疑对象运行 callers | 1–2 |
| 合并前评估差异的风险 | graft callers <changed sym> --depth 2 | 1 / 符号 |
| 在单体代码库的某个代码库中工作 | 在 ask / grep / callers 中添加 --in <scope>/ | 不适用 |
在多代码库工作区中,graft 会公平排序,避免最大的代码库压过其他代码库;每个匹配项都会带有一个 [scope/] 标签,用于标明其子项目。如果你已经知道正在处理哪个项目,可以使用 graft ask "<task>" --in <scope>/ 缩小范围。
尽量减少调用次数
- 节点的
covers:列表已经为每个符号提供了精确的file:line,直接引用即可。这些范围由源代码生成,是权威信息;无需重新打开或重新执行grep来“二次确认”。 - 如果任务已经指出要修改的文件或符号,直接着手处理:运行
graft grep "<symbol>"获取精确的file:line,然后编辑。只有还不知道代码在哪儿时,才使用graft ask——对你已经能明确指出的目标来说,ask的往返就是浪费。 - 相信答案并采取行动。只有第一个工具确实未能满足需求时,才使用第二个工具:例如匹配结果不够理想、范围被截断,或需要穷尽搜索。
- 如果 graft 指出的路径不在磁盘上,说明它的索引领先于当前检出内容(切换了分支,或移动操作尚未拉取)。不要读取缺失的文件——运行
graft grep查找符号当前所在位置,或运行graft build刷新索引。
每轮报告 graft 节省的内容
每个检索工具都会在输出开头显示一行 [graft] tokens saved ≈ N:
这是该调用相较于完整读取其涵盖文件所节省的预估 token 数。
每当你在某一轮中使用了任何 graft 工具,请在回复末尾用一行汇总你所有 graft 调用的这些数字,例如:
🌱 graft saved ~12,400 tokens this turn (3 calls)。没有显示此行的调用(对于指针成本与源内容相当的小文件)不会节省 token,因此请跳过。此数字是每轮的统计值;状态栏显示的是整个会话的累计值。
绝不要将 graft 命令通过 head、tail 或 sed -n 进行管道处理。 每个工具都已设定输出上限,并会说明省略了哪些内容;截取输出会丢掉你需要的命中结果,也会悄悄丢掉状态栏累计值解析所需的节省信息行。
graft 不够用时
- 内容被截断(“+N more lines”):在文件的确切范围处打开文件。
- 节点缺少细节:提出更具体的问题;只有在此之后,才读取确切的
file:line处的源内容,绝不要为了重建 graft 已提供的理解而读取整个文件。 - 你也可以直接在
graft/中使用 grep / ls / cat(纯 Markdown;graft/INDEX.md为节点索引),但上面的工具更快,而且在关键处覆盖更全面,因此请优先使用它们。
连接 graft MCP 服务后,这些工具也会开放使用:
graft_find_code、graft_find_all、graft_file_api、graft_trace_calls(含
direction / depth)、graft_repo_map、graft_check_freshness。使用哪种方式均可;相关指导相同。