缘起
CodeGraph 对代码理解很有用,但它依赖项目本地索引。如果每次进入项目后才想起手动初始化,既容易遗漏,也会把“环境准备”混进正常对话。更糟的是,初始化命令的输出可能进入上下文,干扰模型判断
我的目标很简单:Claude Code 会话开始时自动准备 CodeGraph,但这件事不应该打扰人,也不应该打扰模型
方案
把初始化放进 Claude Code 的全局 SessionStart hook。这样每次启动会话、清空上下文、压缩上下文后,Claude 都会先静默尝试一次 codegraph init。
全局配置只需要关注 hook 片段
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "python3 /home/xxx/.claude/hooks/codegraph-init.py",
"timeout": 10
}
]
},
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "python3 /home/xxx/.claude/hooks/codegraph-init.py",
"timeout": 10
}
]
},
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "python3 /home/xxx/.claude/hooks/codegraph-init.py",
"timeout": 10
}
]
}
]
}
}
脚本
脚本只做一件事:判断当前目录是否是项目目录,如果有 .git,就在该目录运行 codegraph init
#!/usr/bin/env python3
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
from typing import Any
def read_hook_input() -> dict[str, Any]:
try:
value = json.loads(sys.stdin.read())
except (json.JSONDecodeError, OSError):
return {}
return value if isinstance(value, dict) else {}
def resolve_project_dir(hook_input: dict[str, Any]) -> Path:
env_value = os.environ.get("CLAUDE_PROJECT_DIR")
if env_value:
return Path(env_value).resolve()
cwd = hook_input.get("cwd")
if isinstance(cwd, str) and cwd:
return Path(cwd).resolve()
return Path.cwd().resolve()
def run_codegraph_init(project_dir: Path) -> None:
if not (project_dir / ".git").exists():
return
try:
subprocess.run(
["codegraph", "init"],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=45,
cwd=str(project_dir),
check=False,
)
except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError, OSError):
pass
def main() -> None:
hook_input = read_hook_input()
project_dir = resolve_project_dir(hook_input)
run_codegraph_init(project_dir)
if __name__ == "__main__":
main()
全局 hook 会在很多地方触发:home 目录、临时目录、配置目录、非代码目录。如果它过于主动,就可能在不该初始化的地方创建.codegraph
所以这里选择保守策略:只有明确站在一个 Git 项目目录时才初始化