github-twin

io.github.ChristopherDavenport由 GitHub 账号 ChristopherDavenport 发布v0.0.17更新于 Oct 24, 2026

Personal RAG over your GitHub history (commits, code, reviews), served to Claude Code over MCP.

概览

AI 生成的概览

将你的 GitHub 提交、代码与评审评论索引到本地 RAG 存储,并向 MCP 客户端提供检索工具。

可以做什么
github-twin 将你的 GitHub 历史记录导入本地 SQLite 索引,并通过 stdio 提供给 Claude Code 或任意 MCP 客户端(R14)。工具包括 find_review_comments、find_style_examples、find_code、find_applicable_rules、predict_review_outcome、summarize_review_patterns 与 sync(R99、R100、R101、R102、R103、R104、R105)。检索采用 BM25 与向量混合并用倒数排名融合,对多种语言进行 AST 感知分块(R87、R169)。支持索引个人历史的用户模式与索引整个组织的组织模式(R16、R18)。
适用场景
当助手编写或评审代码、而你希望它参考你过去的提交、代码风格与评审意见时使用(R4、R5、R6)。适合个人或组织级代码库,让过去的评审决定与约定影响新工作(R17、R18)。如果只需要实时 GitHub API 访问而非本地检索索引,则无需安装。},
运行要求
以本地 stdio 进程运行,通过 uvx github-twin serve 启动(R7、R32),需要 Python 与 uv/uvx。需要 GitHub 令牌,可通过 OAuth 设备流程、gh CLI 或 GITHUB_TOKEN 环境变量提供(R25、R26、R28、R29)。需要嵌入后端:默认使用运行中的 Ollama 守护进程,或安装 sentence-transformers 附加组件(R65、R66、R68)。可选 ANTHROPIC_API_KEY、GEMINI_API_KEY 或 GT_GEMINI_PROJECT 启用托管 LLM 后端(R52、R54、R56)。GT_PATHS__DATA_DIR 指定数据目录(R140)。
安装前请注意
需要具备 repo、read:org 与 user:email 权限的 GitHub 令牌(R82、R83、R84),可访问私有仓库与组织成员信息;令牌保存在系统钥匙串或 0600 文件中(R27)。可选的 ANTHROPIC_API_KEY、GEMINI_API_KEY 或 GT_GEMINI_PROJECT 会启用托管 LLM 调用,用于 distill、summarize 与 eval(R47、R48、R49);Vertex/ADC 路径即使使用免费 Gemini 模型也会产生计费(R60)。Gemini 嵌入后端是唯一会把代码片段文本发送到外部服务的选择(R73)。

安装

在 SourceWeft 中

  1. 打开 控制台中的 github-twin,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

github-twin

[PyPI version] [Python versions] [CI] [License: MIT]

You reviewed a permission check six months ago. Claude doesn't remember it. github-twin does — it indexes your commits and review comments, and surfaces them as retrieval hits whenever an agent writes or reviews new code in your style.

[gt stats + gt eval search returning hits against a real corpus]

[Claude Code citing a past review comment via the find_review_comments tool]

Try it now from Claude Code — drop this into ~/.claude.json and reload:

json
{  "mcpServers": {    "github-twin": { "command": "uvx", "args": ["github-twin", "serve"] }  }}

Your code stays on your box. Embeddings are computed locally (Ollama or sentence-transformers); only the LLM seam (gt summarize, gt distill, gt eval) optionally calls a hosted provider, and even that's swappable to local Ollama. The gemini embedder is the one exception — opt-in only.


A personal RAG over your GitHub history, served to Claude Code (or any MCP client) as a stdio server. Two scopes, one codebase:

  • User mode — index your own commits + review comments. Surfaces your past code as style examples and your past comments as review hints when an agent is writing or reviewing new code.
  • Org mode — index a whole GitHub org's files-at-HEAD, commits, and PR reviews across every member. Queries scope by repo, language, or reviewer login.

