graphify 钩子集成实战:git post-commit 自动重建知识图谱与 Claude Code 原生接入
本文基于 graphify 的参考文档 hooks.md,讲解 graphify 的两类"免值守"集成方式:通过 graphify hook install 安装 git post-commit/post-checkout 钩子,让每次提交和切分支后自动增量重建知识图谱;以及通过 graphify claude install 把 graphify 规则写进项目 CLAUDE.md 并注册 Claude Code 的 PreToolUse 钩子,让 Claude Code 会话在回答代码库问题前自动查图、在改动代码后自动重建。读完本文,你可以掌握钩子的安装/卸载/状态检查全流程、钩子内部的重建机制、全部相关环境变量与配置项,以及 Claude 原生集成的写入与移除细节,并能从源码层面理解每一步的实际行为。
一、两类集成机制的定位
graphify 的核心产物是 graphify-out/ 目录下的 graph.json(可查询知识图谱)与 GRAPH_REPORT.md(架构报告)。默认情况下,图需要手动构建和更新。参考文档给出的两条"自动化通道"分别解决两个问题:
- git 钩子(
graphify hook install):解决"图过期"问题。每次git commit后自动检测变更的代码文件、重跑本地 AST 抽取并重构建图,无需任何后台常驻进程,每次提交只触发一次,编辑器无关; - 原生 CLAUDE.md 集成(
graphify claude install):解决"Claude 不知道图的存在"问题。一次性把## graphify规则段写入本地CLAUDE.md,让 Claude Code 在之后的每个会话里都默认"先查图再回答",无需每次手动执行/graphify。
两者的命令入口在 CLI 入口 中注册,帮助文本明确列出了 hook install / hook uninstall / hook status 与 claude install / claude uninstall 子命令。
二、git 提交钩子:自动增量重建
2.1 安装、卸载与状态检查
参考文档给出的三个命令覆盖了钩子的完整生命周期:
graphify hook install # install
graphify hook uninstall # remove
graphify hook status # check
这三个子命令最终委托给 hooks.py 中的 install / uninstall / status 函数(见 cli.py 的 hook 分支)。从源码结构看,实际安装动作比文档描述的"装一个 post-commit 钩子"更完整:
- post-commit 钩子(标记块
# graphify-hook-start…# graphify-hook-end,见 hooks.py#L8-L9):每次提交后增量重建; - post-checkout 钩子(标记块
# graphify-checkout-hook-start):仅在切换分支(第三个参数为1)且 HEAD 实际变化时触发全量重建; - graph.json 合并驱动:通过
git config注册merge.graphify.driver,并在.gitattributes追加graphify-out/graph.json merge=graphify,让被跟踪的graph.json在合并时走 union merge 而非产生冲突(见 _register_merge_driver)。
安装策略上,_install_hook(hooks.py#L540-L568)实现了参考文档中"If a post-commit hook already exists, graphify appends to it rather than replacing it"的行为:
- 目标钩子文件不存在:写入完整脚本并
chmod 0o755; - 文件存在但没有 graphify 标记:把 graphify 块追加到已有内容之后(例如已有 husky 或其他工具装的钩子不受影响);
- 文件存在且已有 graphify 标记块:用新脚本原位替换旧块,升级安装时自动刷新脚本内容。
卸载时 _uninstall_hook 用 start/end 标记做正则切除;若切除后只剩 shebang 行则直接删除整个钩子文件,其余第三方内容原样保留。
钩子目录解析尊重 core.hooksPath(例如 Husky 场景):_hooks_dir 通过 git rev-parse --git-path hooks 让 git 自己解析路径,并在解析结果指向 .husky/_(Husky 9 的自动生成目录)时回退到用户可编辑的 .husky/ 父目录(见 _user_hooks_dir)。
2.2 一次 commit 之后发生了什么
参考文档给出的流程描述是:"检测到哪些代码文件变了(git diff HEAD~1),对这些文件重跑 AST 抽取,重建 graph.json 和 GRAPH_REPORT.md;文档/图片变更被钩子忽略,需要手动跑 /graphify --update"。对照生成的钩子脚本 _HOOK_SCRIPT,实际执行链更细:
- 确定性固定:
export PYTHONHASHSEED=0,消除 networkx louvain 社区划分因字符串哈希随机化导致的运行间抖动,保证graphify-out/可复现; - Windows/MSYS 保护:在
WINDIR或MSYSTEM环境下默认GRAPHIFY_MAX_WORKERS=1(串行重建),规避 GUI 客户端/Agent shell 继承的脆弱管道句柄;显式设置的GRAPHIFY_MAX_WORKERS仍然优先; - 交互态跳过:处于 rebase(
rebase-merge/rebase-apply)、merge(MERGE_HEAD)或 cherry-pick(CHERRY_PICK_HEAD)时直接exit 0,避免未暂存改动阻塞--continue; - worktree 守卫:
git worktree add创建的链接 worktree 中git-dir != git-common-dir,此时直接跳过,防止从 worktree 写出"脏"的增量图并与 CI 的git clean竞争(_WORKTREE_GUARD); - 变更收集:
CHANGED=$(git diff --name-only HEAD~1 HEAD ...),即文档所述的git diff HEAD~1;若本次提交只改了graphify-out/下的产物(图输出被纳入版本跟踪的常见情形),直接退出,避免"重建产物又触发重建"的循环; - Python 解释器探测:钩子内嵌了一段四重探测逻辑(_PYTHON_DETECT),依次尝试:安装时钉死的
sys.executable绝对路径(__PINNED_PYTHON__占位符在安装时被替换)→graphify-out/.graphify_python记录文件 → PATH 上的graphifylauncher(含 shebang 解析、WindowsScripts/布局)→uv tool环境目录扫描 → 最后才回退python3/python。每个候选都通过importlib.util.find_spec('graphify')轻量探测(只定位不导入),全部失败时打印提示并exit 0——钩子永远不让 commit 失败; - 后台分离重建:钩子不直接跑重建,而是通过 _LAUNCHER_TEMPLATE 用 Python 自身完成"detached launch":POSIX 用
start_new_session,Windows 用CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB。这一步替换了早期的nohup ... &方案——Git for Windows 的 MSYS shell 没有nohup/setsid,旧方案会让重建静默不执行而 git 仍返回 0(见 graphify/hooks.py#L240-L256 的注释)。结果是git commit立即返回,重建日志追加写入~/.cache/graphify-rebuild.log。
后台子进程执行的核心逻辑是 _REBUILD_BODY_COMMIT:读取环境变量 GRAPHIFY_CHANGED 得到变更文件列表,调用 watch.py 的 _rebuild_code 完成"仅重抽变更文件 + 保留旧节点 + 聚类 + 报告"的增量重建,随后以 best-effort 方式(失败绝不影响钩子)调用 reflect 刷新工作记忆经验文档。
_rebuild_code 的 docstring(watch.py#L1284-L1306)还揭示了几个值得注意的机制:
- 传入
changed_paths时为增量模式:只重抽这些文件,未变更文件的节点从现有图中保留,已删除路径从保留集剔除;changed_paths=None(post-checkout 用的正是这种形式)时为全量重抽; force=True(由GRAPHIFY_FORCE触发)会绕过to_json的节点数安全检查,让"合理地删了大量代码"的重建可以合法地写出更小的图;- 重建带 per-repo 非阻塞
flock:多仓库同时提交、或 commit+checkout 背靠背触发时不会堆叠,抢不到锁的增量变更会被排队,锁持有者重建完成后合并排队的变更集再补一轮重建。
2.3 post-checkout:切分支也自动重建
参考文档只讲了 commit 钩子,但源码里同时安装的 post-checkout 钩子(_CHECKOUT_SCRIPT)值得单独说明:
- 只在
BRANCH_SWITCH=1时运行,git checkout <file>这类文件级检出不会触发; PREV_HEAD与NEW_HEAD相同(如git checkout -b无起点)的 no-op 切换直接退出;- 要求
graphify-out/已存在——即项目至少构建过一次图,否则跳过; - 同样遵守
GRAPHIFY_SKIP_HOOK=1、rebase/merge/cherry-pick 跳过与 worktree 守卫; - 走全量重建路径(不传
changed_paths),因为切分支可能任意改动大量文件。
2.4 环境变量与项目配置一览
结合钩子脚本与 _load_graphifyrc、_apply_resource_limits,可以整理出钩子链路的全部可配置项:
| 变量 / 配置 | 默认值 | 作用 |
|---|---|---|
GRAPHIFY_SKIP_HOOK |
0 |
设为 1 时 post-commit 与 post-checkout 均跳过重建(例如 CI 上不想跑) |
GRAPHIFY_REBUILD_TIMEOUT |
600 秒 |
重建超时,POSIX 用 SIGALRM,无 SIGALRM 的平台用守护线程看门狗 |
GRAPHIFY_FORCE |
未设置 | 1/true/yes 时强制覆盖即使图变小 |
GRAPHIFY_OUT |
graphify-out |
输出目录名;钩子还会读 <out>/.graphify_root 恢复真实仓库根 |
GRAPHIFY_REBUILD_LOG |
~/.cache/graphify-rebuild.log |
后台重建的输出日志 |
GRAPHIFY_MAX_WORKERS |
Windows/MSYS 下默认 1,其余为 CPU 核数 |
AST 抽取子进程数 |
GRAPHIFY_REBUILD_MEMORY_LIMIT_MB |
未设置(不限制) | 用 RLIMIT_AS(Linux)/RLIMIT_DATA(macOS)限制重建内存;钩子还会先 os.nice(10) 降低优先级 |
GRAPHIFY_VIZ_NODE_LIMIT |
未设置 | 可视化节点上限;可由项目 .graphifyrc 以 viz_node_limit=<非负整数> 持久化,且以 ${GRAPHIFY_VIZ_NODE_LIMIT:-<n>} 形式烘焙进钩子,单次运行 git commit 时的显式赋值仍优先 |
PYTHONHASHSEED |
钩子内固定为 0 |
保证聚类结果可复现 |
.graphifyrc 每行必须是 key=value 格式,status 命令会对已安装钩子里烘焙的 limit 与当前 .graphifyrc 值做比对,不一致时报告 "installed (out of date: ...)",提示重跑 graphify hook install。
测试侧,tests/test_hooks.py、tests/test_hook_guard.py 与 tests/test_hook_out_of_project_paths.py 覆盖了钩子脚本生成、安装/卸载与越界路径拦截等行为。
三、原生 CLAUDE.md 集成
3.1 一次性接入
参考文档说明:对每个项目运行一次
graphify claude install
即让 graphify 在 Claude Code 会话中"always-on";对应实现是 install.py 的 claude_install。文档说它"向本地 CLAUDE.md 写入一个 ## graphify 小节",源码确认了这一点:目标文件是项目根的 CLAUDE.md((project_dir or Path(".")) / "CLAUDE.md"),使用 _replace_or_append_section 基于标记做"替换已有小节或追加",因此幂等——重复运行只会打印 "graphify already configured ... (no change)"。
但实现里还有一步文档未展开的动作:claude_install 末尾总是重新安装 Claude Code 的 PreToolUse 钩子(_install_claude_hook),把旧的钩子载荷替换为当前版本(升级场景)。它会合并进 .claude/settings.json 的 hooks.PreToolUse 数组,matcher 覆盖 Bash|Grep 搜索与 Read|Glob 读取两类工具调用(安装输出会打印 "PreToolUse hooks registered (Bash|Grep search + Read/Glob)")。项目级安装(project=True)会写入裸命令形式,因为此时 settings.json 会被提交进仓库,不应携带安装机器的绝对路径。
3.2 写入的 always-on 规则内容
写入 CLAUDE.md 的小节内容来自 always-on 片段 claude-md.md,其规则原文是:
- 项目存在
graphify-out/知识图谱(god nodes、社区结构、跨文件关系); - 回答代码库问题时,若
graphify-out/graph.json存在,先运行graphify query "<question>";关系问题用graphify path "<A>" "<B>",聚焦概念用graphify explain "<concept>"——这些命令返回的是作用域受限的子图,通常远小于GRAPH_REPORT.md或原始 grep 输出; - 若存在
graphify-out/wiki/index.md,宽泛导航优先用它而不是直接翻源码; - 仅在宽泛架构评审或 query/path/explain 上下文不足时才读
GRAPH_REPORT.md; - 修改代码后运行
graphify update .保持图最新(纯 AST,无 API 成本)。
安装完成后的终端提示也印证了这一行为:"Claude Code will now check the knowledge graph before answering codebase questions and rebuild it after code changes."。若以 strict 模式安装,还会额外启用:每个会话第一次裸读文件会被拦截,直到先执行一次 graphify query(可用 GRAPHIFY_HOOK_STRICT=0 关闭)。
3.3 移除集成
graphify claude uninstall # remove the section
对应实现 claude_uninstall 比"删掉小节"做得更彻底,它覆盖用户可能把配置挪到本地文件的几种变体:
- 从
CLAUDE.md、CLAUDE.local.md、.claude/CLAUDE.local.md三个位置精确切除## graphify小节(按标记匹配,不会误伤用户自建的### graphify之类标题);切除后文件若为空则直接删除该文件; - 从
.claude/settings.json与.claude/settings.local.json两个文件里移除 graphify 的 PreToolUse 钩子项(用户可能把钩子挪到 local 文件避免提交进共享仓库); - 按作用域规则清理对应平台的 skill 树(项目级安装只删项目级,避免误删全局技能)。
四、要点小结与验证路径
- 钩子不阻塞、不失败、可复现:提交后立即返回(Python 自研 detached launch)、解释器找不到时
exit 0、PYTHONHASHSEED=0固定聚类随机性——这三点共同解释了"图为什么不会挡住你提交,且每次重建结果稳定"; - 增量是默认,全量是兜底:commit 走
changed_paths增量重建并带锁队列合并;checkout 切分支走全量重建; - 第三方内容零破坏:追加式安装、标记块切除式卸载、
.gitattributes保留其他条目,都可用 hooks.py 中的_install_hook/_uninstall_hook/_register_merge_driver直接验证; - Claude 集成的实质:一条幂等的
## graphify规则段(先查图、改后重建)+ 一组 PreToolUse 钩子,移除时按项目/本地/全局三种作用域分别清理。
参考文档 hooks.md 面向的是 claw(AGENTS.md 系)平台的 skill 引用;由于 git 钩子与 CLAUDE.md 集成是平台无关/平台专用的独立命令,上述行为在 Claude Code 之外同样适用,graphify claude install/uninstall 则专用于 Claude Code。实际调试时,最直接的两个观察点是 ~/.cache/graphify-rebuild.log(每次后台重建的输出)与 git hooks 目录下的 post-commit/post-checkout 文件本身(标记块之间就是 graphify 注入的完整脚本)。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00