关于 graphkeeper
GraphKeeper 是本地命令行工具,可从 Git 历史提取文件共同变更关系,供编码 Agent 查询。它将关系存入可查询图数据,并可选用 graphify 补充调用图信息。
主要功能
- 01统计同一提交中共同修改的文件
- 02限制大型提交以减少噪声
- 03可选合并 graphify 调用图
- 04提供 JSON 查询结果
- 05Node.js 与 Python 实现共享数据格式
适用场景
- 01查找与某文件常一起修改的文件
- 02让编码 Agent 查询代码变更耦合
- 03分析函数的调用者与被调用者
MCP 相关
提供基于 stdio 的 MCP 服务,允许 MCP 客户端构建图并查询共同变更或调用关系。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
GraphKeeper
安装 • 快速入门 • CLI 参考 • 对比 • 常见问题
一个仅在本地运行的 CLI,可从你的 git log 中挖掘哪些文件确实会同时发生变化,然后向 AI 编码 Agent 提供可查询的答案,而不是让它在整个历史记录中执行 grep。

npx graphkeeper-cli build
npx graphkeeper-cli query co-change src/git.ts
Files that historically change alongside "src/git.ts":
1 src/store.ts
1 src/types.ts
1 test/git.test.ts
1 test/store.test.ts
1 test/test-helpers.ts
(这是 GraphKeeper 在项目发展早期针对自身仓库运行后得到的真实输出。随着代码库积累更多提交,共同变更计数也会增加。)
无需服务端、账号或嵌入 API。所有输出都来自你已检出的仓库中的 git log。
安装
GraphKeeper 提供两个相互独立、同等重要的包。选择适合你工具链的包,也可以两个都安装。两者都会从相同的 git log 中挖掘共同变更信号,并共用同一种磁盘上的 .graphkeeper/graph.json 架构,因此使用任一包构建的存储都可以由另一个包读取。
# npm -- JavaScript/TypeScript CLI + library
npm install -g graphkeeper-cli
# or run it once with no install
npx graphkeeper-cli build
# PyPI -- Python CLI + library (genuine port, not a wrapper around the Node binary)
pip install graphkeeper-cli
npm 包需要 Node.js 18 或更高版本;Python 包需要 Python 3.9 或更高版本。两者都要求 git 位于你的 PATH 中。Python 包的 CLI 入口同样是 graphkeeper(例如 graphkeeper build)。请参阅 python/README.md 了解 Python 专属教程,并参阅 CHANGELOG.md 了解各发行包的版本历史。
快速入门
对任意 git 仓库运行,包括本仓库:
git clone https://github.com/RudrenduPaul/GraphKeeper.git
cd GraphKeeper
graphkeeper build
GraphKeeper build complete: /path/to/GraphKeeper
Co-change graph: 4 commit(s) analyzed, 80 file pair(s) found
graphify enrichment: skipped -- graphify was not found on PATH. Install it with
`uv tool install graphifyy` (or `pipx install graphifyy`) for symbol/call-graph
enrichment; GraphKeeper works fine without it, in co-change-only mode.
Wrote /path/to/GraphKeeper/.graphkeeper/graph.json
现在查询:
graphkeeper query co-change src/git.ts
Files that historically change alongside "src/git.ts":
1 src/store.ts
1 src/types.ts
1 test/git.test.ts
1 test/store.test.ts
1 test/test-helpers.ts
如果已安装 graphify(uv tool install graphifyy),graphkeeper build 会自动调用本地无需 API 密钥的 graphify extract --code-only,并将其符号/调用图合并到同一个存储中,从而支持调用图查询:
graphkeeper query calls mineCoChange
mineCoChange() (src/git.ts)
Calls (2):
--> assertIsGitRepo()
--> runGit()
Called by (1):
<-- build()
(这也是实际输出,来自安装 graphify 后针对本仓库运行 graphkeeper build 的结果。)

如果未安装 graphify,同一命令会准确说明为何无法提供答案,而不会崩溃或返回空结果:
Call-graph query for "mineCoChange" is not available.
graphify was not found on PATH. Install it with `uv tool install graphifyy`
(or `pipx install graphifyy`) for symbol/call-graph enrichment; GraphKeeper
works fine without it, in co-change-only mode.
每条命令也都支持用于脚本和 Agent 的 --json:
graphkeeper query co-change src/git.ts --json
{
"file": "src/git.ts",
"results": [
{ "file": "src/store.ts", "count": 1 },
{ "file": "src/types.ts", "count": 1 },
{ "file": "test/git.test.ts", "count": 1 },
{ "file": "test/store.test.ts", "count": 1 },
{ "file": "test/test-helpers.ts", "count": 1 }
]
}