Retrieval is hybrid (BM25 + vector via RRF), AST-aware via tree-sitter for python/scala/javascript/typescript/go/rust, and contextually enriched at embed time with per-chunk headers + optional LLM-generated summaries.

Install

The fastest path is uvx — no virtualenv to manage, isolated per-tool:

sh
# One-shotuvx github-twin --help
# Pinned versionuvx [email protected] --help
# With sentence-transformers for the alt embedderuvx --with 'github-twin[st]' github-twin --help

If you prefer a project-local install:

sh
uv add github-twin            # or: pip install github-twingt --help

gt and github-twin are the same Typer app — use whichever fits your muscle memory.

Authenticate

Pick whichever is least friction — github-twin tries them in this order:

  1. OAuth device flow (no gh install needed):
    sh
    uvx github-twin auth login        # opens browser, persists tokenuvx github-twin auth status       # show which source is active
    Token persists in the OS keyring (macOS Keychain / Linux Secret Service / Windows Credential Manager) or, when unavailable, a 0600 file under your data dir.
  2. Existing gh CLI: if you've already run gh auth login, gt picks up the token via gh auth token — nothing to do.
  3. GITHUB_TOKEN env var: a classic PAT works too; useful for CI / headless / docker. Required scopes: repo, read:org, user:email.

Wire into Claude Code

The MCP server runs over stdio via github-twin serve (or gt serve). Run uvx github-twin auth login once on the box that will host the server.

Option A — via the Claude Code plugin marketplace (lowest-friction):

/plugin marketplace add ChristopherDavenport/christopherdavenport-marketplace/plugin install github-twin@christopherdavenport

