关于 github-twin
github-twin 为编码 Agent 索引 GitHub 提交、代码和评审记录,支持个人或组织范围的检索。混合搜索结合 BM25 与向量检索,索引在本地运行,嵌入和 LLM 后端可配置。
主要功能
- 01索引提交、代码和评审记录
- 02结合 BM25 与向量的混合搜索
- 03支持 AST 的代码检索
- 04按仓库或作者筛选结果
- 05增量同步 GitHub 数据
- 06通过 MCP 提供检索工具
适用场景
- 01为新 diff 查找过往评审意见
- 02编写代码时查找个人代码示例
- 03搜索组织代码和评审历史
- 04为编码任务检索相关规则
MCP 相关
stdio MCP 服务向客户端提供检索、评审结果预测、模式摘要和同步工具。检索使用本地 SQLite 索引。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx github-twinGITHUB_TOKEN密钥GitHub personal access token. Optional: github-twin can also pick the token up from `gh auth token` or from its own OAuth device-flow login (`gt auth login`).ANTHROPIC_API_KEY密钥Optional. Enables the Claude backend for `gt summarize`, `gt distill`, and `gt eval`. Defaults to local Ollama when unset.GEMINI_API_KEY密钥Optional. Enables the Gemini backend for embedding and the LLM seam. Vertex AI ADC via `GT_GEMINI_PROJECT` is also supported.GT_PATHS__DATA_DIROptional. Override the on-disk data directory holding the SQLite index, embeddings, and cached GitHub responses. Defaults to `$XDG_DATA_HOME/github-twin`.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
github-twin
六个月前,你审查过一项权限检查。Claude 不记得了。 github-twin 会记得——它会为你的提交和审查评论建立索引,并在 Agent 按照你的风格编写或审查新代码时,将相关内容作为检索结果呈现出来。
现在就通过 Claude Code 试用——将以下内容放入 ~/.claude.json 并重新加载:
{
"mcpServers": {
"github-twin": { "command": "uvx", "args": ["github-twin", "serve"] }
}
}
你的代码会留在本机。 嵌入在本地计算 (Ollama 或 sentence-transformers);只有 LLM 接口(
gt summarize、gt distill、gt eval)会选择性地调用托管服务商,而且也可以 切换为本地 Ollama。gemini嵌入器是唯一的例外——仅限主动选择启用。
基于你的 GitHub 历史记录构建的个人 RAG,可作为 stdio 服务提供给 Claude Code(或任何 MCP 客户端)。两种范围,一套代码库:
- 用户模式——为你自己的提交和审查评论建立索引。当 Agent 编写或审查新代码时,会呈现你过去的代码作为风格示例,并将你过去的评论作为审查提示。
- 组织模式——为整个 GitHub 组织中所有成员的 HEAD 文件、提交和 PR 审查建立索引。查询可按仓库、语言或审查者登录名限定范围。
检索采用混合方式(BM25 + 通过 RRF 进行向量检索),使用 tree-sitter 感知 AST,支持 python/scala/javascript/typescript/go/rust,并在嵌入时通过每个分块的标头和可选的 LLM 生成摘要,添加上下文信息。
安装
最快的方式是使用 uvx——无需管理虚拟环境,每个工具都彼此隔离:
# One-shot
uvx github-twin --help
# Pinned version
uvx [email protected] --help
# With sentence-transformers for the alt embedder
uvx --with 'github-twin[st]' github-twin --help
如果你更喜欢在项目本地安装:
uv add github-twin # or: pip install github-twin
gt --help
gt 和 github-twin 是同一个 Typer 应用——根据你的使用习惯任选其一。
身份验证
选择最省事的方式——github-twin 会按以下顺序尝试:
- OAuth 设备授权流程(无需安装
gh):
令牌会保存到操作系统密钥环(macOS Keychain / Linux Secret Service / Windows Credential Manager);若不可用,则保存到数据目录下权限为 0600 的文件中。uvx github-twin auth login # opens browser, persists token uvx github-twin auth status # show which source is active - 已有的
ghCLI:如果你已经运行过gh auth login,gt会通过gh auth token获取令牌——无需额外操作。 GITHUB_TOKEN环境变量:经典 PAT 也可使用;适用于 CI / 无头环境 / docker。所需范围:repo、read:org、user:email。
接入 Claude Code
MCP 服务通过 github-twin serve(或 gt serve)使用 stdio 运行。
在将要托管该服务的机器上运行一次 uvx github-twin auth login。
选项 A——通过 Claude Code 插件市场(最省事):
/plugin marketplace add ChristopherDavenport/christopherdavenport-marketplace
/plugin install github-twin@christopherdavenport
这会自动注册 MCP 服务条目;请在环境中(或在 ~/.claude.json 中该服务的
env 块里)设置 GT_PATHS__DATA_DIR,指向数据库目录。
选项 B——手动配置:向 ~/.claude.json(或
你的 mcp_servers.json)添加条目:
{
"mcpServers": {
"github-twin": {
"command": "uvx",
"args": ["github-twin", "serve"],
"env": {
"GT_PATHS__DATA_DIR": "/path/to/your/github-twin-data"
}
}
}
}
如果你不想持久保存令牌,而是希望在调用时直接提供(CI、
临时容器),请在该 env 块中添加 "GITHUB_TOKEN": "ghp_...";它会作为优先级最低的备用令牌。
重新启动 Claude Code;届时即可使用 find_*、predict_review_outcome、
summarize_review_patterns 和 sync 工具。
快速入门
选择一个目录来存放 SQLite 数据库、配置和摄取缓存 — 每个数据目录中的所有内容都位于这个根目录下:
export GT_PATHS__DATA_DIR=~/github-twin-data
uvx github-twin auth login # one-time OAuth (or set GITHUB_TOKEN)
# user mode (your own GitHub history)
uvx github-twin init # discover identity via /user
uvx github-twin sync # ingest + summarize + embed
uvx github-twin serve # MCP server over stdio
# layer an org into the SAME DB
uvx github-twin init --kind org --org http4s
uvx github-twin sync
# OR keep the org in its own DB by switching data dirs
GT_PATHS__DATA_DIR=~/twin-http4s \
uvx github-twin init --kind org --org http4s
GT_PATHS__DATA_DIR=~/twin-http4s uvx github-twin sync
后续运行时,gt sync 会增量同步。
config.toml 与数据库位于同一目录,即 <data_dir>/config.toml,并在首次调用 gt init --embed-backend ... 时创建。若未设置 GT_PATHS__DATA_DIR,默认 <data_dir> 为 $XDG_DATA_HOME/github-twin(或 ~/.local/share/github-twin)。
LLM 提供方矩阵
检索接口(find_*、predict_review_outcome)始终在 SQLite 索引上本地运行 — 不会调用 API。只有在以下三个场景中才会调用 LLM:
gt distill— 将审查评论/提交聚类为规则。gt summarize— 生成每个分块的自然语言摘要,用作嵌入时的前缀。gt eval reviews/eval predictions— 对留出数据进行 RAG 与基线评分。
每个操作都会按 Claude → Gemini → Ollama 的优先顺序选择后端(使用已设置 API 密钥的提供方),也可以显式指定后端。
| 提供方 | 环境变量 | 用途 |
|---|---|---|
| Anthropic(Claude) | ANTHROPIC_API_KEY | 蒸馏/摘要/评估 LLM。质量最佳。 |
| Google(Gemini,API 密钥) | GEMINI_API_KEY 或 GOOGLE_API_KEY | 蒸馏/摘要/评估 LLM。免费层额度充足。 |
| Google(Gemini,Vertex/ADC) | GT_GEMINI_PROJECT(+ 可选的 GT_GEMINI_LOCATION,默认为 us-central1) | 使用相同后端,但通过 gcloud auth application-default login 进行身份验证 — shell 中无需密钥。如果两者都已设置,则优先使用 API 密钥。 |
| Ollama(本地) | OLLAMA_HOST(默认为 http://127.0.0.1:11434) | 蒸馏/摘要/评估 LLM。完全离线。 |
Vertex/ADC 路径需要在项目中启用 aiplatform.googleapis.com API,且即使是“免费”的 Gemini 模型也需要付费 — AI Studio 免费层不适用于 Vertex。项目 ID 不属于机密;凭据本身存放在 ~/.config/gcloud/application_default_credentials.json,并由 gcloud 刷新。
嵌入器后端
嵌入器后端与 LLM 后端彼此独立。请选择一个:
- 默认 — Ollama(
nomic-embed-text,768 维,每个分块约 50 毫秒)。 需要运行中的 Ollama 守护进程。零成本,完全本地运行。 - 替代方案 — sentence-transformers(
uv add 'github-twin[st]', 会拉取torch)。当无法使用 Ollama 守护进程,或你想使用特定的 HuggingFace 模型时很有用。本地运行。 - 替代方案 — Gemini(默认使用 3072 维的
gemini-embedding-001)。 使用已安装的google-genai依赖;通过GEMINI_API_KEY/GOOGLE_API_KEY进行身份验证,或者通过GT_GEMINI_PROJECT- ADC(
gcloud auth application-default login)路由至 Vertex AI,无需管理密钥。远程 — 这是唯一会将分块文本发送到本机之外的嵌入器。如果你有 Gemini 身份验证,但没有 Ollama/[st]安装,并且可以将语料库分享给 Google,请选择此方案。
- ADC(
嵌入器是每个数据库的一项固定选择 — sqlite-vec 会在首次创建时将向量维度写入表中。请在初始化时将选择写入 <data_dir>/config.toml,以便后续每条命令都能使用该设置:
gt init --embed-backend gemini # gemini-embedding-001, 3072
gt init --embed-backend gemini --embed-dim 1536 # request shorter output
gt init --embed-backend sentence_transformers \
--embed-model BAAI/bge-small-en-v1.5 --embed-dim 384
使用相同的值重新运行不会产生任何变化;若对已有的 config.toml 使用不同的值运行,则会明确报错,而不会悄悄更改语料库。GT_EMBED__* 环境变量仍可用于单次覆盖和 CI。
“仅使用云端 LLM”的配置需要嵌入器进程(Ollama/[st]),或选择远程 Gemini 嵌入器。
GitHub 令牌所需权限范围
运行 gt init 时,GH 客户端需要以下权限:
repo— 访问私有仓库及其 PR 评论user:email— 用于用户模式身份信息扫描的已验证电子邮件地址read:org— 列出组织成员并发现组织的私有仓库
细粒度 PAT 和经典令牌均可使用。
检索
默认使用混合搜索:BM25(SQLite FTS5)和向量相似度并行运行,然后通过 Reciprocal Rank Fusion(k=60)融合结果。向量检索部分匹配语义意图;BM25 部分则能捕捉向量搜索经常漏掉的精确标识符(getUserById、SQLITE_OPEN_READWRITE)。设计参考:Anthropic — Contextual
Retrieval。
嵌入时,每个分块前都会加上确定性标头:# path :: symbol_name (node_kind),以及函数开头的文档字符串/注释(如果有),和可选的 LLM 生成摘要(参见 gt summarize)。标头可让向量查询命中正文只包含标识符的分块(例如,针对 VaultSecretEq 函数的自然语言查询)。
默认启用 BM25 查询扩展(cfg.retrieval.query_expansion = "rule"),仅对 BM25 部分应用基于规则的代码形式同义词——嵌入本身已能捕捉同义关系,因此扩展不会影响向量查询。切换为 "ollama" 可在此基础上添加 LLM 生成的替代查询,并按词元缓存在磁盘上。
predict_review_outcome 仍使用纯向量检索,因为其反距离投票权重依赖经过校准的 L2 距离。
MCP 工具
所有检索工具均接受可选的 repo= 和 author_login= 筛选条件。
| 工具 | 返回内容 |
|---|---|
find_review_comments(diff_hunk, language?, repo?, author_login?, k=5) | 与输入相似的差异中,过去的评审评论。 |
find_style_examples(query, language?, repo?, author_login?, k=5) | 与描述匹配的过往代码分块。 |
find_code(query, language?, repo?, path_glob?, node_kind?, k=5) | HEAD 中文件的源代码片段(组织模式)。 |
find_applicable_rules(query, language?, repo?, author_login?, k=5) | 与编码任务相关的提炼代码模式规则。 |
predict_review_outcome(diff_or_summary, language?, repo?, author_login?, k=20) | 对最相近的过往 PR 进行加权预测:{approved, changes_requested, commented}。 |
summarize_review_patterns(language?, limit=20) | 从聚类后的评审评论中提炼规则(请先运行 gt distill)。 |
sync(since?) | 增量导入 + 摘要生成 + 嵌入。 |
命令行
gt init [--kind user|org|repo] [--org N] [--repo owner/name]
gt repos # list discovered org repos
gt ingest # backfill
gt summarize [--limit N] [--backend ...] # LLM NL summaries per chunk
gt embed # embed pending chunks
gt sync [--skip-summarize] # incremental: ingest → summarize → embed
gt stats # corpus counts
gt distill [--backend ...] [--author ...] # rule extraction
gt clones prune [--older-than-days N] # GC the persistent clone cache
gt eval reviews --since DATE [...] # held-out RAG-vs-baseline eval
gt eval predictions --since DATE [...]
gt eval search evals/queries/default.yaml # retrieval-quality dogfood
gt serve # MCP stdio server
github-twin <command> 和 gt <command> 可以互换使用。
可插拔后端
| 接口 | 环境变量/配置项 | 默认值 | 备选项 |
|---|---|---|---|
LLM(cfg.distill.backend、cfg.summarize.backend) | ANTHROPIC_API_KEY/GEMINI_API_KEY(或 GT_GEMINI_PROJECT + ADC)/Ollama | auto(云端优先于本地) | 强制使用 claude/gemini/ollama |
嵌入模型(cfg.embed.backend) | —/GEMINI_API_KEY(或 GT_GEMINI_PROJECT + ADC) | ollama(nomic-embed-text) | 通过 [st] extra 使用 sentence_transformers,或使用 gemini(gemini-embedding-001,远程) |
向量存储(cfg.vector_store.backend) | — | sqlite-vec(暴力 KNN) | 通过 [faiss] extra 使用 faiss |
BM25 查询扩展(cfg.retrieval.query_expansion) | — | rule(确定性) | ollama(LLM,缓存)或 off |
所有设置均按以下层级应用:默认值 → <data_dir>/config.toml(或显式指定的 --config PATH)→ 前缀为 GT_ 的环境变量(嵌套配置使用 __,例如 GT_EMBED__BACKEND=sentence_transformers)。
留出集评估
gt eval 使用相同提示词,分别在启用和不启用检索的情况下运行,并衡量 RAG 在真实留出数据上的准确率提升:
# Review-comment voice match (cosine distance to ground truth)
uvx github-twin eval reviews --since 2025-01-01 --limit 100
# Org-mode: scope to one reviewer (and optionally one repo)
uvx github-twin eval reviews --since 2025-01-01 --author alice --repo http4s/http4s
uvx github-twin eval predictions --since 2025-01-01 --author alice
# Retrieval-quality dogfood (per-tier, per-backend pass rates)
uvx github-twin eval search evals/queries/default.yaml --mode all
评估框架会预先检查符合条件的数据量,因此拼错的 --author 或 --repo 会立即报错,不会浪费 LLM 调用。裁判嵌入模型默认与检索器使用不同模型(安装 [st] extra 后使用 sentence-transformers BGE-small),以避免测量检索器对自身输出的聚类效果。
可观测性(OpenTelemetry)
每次 MCP 工具调用、每次嵌入器调用以及每个检索阶段都会生成 Span,并通过 OTLP 导出。自动检测——除非配置了环境,否则不会触发任何操作。具体如下:
-
安装
[otel]附加组件(包含 SDK 和 HTTP OTLP 导出器):uvx --with 'github-twin[otel]' github-twin serve -
通过环境变量指定 OTLP HTTP 收集器:
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 export OTEL_SERVICE_NAME=github-twin # optional
即使设置了端点,OTEL_SDK_DISABLED=true 也会强制禁用它。
如果没有 [otel] 或没有端点环境变量,代码路径仍会运行,但每个 Span 都会由 opentelemetry-api 的内置追踪器免费空操作。即使启用了遥测,也绝不会使用 stdout——因为 MCP 使用 stdin/stdout 传输 JSON,意外的控制台导出器会破坏通信通道。OTLP HTTP 导出器会向你的收集器发送数据;SDK 警告则会通过 Python logging 路由到 stderr。
已接入 Claude Code:
{
"mcpServers": {
"github-twin": {
"command": "uvx",
"args": ["--with", "github-twin[otel]", "github-twin", "serve"],
"env": {
"GITHUB_TOKEN": "ghp_...",
"GT_PATHS__DATA_DIR": "/path/to/twin-data",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4318",
"OTEL_SERVICE_NAME": "github-twin"
}
}
}
}
Span 名称和可用于筛选的关键属性:
| Span | 有用的属性 |
|---|---|
mcp.tool.{find_review_comments,find_style_examples,find_code,find_applicable_rules,predict_review_outcome,summarize_review_patterns,sync} | gh_twin.tool.k、gh_twin.filter.*、gh_twin.result.count(predict 时则为 .prediction/.confidence) |
embedder.embed | gh_twin.embed.input_chars、gh_twin.embed.model |
retrieval.hybrid_search | gh_twin.retrieval.{chunk_kind,k,expander,hits,top_distance} |
retrieval.vector_search(predict_review_outcome) | 属性结构相同,但没有 expander |
收集器故障或无法访问时,每次刷新尝试都会输出一条 Failed to export span batch 日志,并且绝不会传播到工具处理程序——这一点由 tests/test_observability.py 保证。
gRPC 用户:除 [otel] 附加组件外,还需安装
opentelemetry-exporter-otlp-proto-grpc,SDK 会根据
OTEL_EXPORTER_OTLP_PROTOCOL=grpc 自动启用它。
存储
一个数据库可以容纳多个目标(用户 + N 个组织 + N 个仓库);若要隔离这些目标,请为每个数据库使用单独的 GT_PATHS__DATA_DIR。数据目录的解析不受环境影响:
- 设置了
GT_PATHS__DATA_DIR时使用该目录 - 否则,如果设置了
XDG_DATA_HOME,则使用$XDG_DATA_HOME/github-twin/ - 否则使用
~/.local/share/github-twin/
不会读取当前工作目录。
目录结构——每个数据库的所有内容都位于同一个根目录下:
<data_dir>/
db.sqlite # artifacts + chunks + vectors + FTS5 index
config.toml # written by `gt init --embed-backend ...`
raw/ # on-disk cache of raw GitHub responses
clones/ # persistent shallow clones (if cache_clones=true)
wiki/ # `gt wiki export` default output
auth/token.json # OAuth file fallback
query_expansion_cache.sqlite # only when retrieval.query_expansion=ollama
如果你运行过会将 ./config.toml 或 ./data/ 写入当前工作目录的旧版本,那么每次调用 CLI 时都会记录一次性 WARN,并附上准确的 mv 命令用于迁移。
发布
版本通过 hatch-vcs 从 git 标签获取。 发布只需一条命令:
git tag v0.2.0 # PEP 440 forms: v0.2.0, v0.2.0a1, v0.2.0rc1, v0.2.0.post1
git push --tags
推送 v* 标签会触发 .github/workflows/release.yml,该工作流会:
- 在 Python 3.12 / 3.13 上运行 pytest + ruff +
uv build。 - 通过 Trusted Publishing
(OIDC) 将 wheel + sdist 发布到 PyPI。仓库机密中不会存储 PyPI 令牌——PyPI 会根据你在项目页面上注册的 Trusted Publisher,验证由 GitHub 签名的 OIDC 令牌(工作流文件名
release.yml,环境pypi)。 - 创建带有自动生成说明(自上一个标签以来的 PR)的 GitHub Release,并附上 wheel + sdist。预发布标签(
a/b/rc)会标记为预发布,因此不会取代“Latest”。 - 更新
main上的.claude-plugin/plugin.json,使其与标签版本一致——设置version,并将 MCP 服务调用固定为uvx [email protected] serve。市场会从 HEAD 获取清单,因此用户的市场缓存刷新后就会获得此版本。
每个仓库只需进行一次的首次设置:
- 将项目推送到 GitHub(任意账号 / 组织均可)。
- 在 PyPI 上注册 Trusted Publisher:
- https://pypi.org/manage/account/publishing/
- Owner:你的 GitHub 用户名 / 组织;Repository:
github-twin; Workflow:release.yml;Environment:pypi。 - (如果项目尚未在 PyPI 上创建,也可以使用“Pending Publisher”流程。)
- 在 GitHub 上:Settings → Environments → 新建环境
pypi。将自己添加为 Required Reviewer,以便在每次发布前增加审批步骤(可选,但建议)。
.github/workflows/ci.yml 会在每个 PR 以及推送到 main 时运行——发布工作流会在发布前重新运行相同的检查,因此有问题的 main 不会产生发布版本。
设计说明
- 嵌入时前缀(
embed.prefix.prefix_chunk):按类型生成的标头,会在嵌入时拼接到每个分块的文本之前,且不会写回chunk.text。形状发生变化时会递增EMBED_TEXT_VERSION,以便下一次gt embed重新生成向量。 - AST 分块(
process.chunkers):tree-sitter 遍历会按可声明单元生成分块;对于不支持的语言或解析失败的情况,则回退到按行窗口分块。 - 非对称查询扩展
(
store.query_expansion):仅应用于 BM25 部分,向量部分始终使用原始嵌入——由test_hybrid_search.py固定验证。
原始设计方案见
getting_started.md,其中包含完整的演练说明。
许可证
MIT — 详见 LICENSE。
mcp-name: io.github.ChristopherDavenport/github-twin
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。