功能
- 挖掘真实的提交历史,而非静态快照。
graphkeeper build会在仓库的完整历史中运行git log --no-merges --name-only,并统计 每个提交中共同变更的每对文件。它不会仅凭目录结构或导入语句来 猜测耦合关系;结论基于代码库随时间的实际编辑情况。 --max-files-per-commit可保护信号质量。 一次涉及 400 个文件的 vendoring 提交或大规模格式重排,否则会污染该提交中的所有文件对。 默认上限为 100 个文件,超过此阈值的提交会被跳过,避免真实的耦合关系 淹没在噪声中。- 可选的调用图增强,绝非必需。 如果
PATH中有 graphify,graphkeeper build会调用其本地graphify extract --code-only --no-cluster,并将生成的符号边/调用边合并到 同一存储中,从而启用graphkeeper query calls。没有 graphify 时, GraphKeeper 仍可在仅使用共同变更数据的模式下运行,并会明确说明这一点, 而不是直接失败。 - 每条命令都有
--json模式。graphkeeper query co-change <file> --json及对应命令会返回机器可读的输出,因此 Agent 的调用代码 可以解析真正的数据结构,而不必从文本中提取信息。 - 两种从零实现,共用同一架构。 npm 包(
src/,TypeScript)和 PyPI 包(python/src/graphkeeper/,Python)是彼此独立的移植版本, 并非一方封装另一方。两者都会读写同一个.graphkeeper/graph.json, 因此可用一个 CLI 构建存储,再用另一个 CLI 查询。 - 所有子进程调用都使用 argv 数组,绝不使用 shell 字符串。 Git
和 graphify 都通过参数列表调用
spawnSync/subprocess.run,因此 被分析仓库中精心构造的提交消息或文件名不会被解释为 shell 语法。
CLI 参考
Usage: graphkeeper [options] [command]
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
build [options] [path] Mine git history for co-change and (if available)
merge in graphify's symbol/call graph
query Query the GraphKeeper store built by
`graphkeeper build`
help [command] display help for command
graphkeeper build [path]
遍历 path(默认值:当前目录),在完整历史中运行 git log --no-merges --name-only,并统计每对文件在同一提交中共同变更的次数。将结果写入
.graphkeeper/graph.json。
| 选项 | 说明 |
|---|---|
--json | 输出机器可读的 JSON,而非人类可读的文本 |
--max-files-per-commit <n> | 跳过变更文件数超过此值的提交(默认值:100),避免一次大规模格式重排或 vendoring 提交淹没真实的共同变更信号 |
--no-graphify | 即使已安装 graphify,也跳过 graphify 增强 |
如果在 PATH 中检测到 graphify,
build 还会在 .graphkeeper/ 内的一个目录中运行 graphify extract <path> --code-only --no-cluster
(graphify 自带的无头、本地、无需 API 密钥的 AST 提取路径),并将其节点/边合并到同一存储中。构建输出始终会明确说明是否包含了此增强;如果没有,也会说明跳过原因。
graphkeeper query co-change <file>
列出历史上与 <file> 同时变更过的文件,并按同时变更的提交数排序。
| 选项 | 说明 |
|---|---|
--json | 输出机器可读的 JSON,而非人类可读的文本 |
--limit <n> | 限制结果数量 |
--graph <path> | 指定 graph.json 的路径(默认值:<cwd>/.graphkeeper/graph.json) |
找到结果时退出码为 0;该文件尚无共同变更数据时为 1;用法或文件系统错误时为 2。
graphkeeper query calls <symbol>
显示 <symbol> 的调用方和被调用方,使用最近一次 build 生成的 graphify calls 边。只有当该次构建包含 graphify 增强时,此查询才有意义;如果没有,则会清楚说明原因,而不会崩溃或静默返回空结果。
| 选项 | 描述 |
|---|---|
--json | 输出机器可读的 JSON,而非人类可读的文本 |
--graph <path> | 指定 graph.json 的路径(默认:<cwd>/.graphkeeper/graph.json) |
找到符号时退出代码为 0,未找到(或增强不可用)时为 1,用法错误或文件系统错误时为 2。
MCP 服务
GraphKeeper 提供 Model Context Protocol 服务,让 AI 编码 Agent(Claude、Cursor 或任何兼容 MCP 的客户端)无需人工手动调用 CLI,即可挖掘共同变更历史并直接查询图。
安装附加组件:
pip install "graphkeeper-cli[mcp]"
将其添加到 MCP 客户端的配置中(对于 Claude Desktop,请编辑 claude_desktop_config.json):
{
"mcpServers": {
"graphkeeper": {
"command": "uvx",
"args": ["--from", "graphkeeper-cli", "graphkeeper-mcp"]
}
}
}
该服务公开一个工具 run,它会通过 npx graphkeeper-cli 调用已发布的 graphkeeper-cli npm 包,并附上给定的子命令和参数以及 --json,然后返回解析后的 JSON 结果:
run(["build", "."])
run(["query", "co-change", "src/git.ts"])
传输方式为 stdio,因此无需托管:MCP 客户端会将该服务作为本地子进程启动。源文件:python/src/graphkeeper/mcp_server.py。
库 API 参考
以下列出了两个包公开的、可实际导入的接口。命令行只是对相同函数的轻量封装。
TypeScript / JavaScript(npm 上的 graphkeeper-cli)
import { build, queryCoChange } from "graphkeeper-cli";
const result = build(".");
console.log(`${result.store.commitsAnalyzed} commit(s) analyzed`);
const coChange = queryCoChange(result.store, "src/git.ts");
for (const row of coChange.results) {
console.log(row.count, row.file);
}
| 导出项 | 签名 |
|---|---|
build | build(targetPath: string, options?: BuildOptions): BuildResult |
queryCoChange | queryCoChange(store: GraphKeeperStore, file: string, options?: { limit?: number }): CoChangeQueryResult |
queryCalls | queryCalls(store: GraphKeeperStore, symbol: string): CallsQueryResult |
findGraphifyNode | findGraphifyNode(nodes: GraphifyNode[], symbol: string): GraphifyNode | null |
normalizeFileArg | normalizeFileArg(store: GraphKeeperStore, file: string): string |
detectGraphify | detectGraphify(): { installed: boolean; version: string | null } |
runGraphifyEnrichment | runGraphifyEnrichment(repoRoot: string): GraphifyEnrichment |
mineCoChange | mineCoChange(repoPath: string, options?: { maxFilesPerCommit?: number }): CoChangeMiningResult |
GitError | Git 相关操作失败时抛出的错误子类 |
resolveRepoRoot | resolveRepoRoot(targetPath: string): string |
readStore | readStore(repoRoot: string, overridePath?: string): GraphKeeperStore |
writeStore | writeStore(repoRoot: string, store: GraphKeeperStore): string |
PathSafetyError | 解析后的路径超出仓库根目录时抛出的错误子类 |
graphFilePath | graphFilePath(repoRoot: string): string |
类型(GraphKeeperStore、CoChangeEdge、GraphifyNode、GraphifyEdge、GraphifyRawGraph、GraphifyEnrichment、BuildOptions、BuildResult、CoChangeQueryResult、CallsQueryResult)以 .d.ts 声明文件的形式随编译产物一同发布;目前尚无单独生成的文档网站。
Python(PyPI 上的 graphkeeper-cli)
from graphkeeper import build, query_co_change
result = build(".")
print(f"{result.store.commits_analyzed} commit(s) analyzed")
co_change = query_co_change(result.store, "src/git.py")
for row in co_change.results:
print(row.count, row.file)
graphkeeper.__all__ 导出:build、query_co_change、query_calls、
find_graphify_node、normalize_file_arg、detect_graphify、
run_graphify_enrichment、mine_co_change、unquote_git_path、GitError、
resolve_repo_root、read_store、write_store、graph_file_path、
PathSafetyError,以及 GraphKeeperStore、CoChangeEdge、
GraphifyNode、GraphifyEdge、GraphifyEnrichment、BuildOptions、
BuildResult、CoChangeQueryResult、CoChangeResultRow 和
CallsQueryResult 数据类。与上文 TypeScript 导出表中的名称相同,
采用 snake_case。目前还没有单独生成的文档网站;python/src/graphkeeper/__init__.py 顶部的
docstring 涵盖了与本节相同的内容。
对比
| GraphKeeper | graphify | GitNexus | Greptile | Augment Code | |
|---|---|---|---|---|---|
| 功能 | 从 git log 中挖掘文件级别的协同变更 | 通过 tree-sitter 提取符号/导入/调用图,并提供 AI 助手技能 | CLI + MCP 工具(原生、本地),可选的免安装浏览器/WASM 模式;进行结构分析和调用流程分析 | 托管式 AI 代码审查,使用图索引代码库 | 托管式 AI 编码平台,具备实时代码依赖图(Context Engine),并提供提交历史和文档索引 |
| 仅限本地? | 是,始终如此 | 是,代码解析仅限本地(如果配置了后端,文档/媒体索引会调用后端) | CLI/MCP 路径是;浏览器模式在客户端运行,但需要托管的 Web 应用 | 默认不是;仅 Enterprise 方案提供可自托管/隔离网络部署 | 否;托管在云端,未公开说明提供自托管选项 |
| 免费/开源? | 是,Apache-2.0 | 是,Apache-2.0 | 否,PolyForm Noncommercial 1.0.0 | 免费 Starter 方案(1 个席位,每月 50 个额度),非开源 | 未公开说明是否免费;采用面向企业销售的定价 |
| 协同变更挖掘? | 是,这是该工具的全部功能 | 否 | 否 | 否 | 否 |
| GraphKeeper 与之的关系 | -- | graphify 已安装时,GraphKeeper 会使用 graphify 本地 extract 的输出丰富自身存储;不会重新实现其功能 | 交付模式不同(CLI + MCP + 可选浏览器应用,而本项目是纯 CLI);不进行协同变更挖掘 | 面向团队/PR 审查的托管产品,不是本地单 Agent 工具 | 企业级编码助手平台,不是独立的本地 CLI |
(凡是竞争产品未公开具体数字的地方,均使用“未公开说明”,而不作猜测。数据已根据各项目自己的 README、定价页面或公开网站核实,截至 2026 年 8 月。)
GraphKeeper 是什么?它为何存在?
GraphKeeper 是一个本地 CLI 和库,以 graphkeeper-cli 发布到 npm 和 PyPI。它会从 git log 中挖掘文件级共同变更数据:哪些文件历来会与指定文件在同一个提交中一起编辑。它将数据写入单个 JSON 文件 .graphkeeper/graph.json,并在不进行网络调用的情况下针对该文件回答查询。
它的存在是因为,独自处理不熟悉的代码库时,AI 编码 Agent 无法快速回答“我改动这个文件时,通常还会改动什么?”,除非每次被问到时都自行运行 git log --name-only 扫描,并手动统计结果。GraphKeeper 会预先计算这个答案,并提供查询方式,其中包括脚本或 Agent 可直接解析的 --json 格式。
GraphKeeper 不会重新实现符号或调用图提取功能。
graphify(在 GitHub 上有 100K+ 星标,采用 Apache-2.0 许可证,通过 pip install graphifyy 安装)已支持 36 种 tree-sitter 语法,并作为斜杠命令技能提供给 Claude Code、Cursor、Codex、Gemini CLI、GitHub Copilot 及其他 15+ 款助手(总计 20+ 款)。当 graphify 位于 PATH 中时,graphkeeper build 会调用本地的 graphify extract --code-only --no-cluster,并将结果合并到同一存储中,从而启用 graphkeeper query calls。即使没有 graphify,GraphKeeper 仍可在仅支持共同变更的模式下工作,并会直接说明这一点,而不会报错。
工作原理
graphkeeper build会通过安全的 argv 数组子进程调用(绝不使用 shell 字符串),在整个仓库历史中运行git log --no-merges --name-only。- 对于每个提交,它都会统计每一对共同变更的文件。如果某个提交涉及的文件数超过
--max-files-per-commit(默认值为 100),就会跳过该提交,以免单个引入供应商代码或大规模重新格式化的提交淹没真实信号。 - 如果在
PATH中检测到graphify,GraphKeeper 还会将 graphify 自带的本地、无需 LLM、无需 API 密钥的提取模式graphify extract <path> --code-only --no-cluster运行到.graphkeeper/内的一个目录中,然后将其nodes/edges合并到同一存储中。 - 合并后的结果会一次性原子写入
.graphkeeper/graph.json。 graphkeeper query会读取该文件,并据此回答共同变更或调用图相关问题。绝不进行网络调用。
安全性
- 每次调用
git和graphify时,都会使用直接传递给操作系统的 argv 数组(TypeScript 中使用spawnSync,Python 中使用带列表参数的subprocess.run),绝不使用 shell 字符串,因此提交消息、文件名或仓库路径不会被解释为 shell 语法。 - 每次写入前,都会检查
.graphkeeper/输出路径是否位于解析后的仓库根目录内(包括通过fs.realpathSync检查符号链接),因此恶意构造的仓库无法将 GraphKeeper 的写入重定向到.graphkeeper/之外。 - 无遥测、无网络调用、无机密信息。GraphKeeper 唯一读取的文件是
git log输出,以及可选的 graphify 自带graph.json;唯一写入的文件是.graphkeeper/graph.json。
漏洞报告流程请参阅 SECURITY.md。
常见问题
GraphKeeper 是通用的代码库知识图谱索引器吗?
它本身不是。graphkeeper build 会从 git log 中挖掘文件级共同变更数据,并将这些边写入 .graphkeeper/graph.json。只有在安装了 graphify 并于同一次构建中将其合并后,该文件才会同时包含符号图和调用图。如果 PATH 中没有 graphify,存储中就只有共同变更数据,graphkeeper query calls 也会直接说明这一点,而不是返回空结果。
与 grep 或 git log 相比,GraphKeeper 实际能为 Agent 提供什么?
预先计算、可查询的“这里哪些文件会一起变更”的答案,
这样 Agent 就不必每次遇到问题时都运行自己的 git log --name-only 扫描,
再手动统计结果。每条命令都支持 --json,
因此答案可供脚本使用,而不必由人来阅读并重新输入。
如何安装?它能在 Windows 上运行吗?
npm install -g graphkeeper-cli(Node.js 18+)或 pip install graphkeeper-cli(Python 3.9+);两者都需要 git 位于 PATH 中。两个
软件包都不包含特定于操作系统的分支或原生绑定,且 PyPI 上的条目被归类为
Operating System :: OS Independent,因此只要有 git 和受支持的
Node 或 Python 运行时,就能在 Windows、macOS 和 Linux 上以相同方式运行。
这与它链接用于丰富信息的工具 graphify 有何不同?
它们回答的是不同的问题。graphify 通过 tree-sitter 直接从源代码中提取符号、导入项和
调用图,支持 36 种语言;GraphKeeper 则从提交历史中挖掘哪些文件过去曾一起
编辑,这是 graphify 没有理由计算的信号。若 graphify 存在于 PATH 中,
GraphKeeper 会调用 graphify 自带的本地 extract 命令并合并结果,而不是从头
重新实现 tree-sitter 解析。两者都不能取代对方;请参阅上方的比较表,了解
GitNexus、Greptile 和 Augment Code 与两者的区别。
什么情况会导致 GraphKeeper 出错或返回空结果?
有两种真实情况,都有文档说明,且都不会导致崩溃:浅层 git 克隆(GitHub Actions
默认的 fetch-depth: 1)没有可供挖掘的历史记录,因此 build 会报告
0 commit(s) analyzed 并写入空的共同变更图;需要完整历史记录(fetch-depth: 0)。
另外,只有在最近一次 build 运行时 PATH 中存在 graphify,query calls
才会返回结果;如果不存在,命令会明确说明这一点
(graphify was not found on PATH...),而不会假装该符号不存在。
对我不完全信任的仓库运行它安全吗?
每次 git 和 graphify 调用都会通过 argv 数组直接传给操作系统
(spawnSync/Python 的 subprocess.run 使用列表,绝不使用
shell 字符串),因此文件名或提交消息不会被解释为 shell 语法。每次写入
.graphkeeper/ 前,都会检查路径是否位于解析后的仓库根目录内,其中也包括符号链接。
该工具不会进行任何网络调用,因此你指定的仓库中的任何内容都不会离开你的计算机。
npm CLI 只是 Python CLI 的封装,还是反过来?
都不是。它们是两个独立、从头实现的版本(TypeScript 版位于 src/,
Python 版位于 python/src/graphkeeper/),只是恰好采用相同的
.graphkeeper/graph.json 架构、子命令、标志和退出代码。一个版本构建的存储
可以由另一个版本读取。Python 端口自己的测试套件(从 TypeScript vitest
套件移植而来)包含 78 个测试,针对真实的子进程 CLI 调用运行,而不是模拟另一种
语言的输出。截至目前,在全新安装环境中两个套件都通过:TypeScript 端为 78/78
(npm test),Python 端为 78/78(pytest)。
它采用什么许可证?可以用于商业用途吗?
npm 和 PyPI 软件包均采用 Apache License 2.0,没有双重许可,也没有单独的商业版。 该许可证允许商业使用、修改和再分发,但需注明出处并遵守标准的 Apache 专利授权条款。 完整文本请参阅 LICENSE。
贡献
欢迎提交问题和 PR。要从源代码构建 TypeScript 软件包:
git clone https://github.com/RudrenduPaul/GraphKeeper.git
cd GraphKeeper
npm install
npm run build
npm test
npm run lint
npm run typecheck
Python 软件包请参阅 python/README.md。涵盖两个代码库的完整
贡献指南见 CONTRIBUTING.md。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。