This registers the MCP server entry automatically; set GT_PATHS__DATA_DIR in your environment (or in ~/.claude.json's env block for this server) to point at the DB directory.

Option B — manual wiring: add an entry to ~/.claude.json (or your mcp_servers.json):

json
{  "mcpServers": {    "github-twin": {      "command": "uvx",      "args": ["github-twin", "serve"],      "env": {        "GT_PATHS__DATA_DIR": "/path/to/your/github-twin-data"      }    }  }}

If you'd rather not persist a token and instead supply it inline (CI, ephemeral container), add "GITHUB_TOKEN": "ghp_..." to that env block; it acts as the lowest-priority fallback.

Restart Claude Code; the find_*, predict_review_outcome, summarize_review_patterns, and sync tools will be available.

Quickstart

Pick a directory to hold the SQLite DB, config, and ingested cache — everything per-data-dir lives under this one root:

sh
export GT_PATHS__DATA_DIR=~/github-twin-datauvx github-twin auth login                 # one-time OAuth (or set GITHUB_TOKEN)
# user mode (your own GitHub history)uvx github-twin init                       # discover identity via /useruvx github-twin sync                       # ingest + summarize + embeduvx github-twin serve                      # MCP server over stdio
# layer an org into the SAME DBuvx github-twin init --kind org --org http4suvx github-twin sync
# OR keep the org in its own DB by switching data dirsGT_PATHS__DATA_DIR=~/twin-http4s \  uvx github-twin init --kind org --org http4sGT_PATHS__DATA_DIR=~/twin-http4s uvx github-twin sync

gt sync is incremental on subsequent runs.

config.toml lives next to the DB at <data_dir>/config.toml and is created on the first gt init --embed-backend ... call. Default <data_dir> is $XDG_DATA_HOME/github-twin (or ~/.local/share/github-twin) when GT_PATHS__DATA_DIR is unset.

LLM provider matrix

The retrieval surface (find_*, predict_review_outcome) always runs locally on the SQLite index — no API call. LLM calls only happen in three places:

  • gt distill — clusters review comments / commits into rules.
  • gt summarize — generates per-chunk NL summaries used by the embed-time prefix.
  • gt eval reviews / eval predictions — held-out RAG-vs-baseline scoring.

Each picks a backend by precedence Claude → Gemini → Ollama (whichever API key is set), or you can force one explicitly.

ProviderEnv varWhat it covers
Anthropic (Claude)ANTHROPIC_API_KEYDistill / summarize / eval LLM. Best quality.
Google (Gemini, API key)GEMINI_API_KEY or GOOGLE_API_KEYDistill / summarize / eval LLM. Free tier is generous.
Google (Gemini, Vertex / ADC)GT_GEMINI_PROJECT (+ optional GT_GEMINI_LOCATION, default us-central1)Same backends, but auth via gcloud auth application-default login — no key in your shell. API key wins if both are set.
Ollama (local)OLLAMA_HOST (default http://127.0.0.1:11434)Distill / summarize / eval LLM. Fully offline.

The Vertex / ADC path needs the aiplatform.googleapis.com API enabled on your project, and billing applies even for "free" Gemini models — the AI Studio free tier does not extend to Vertex. Project IDs are not secrets; the credential itself lives at ~/.config/gcloud/application_default_credentials.json and is refreshed by gcloud.

Embedder backends

We keep the embedder backend separate from the LLM backend. Choose one:

  • Default — Ollama (nomic-embed-text, 768-dim, ~50ms/chunk). Requires a running Ollama daemon. Zero cost, fully local.
  • Alternative — sentence-transformers (uv add 'github-twin[st]', pulls torch). Useful when an Ollama daemon isn't available or you want a specific HuggingFace model. Local.
  • Alternative — Gemini (gemini-embedding-001 at 3072-dim by default). Uses the google-genai dep that's already installed; auth via GEMINI_API_KEY / GOOGLE_API_KEY, or via GT_GEMINI_PROJECT
    • ADC (gcloud auth application-default login) to route through Vertex AI without managing a key. Remote — this is the only embedder that sends chunk text off-box. Pick it when you have Gemini auth but no Ollama / [st] install, and your corpus is okay to share with Google.

The embedder is a per-DB commitment — sqlite-vec bakes the vector dimension into the table at first creation. Stamp the choice into <data_dir>/config.toml at init time so every subsequent command picks it up:

sh
gt init --embed-backend gemini                              # gemini-embedding-001, 3072gt init --embed-backend gemini --embed-dim 1536            # request shorter outputgt init --embed-backend sentence_transformers \        --embed-model BAAI/bge-small-en-v1.5 --embed-dim 384

Re-running with the same values is a no-op; running with different values against an existing config.toml fails loud rather than silently changing the corpus. GT_EMBED__* env vars still work for one-off overrides and CI.

A "cloud-LLM only" setup either needs an embedder process (Ollama / [st]) or has to opt into the remote Gemini embedder.

Required GitHub token scopes

When you gt init, the GH client needs:

  • repo — private repos and PR comments on them
  • user:email — verified email addresses for the user-mode identity sweep
  • read:org — org member listing and private org repo discovery

A fine-grained PAT works; classic tokens too.

Retrieval

Hybrid search by default: BM25 (SQLite FTS5) and vector similarity run in parallel, then fuse via Reciprocal Rank Fusion (k=60). The vector leg matches semantic intent; the BM25 leg catches exact identifiers (getUserById, SQLITE_OPEN_READWRITE) that vector search routinely misses. Design reference: Anthropic — Contextual Retrieval.

At embed time, each chunk gets a deterministic header prepended: # path :: symbol_name (node_kind), plus the function's leading docstring/comment when present, plus an optional LLM-generated summary (see gt summarize). The header lets vector queries land on chunks whose bodies only contain identifiers (e.g. natural-language queries against a VaultSecretEq function).

BM25 query expansion is on by default (cfg.retrieval.query_expansion = "rule"), with rule-based code-shaped synonyms applied only to the BM25 leg — embeddings already capture synonymy, so expansion never touches the vector query. Switch to "ollama" to add LLM-generated alternates on top, cached on disk per-token.

predict_review_outcome stays on pure vector retrieval because its inverse-distance vote weighting depends on calibrated L2 distance.

MCP tools

All retrieval tools accept optional repo= and author_login= filters.

ToolReturns
find_review_comments(diff_hunk, language?, repo?, author_login?, k=5)Past review comments on diffs similar to the input.
find_style_examples(query, language?, repo?, author_login?, k=5)Past code chunks matching a description.
find_code(query, language?, repo?, path_glob?, node_kind?, k=5)Source snippets from files at HEAD (org mode).
find_applicable_rules(query, language?, repo?, author_login?, k=5)Distilled code-pattern rules relevant to a coding task.
predict_review_outcome(diff_or_summary, language?, repo?, author_login?, k=20)Weighted prediction over nearest past PRs: {approved, changes_requested, commented}.
summarize_review_patterns(language?, limit=20)Distilled rules from clustered review comments (run gt distill first).
sync(since?)Incremental ingest + summarize + embed.

CLI

gt init [--kind user|org|repo] [--org N] [--repo owner/name]gt repos                                       # list discovered org reposgt ingest                                      # backfillgt summarize [--limit N] [--backend ...]       # LLM NL summaries per chunkgt embed                                       # embed pending chunksgt sync [--skip-summarize]                     # incremental: ingest → summarize → embedgt stats                                       # corpus countsgt distill [--backend ...] [--author ...]      # rule extractiongt clones prune [--older-than-days N]          # GC the persistent clone cachegt eval reviews     --since DATE [...]         # held-out RAG-vs-baseline evalgt eval predictions --since DATE [...]gt eval search evals/queries/default.yaml      # retrieval-quality dogfoodgt serve                                       # MCP stdio server

Use github-twin <command> interchangeably with gt <command>.

Pluggable backends

SurfaceEnv / config keyDefaultAlt
LLM (cfg.distill.backend, cfg.summarize.backend)ANTHROPIC_API_KEY / GEMINI_API_KEY (or GT_GEMINI_PROJECT + ADC) / Ollamaauto (cloud > local)force claude / gemini / ollama
Embedder (cfg.embed.backend)— / GEMINI_API_KEY (or GT_GEMINI_PROJECT + ADC)ollama (nomic-embed-text)sentence_transformers via [st] extra, or gemini (gemini-embedding-001, remote)
Vector store (cfg.vector_store.backend)—sqlite-vec (brute-force KNN)faiss via [faiss] extra
BM25 query expansion (cfg.retrieval.query_expansion)—rule (deterministic)ollama (LLM, cached) or off

All settings are layered: defaults → <data_dir>/config.toml (or the explicit --config PATH) → env vars prefixed GT_ (nested via __, e.g. GT_EMBED__BACKEND=sentence_transformers).

Held-out evaluation

gt eval runs the same prompt with and without retrieval and measures RAG's accuracy lift on real held-out data:

sh
# 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/http4suvx 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

The harness pre-flights eligibility counts so typo'd --author or --repo fail fast without burning LLM calls. The judge embedder defaults to a different model than the retriever (sentence-transformers BGE-small with the [st] extra installed) to avoid measuring how well retrieval clusters its own outputs.

Observability (OpenTelemetry)

Spans for every MCP tool call, every embedder call, and every retrieval leg, exported via OTLP. Auto-detected — nothing fires unless the environment is configured. Specifically:

  1. Install the [otel] extra (carries the SDK + HTTP OTLP exporter):

    sh
    uvx --with 'github-twin[otel]' github-twin serve
  2. Point at an OTLP HTTP collector via env vars:

    sh
    export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318export OTEL_SERVICE_NAME=github-twin            # optional

OTEL_SDK_DISABLED=true forces it off even when an endpoint is set.

Without [otel] or without an endpoint env var, the code paths still run but every span is a free no-op from opentelemetry-api's built-in tracer. stdout is never used — even with telemetry on — because MCP speaks JSON over stdin/stdout and a stray console exporter would corrupt the channel. The OTLP HTTP exporter posts to your collector; SDK warnings route through Python logging (stderr).

Wired into Claude Code:

json
{  "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 names + key attributes you can pivot on:

SpanUseful attributes
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 (or .prediction/.confidence for predict)
embedder.embedgh_twin.embed.input_chars, gh_twin.embed.model
retrieval.hybrid_searchgh_twin.retrieval.{chunk_kind,k,expander,hits,top_distance}
retrieval.vector_search (predict_review_outcome)same shape, sans expander

A broken or unreachable collector emits a single Failed to export span batch log line per flush attempt and never propagates into the tool handler — pinned by tests/test_observability.py.

gRPC users: install opentelemetry-exporter-otlp-proto-grpc alongside the [otel] extra and the SDK picks it up automatically based on OTEL_EXPORTER_OTLP_PROTOCOL=grpc.

Storage

One DB can hold many targets (user + N orgs + N repos); use a separate GT_PATHS__DATA_DIR per DB when you want them isolated. The resolved data dir is pure with respect to env:

  • GT_PATHS__DATA_DIR when set
  • else $XDG_DATA_HOME/github-twin/ when XDG_DATA_HOME is set
  • else ~/.local/share/github-twin/

The current working directory is never consulted.

Layout — everything per-DB lives under one root:

<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

If you ran an older release that wrote ./config.toml or ./data/ into the current working directory, every CLI invocation logs a one-time WARN with the exact mv command to migrate.

Releasing

Versions come from git tags via hatch-vcs. Cutting a release is one command:

sh
git tag v0.2.0    # PEP 440 forms: v0.2.0, v0.2.0a1, v0.2.0rc1, v0.2.0.post1git push --tags

The push to a v* tag triggers .github/workflows/release.yml, which:

  1. Runs pytest + ruff + uv build across Python 3.12 / 3.13.
  2. Publishes the wheel + sdist to PyPI via Trusted Publishing (OIDC). No PyPI token is stored in repo secrets — PyPI verifies the GitHub-signed OIDC token against the Trusted Publisher you register on the project page (workflow filename release.yml, environment pypi).
  3. Creates a GitHub Release with auto-generated notes (PRs since the previous tag) and attaches the wheel + sdist. Pre-release tags (a/b/rc) are flagged so they don't replace "Latest".
  4. Bumps .claude-plugin/plugin.json on main to match the tag — sets version and pins the MCP server invocation to uvx [email protected] serve. The marketplace fetches the manifest from HEAD, so this is what users get when their marketplace cache refreshes.

First-time setup, once per repo:

  1. Push the project to GitHub (any account / org).
  2. Register the Trusted Publisher on PyPI:
    • https://pypi.org/manage/account/publishing/
    • Owner: your GitHub user/org, Repository: github-twin, Workflow: release.yml, Environment: pypi.
    • (Or use the "Pending Publisher" flow if the project doesn't exist on PyPI yet.)
  3. On GitHub: Settings → Environments → New environment pypi. Add yourself as a Required Reviewer for an extra approval step before each publish (optional but recommended).

.github/workflows/ci.yml runs on every PR and push to main — the release workflow re-runs the same checks before publishing, so a broken main never produces a release.

Design notes

  • Embed-time prefix (embed.prefix.prefix_chunk): per-kind header spliced before each chunk's text at embed time, never written back to chunk.text. Bumps EMBED_TEXT_VERSION whenever the shape changes so the next gt embed re-derives vectors.
  • AST chunking (process.chunkers): tree-sitter walks emit chunks per declarable unit; falls back to line-window for unsupported languages or parse failures.
  • Asymmetric query expansion (store.query_expansion): BM25 leg only, vector leg always sees the raw embedding — pinned by test_hybrid_search.py.

The original design plan lives in getting_started.md along with the full walkthrough.

License

MIT — see LICENSE.

mcp-name: io.github.ChristopherDavenport/github-twin

来源:README.md,提交 a078be8

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.0.17最新Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分