{"id":50227029,"url":"https://github.com/mtrdesign/whygraph","last_synced_at":"2026-05-26T16:13:49.494Z","repository":{"id":355665339,"uuid":"1228849549","full_name":"mtrdesign/whygraph","owner":"mtrdesign","description":"MCP server that gives Claude Code the rationale behind a symbol before editing - synthesized from git history, PRs, and call-graph context.","archived":false,"fork":false,"pushed_at":"2026-05-21T21:03:23.000Z","size":794,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-21T21:12:15.133Z","etag":null,"topics":["claude-code","codegraph","mcp-server"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtrdesign.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-04T12:50:40.000Z","updated_at":"2026-05-12T17:30:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mtrdesign/whygraph","commit_stats":null,"previous_names":["mtrdesign/whygraph"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mtrdesign/whygraph","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtrdesign%2Fwhygraph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtrdesign%2Fwhygraph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtrdesign%2Fwhygraph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtrdesign%2Fwhygraph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtrdesign","download_url":"https://codeload.github.com/mtrdesign/whygraph/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtrdesign%2Fwhygraph/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33528414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","codegraph","mcp-server"],"created_at":"2026-05-26T16:13:48.588Z","updated_at":"2026-05-26T16:13:49.485Z","avatar_url":"https://github.com/mtrdesign.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# whygraph\n\nRationale layer over [CodeGraph](https://github.com/colbymchenry/codegraph): explains *why* code exists, not just what it does.\n\nFor each symbol, WhyGraph collects evidence from git history and GitHub (commits, blame, PRs, closing issues, callers/callees from CodeGraph), then exposes it to AI assistants over MCP plus an on-demand rationale (purpose, why, constraints, tradeoffs, risks) with a deterministic confidence score and persistent cache.\n\n\u003e **Status:** v1.x in progress on the `feature/scan-and-scoring` branch. MCP surface (resources, tools, prompts) is functional. The `/whygraph-plan` slash command + fan-out/fan-in planner subagents shipped in v1.3.\n\n## Prerequisites\n\n- **[uv](https://docs.astral.sh/uv/)** — Python toolchain. Installs Python 3.11+ automatically.\n- **git** — repo history is the primary evidence source.\n- **[`gh` CLI](https://cli.github.com/)**, authenticated (`gh auth login`) — required only if your repo is on GitHub. Without it, the GitHub crawl phase is skipped silently.\n- **Node ≥ 22** — required by CodeGraph (used for graph queries). `whygraph init` bootstraps this for you via nvm if needed.\n- **`claude` CLI** — required only for the LLM diff-description phase of `whygraph scan` and for `whygraph_rationale_brief`. Both phases skip cleanly if the CLI is missing. Defaults to your Claude.ai subscription billing.\n\n## Quickstart\n\nInstall WhyGraph once (see [Installation](#installation) below), then in the repository you want to analyse:\n\n```bash\n# 1. Bootstrap CodeGraph (Node ≥ 22, then runs `codegraph init -i`).\nwhygraph init\n\n# 2. Scan: walks git history, fetches PRs/issues, runs TF-IDF scoring,\n#    generates an LLM diff description per commit. Writes to\n#    .whygraph/whygraph.db in the current repo.\nwhygraph scan\n\n# 3. Verify the MCP server can launch.\nwhygraph-mcp   # Ctrl-C to exit\n```\n\nThe full scan touches every commit on the default branch. On large or remote-heavy repos you may want to bound the LLM phase only:\n\n```bash\n# Run scan + LLM only on the 50 most recent commits. Other phases\n# (git crawl, GitHub fetch, TF-IDF scoring) still cover full history.\nwhygraph scan --llm-recent 50\n```\n\n## Installation\n\nWhyGraph follows a **one-global-install / use-anywhere** model — like `npx`, but for Python. You install the package once on your machine; that puts the `whygraph` and `whygraph-mcp` console scripts on your `PATH`. Then `whygraph init --agent \u003cname\u003e` wires up each individual project so its agent can launch the MCP server.\n\nPick whichever install path fits where the project is in its lifecycle:\n\n### From PyPI (stable releases)\n\n```bash\nuv tool install whygraph        # or: pipx install whygraph\n```\n\n\u003e **Status:** WhyGraph is not yet published to PyPI. Use one of the GitHub or local-checkout paths below until v1 ships.\n\n### From GitHub (latest / pre-release)\n\nFor unreleased features on `main`, a specific feature branch, or a tag:\n\n```bash\n# Latest from main:\nuv tool install \"git+https://github.com/cvetty/whygraph.git\"\n\n# A specific branch (e.g. an in-flight feature):\nuv tool install \"git+https://github.com/cvetty/whygraph.git@feature/scan-and-scoring\"\n\n# A specific tag (once tagged):\nuv tool install \"git+https://github.com/cvetty/whygraph.git@v1.3.0\"\n```\n\nRe-running upgrades in place. To switch refs, add `--force` (or `uv tool uninstall whygraph` first). `pipx` accepts the same `git+https://…` URLs.\n\n### From a local checkout (contributors)\n\n```bash\ngit clone https://github.com/cvetty/whygraph.git\nuv tool install --editable ./whygraph\n```\n\n`--editable` lets your local edits show up immediately, without reinstalling.\n\n### Verify\n\n```bash\nwhygraph version\nwhich whygraph-mcp\n```\n\nBoth should resolve to the global tool install (under `~/.local/bin/` or `uv`'s shim directory).\n\n### Wire each project\n\n```bash\ncd /path/to/your-project\nwhygraph init --agent claude     # Claude Code: writes .mcp.json + drops bundled assets in .claude/\n```\n\n`whygraph init --agent claude` writes `.mcp.json` at the repo root and copies the bundled agent / command / skill markdown into `\u003cproject\u003e/.claude/agents`, `/.claude/commands`, `/.claude/skills`. The `.mcp.json` references `whygraph-mcp` by bare command name, so the same checked-in config works for every teammate who has WhyGraph installed globally — no absolute paths to scrub. Re-running is safe — pre-existing files are left alone; pass `--force` to overwrite, `--no-install-assets` to skip the asset copy entirely.\n\n### Migration from the Claude Code plugin\n\nEarlier versions shipped via the Claude Code plugin marketplace. That path is gone — there is no more `plugins/whygraph/` or `.claude-plugin/marketplace.json`, and an old `/plugin install whygraph@whygraph` will fail. To migrate:\n\n```\n# In your Claude Code session:\n/plugin uninstall whygraph@whygraph\n/plugin marketplace remove whygraph\n\n# Then in each project where you want WhyGraph:\nwhygraph init --agent claude\n```\n\n## Wire WhyGraph into your editor\n\nWhyGraph's MCP server (`whygraph-mcp`) is a standalone console script, so any LLM agent that speaks MCP can use it. `whygraph init --agent X` writes the right snippet to the right file for each supported agent.\n\nRun from the repo you want WhyGraph to analyse:\n\n```bash\nwhygraph init                          # DB only, no agent wiring (safe default)\nwhygraph init --agent claude          # writes .mcp.json + populates .claude/\nwhygraph init --agent cursor          # writes .cursor/mcp.json\nwhygraph init --agent vscode          # writes .vscode/mcp.json (alias: copilot)\nwhygraph init --agent codex           # prints snippet for ~/.codex/config.toml\nwhygraph init --agent claude-desktop  # prints snippet for Claude Desktop config\nwhygraph init --agent X --print       # prints the MCP snippet, never writes it\nwhygraph init --agent claude --no-install-assets   # MCP only, skip .claude/ copy\nwhygraph init --agent claude --force               # overwrite existing .claude/* files\nwhygraph init --list-agents            # show all supported agents + paths\n```\n\n**Project-scoped agents** (Claude Code, Cursor, VS Code / Copilot) get a config file written inside the repo so you can commit it — every contributor's editor picks it up automatically. **User-scoped agents** (Codex, Claude Desktop) are print-only: the command emits the snippet and tells you where to paste it, so WhyGraph never silently edits files outside the repo.\n\n`--agent claude` is the only path that also installs the `/whygraph-plan` slash command, the `plan-change` skill, and the planner / researcher / synthesizer subagents — these only make sense for Claude Code, so they ship as `.claude/*` markdown rather than as part of the MCP surface.\n\n## CLI commands\n\n| Command | Purpose |\n|---|---|\n| `whygraph version` | Print installed package version. |\n| `whygraph init [-y]` | Bootstrap CodeGraph in the current repo. Detects/installs Node ≥ 22 via nvm if needed, then runs `codegraph init -i`. |\n| `whygraph scan` | Walk first-parent history and populate `.whygraph/whygraph.db`: commits + GitHub PRs/issues + TF-IDF scoring + per-commit LLM diff descriptions. Idempotent. |\n| `whygraph render [--out PATH] [--open] [--depth N]` | Render a self-contained HTML viewer of the CodeGraph + WhyGraph data. Single file, vendored Cytoscape, opens with double-click. Cached rationale only. `--depth N` (1–4, default 1) caps which nodes get a populated detail block — fast first paint at default 1 (modules only); pass `--depth 4` for full data. |\n| `whygraph serve [--port 8765] [--open]` | Long-running localhost viewer with on-demand rationale generation. Same UI as `render`, plus a \"Generate rationale\" button on uncached nodes. |\n| `whygraph-mcp` | Launch the FastMCP stdio server. Referenced by the `.mcp.json` files `whygraph init --agent X` writes into each project. |\n\n### `whygraph scan` flags\n\n| Flag | Default | Purpose |\n|---|---|---|\n| `--no-score` | off | Skip TF-IDF scoring after data collection. |\n| `--no-llm-description` | off | Skip the per-commit LLM diff-description phase entirely. |\n| `--anthropic-key TEXT` | unset | If set, the `claude` subprocess uses API billing with this key. If omitted, the subprocess inherits a stripped env (no `ANTHROPIC_API_KEY`), forcing Claude.ai subscription billing. |\n| `--llm-workers N` | `4` | Parallel `claude` subprocesses in the LLM phase. |\n| `--llm-recent N` | unbounded | Limit the LLM phase to the most recent N commits on the default branch. Other phases still cover full history. |\n| `--llm-model TEXT` | `claude-sonnet-4-6` | Model used by the `claude` subprocess in the LLM phase. Also persisted to `commits.llm_description_model` per row. Use Opus on small repos for higher-quality descriptions; default is Sonnet for throughput on large scans. |\n\n## MCP surface\n\nThe `.mcp.json` written by `whygraph init --agent claude` (and the equivalents for other agents) launches `whygraph-mcp`, which registers:\n\n### Resources\n\n- `whygraph://repo/overview` — counts, scan freshness, scoring + LLM coverage, top contributors.\n- `whygraph://commit/{sha}` — full commit row + linked PRs + closing issues.\n- `whygraph://pr/{number}` — full PR row + closing issues.\n- `whygraph://issue/{number}` — full issue row + closing PRs.\n\n### Tools\n\n- **`whygraph_evidence_for`** — historical evidence (commits + PRs + closing issues) for a code chunk. Pass `(path, line_start, line_end)` or `qualified_name` (CodeGraph resolves it to a file/line range — no graph traversal). Multi-narrative output: each commit ships `llm_description` + `subject` + `body` when each clears the harshness gate. For caller/callee context, query CodeGraph or Claude Code's Explore agent separately.\n- **`whygraph_search`** — LIKE-match query across commits/PRs/issues, ranked by TF-IDF.\n- **`whygraph_velocity_summary`** — per-author commit velocity or per-path-prefix touch counts over a window. Author resolution goes through the `authors` identity table (replaces the old email-localpart heuristic).\n- **`whygraph_window`** — generic windowed query over the scan DB. Filters: `since` / `until` (ISO date or relative shorthand `30d`/`3m`/`1y`), `kinds` (`commit` / `pr` / `issue`), `author` (login | email | name → resolved via `authors`), `path_prefix`, `label`, `state` (`merged` | `open` | `closed`). Returns time-ordered rows; the data spine for the analytics prompts below.\n- **`whygraph_rationale_brief`** — generates the 5-section rationale card (purpose / why / constraints / tradeoffs / risks + confidence) by feeding the evidence bundle to a `claude` subprocess. **Cached** in the scan DB by `(target + bundle content + model + prompt version)` — re-invocation on unchanged code is a sub-millisecond DB read. Pass `force_refresh=True` to bypass.\n\n### Prompts\n\nOrchestration recipes that wire the tools above into common workflows:\n\n- `explain_change` — pre-edit rationale for a code chunk.\n- `debug_history` — find historical candidate causes for a bug symptom.\n- `team_pulse` — per-author + per-path velocity over a rolling window.\n- `changelog(since, until, scope?)` — themed markdown changelog of merged PRs in a date window.\n- `feature_timeline(since, until)` — Mermaid `timeline` of merged PRs and issues opened in the window.\n- `user_profile(identity, since, until)` — per-user contribution profile (commits, PRs, areas owned, issues closed).\n- `whygraph_plan(task)` — composes search → CodeGraph (for symbol resolution) → rationale_brief into an ordered implementation plan.\n\n### Composition with CodeGraph\n\nWhyGraph deliberately does not expose graph-traversal tools. The split:\n\n| Layer | Owns |\n|---|---|\n| **CodeGraph** (its MCP server / Claude's Explore agent) | \"what is connected to what\" — `findUsages`, `getCallers`, `find_symbols`, type hierarchy |\n| **WhyGraph** | \"why does this exist + when did it change\" — evidence, rationale, windowed analytics |\n\nThe `whygraph_plan` prompt and the `/whygraph-plan` slash command both explicitly delegate symbol resolution to CodeGraph. For ad-hoc traversal mid-conversation, agents should call CodeGraph's tools directly.\n\n### Slash command\n\n`/whygraph-plan \u003ctask description\u003e [--shallow|--deep] [--no-questions]` — produces a step-by-step implementation plan grounded in CodeGraph (impact) and WhyGraph (rationale). `whygraph init --agent claude` drops three subagents under `.claude/agents/`:\n\n- **`whygraph-planner`** — orchestrator. Builds the working set via CodeGraph, warms the rationale cache, then either writes a plan single-pass (small scope) or fans out.\n- **`whygraph-researcher`** — fan-out worker, instantiated three times in parallel with one of three dimensions: `impact` (blast radius via CodeGraph callers), `constraints_risks` (verbatim from rationale cards), `prior_art` (similar past PRs via `whygraph_search` / `whygraph_window`).\n- **`whygraph-synthesizer`** — fan-in combiner. Folds the three reports into the final plan markdown with a confidence floor = lowest researcher confidence.\n\nAuto-mode heuristic: single-pass when working set \u003c 5 nodes OR \u003e 60% of rationale cards are empty/low-confidence; fan-out otherwise. `--shallow` and `--deep` override.\n\n### Skill\n\n`plan-change` — auto-trigger description that nudges the user toward `/whygraph-plan` on planning-shaped prompts (e.g. *\"plan how to refactor X\"*, *\"design a migration for Y\"*). Suggestion-only; never auto-runs the planner — the slash command is the user's opt-in cost gate.\n\n## HTML viewer\n\n```bash\nwhygraph render --open    # static, self-contained HTML\nwhygraph serve --open     # localhost viewer with on-demand rationale\n```\n\n`render` writes `.whygraph/whygraph.html` — a single self-contained file (Cytoscape.js vendored inline) with three tabs:\n\n- **Graph** — Cytoscape view of CodeGraph nodes/edges. Nodes are coloured by hierarchy level (Modules / Classes / Methods / Leaves); the slider buttons double as a legend. Cached rationale is shown as a green border. A **level slider** in the top bar controls how deep the graph displays — defaults to \"Modules\" for fast first paint. Edges aggregate up to the nearest visible ancestor when deeper levels are hidden. Click a node → side panel with top contributors (from blame), per-month activity, recent commits + linked PRs/issues, and the cached rationale card if any. Nodes deeper than the rendered `--depth` show a \"re-render with `--depth N`\" placeholder when clicked.\n- **Dashboard** — repo overview (commits/PRs/issues counts), top contributors over the last 90 days, hottest path-prefixes, monthly activity bars.\n- **Authors** — list of identities (resolved through the `authors` table); click → recent activity over the last 180 days.\n\n`serve` starts a localhost-only HTTP server (default `127.0.0.1:8765`) with the same UI plus a \"Generate rationale\" button on uncached nodes. The button calls `whygraph_rationale_brief` server-side (~30s on first call, then cached); subsequent `whygraph render` runs include the newly-cached rationale in the static dump.\n\n## Environment variables\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `WHYGRAPH_DB` | `\u003crepo\u003e/.whygraph/whygraph.db` | Where WhyGraph stores its evidence + rationale cache. Used by both the CLI and the MCP tools. |\n| `CODEGRAPH_DB` | `\u003crepo\u003e/.codegraph/codegraph.db` | CodeGraph SQLite location. Required for `qualified_name` targeting on `whygraph_evidence_for`. |\n| `ANTHROPIC_API_KEY` | unset | Honoured by the `claude` subprocess only when `--anthropic-key` is passed (or the equivalent tool argument). Not a runtime switch by itself. |\n\n## Layout\n\n```\n.\n├── src/whygraph/\n│   ├── cli.py                          # `whygraph` CLI (init, scan, version)\n│   ├── agents.py                       # agent registry + MCP snippet writers\n│   ├── assets.py                       # .claude/ asset installer (skip-if-exists + --force)\n│   ├── assets/claude-code/             # bundled Claude Code assets (shipped in the wheel)\n│   │   ├── agents/                     # planner / researcher / synthesizer / implementor\n│   │   ├── commands/                   # /rationale, /whygraph-plan, /whygraph-implement\n│   │   └── skills/                     # ask-why / plan-change / pre-edit / implement-plan\n│   ├── init.py                         # CodeGraph bootstrap (nvm + codegraph init -i)\n│   ├── mcp_server.py                   # FastMCP stdio server (resources/tools/prompts)\n│   ├── mcp_queries.py                  # composite SQL for the MCP layer\n│   ├── backend.py                      # GraphBackend Protocol + SqliteCodegraphBackend\n│   ├── llm_subprocess.py               # `claude` CLI invocation helpers\n│   └── scan/\n│       ├── runner.py                   # parallel crawler orchestration\n│       ├── git.py / github.py          # data sources\n│       ├── db.py                       # WhyGraph SQLite schema + migrations\n│       ├── scoring.py                  # TF-IDF + ValueGate\n│       ├── authors.py                  # identity dedup + resolver\n│       └── llm_descriptions.py         # per-commit diff-description phase\n├── tests/\n└── pyproject.toml                      # uv-managed\n```\n\n## Develop\n\n```bash\nuv sync                       # bootstrap .venv and install deps\nuv run pytest                 # full test suite\nuv run pytest tests/test_smoke.py::test_imports   # single test\nuv run whygraph version       # CLI sanity check\nuv run whygraph-mcp           # launch MCP server on stdio\n```\n\nIf `uv` fails with `UnknownIssuer` SSL errors off-VPN, prefix with `SSL_CERT_FILE= ` (works around a corp-only cert bundle) — this applies to `make` targets too, e.g. `SSL_CERT_FILE= make sync`.\n\nA `Makefile` wraps the common dev tasks; run `make` to list them — `make sync`, `make test`, `make scan`, `make db` / `make db-down`, `make inspect`.\n\n### Browse the databases\n\nWhyGraph is developed by running it against its own repo, so it helps to eyeball the two SQLite databases it touches — `.whygraph/whygraph.db` (its own evidence/rationale data) and `.codegraph/codegraph.db` (CodeGraph's symbol graph). `make db` brings up [DBGate](https://dbgate.org/) in Docker with both databases wired up as connections:\n\n```bash\ncp docker-compose.example.yml docker-compose.yml   # one-time; the copy is git-ignored\nmake db                                            # DBGate at http://localhost:8081\nmake db-down                                       # stop the viewer\n```\n\nBoth databases appear in the DBGate sidebar; the CodeGraph one is opened read-only since CodeGraph rewrites it on re-index. Toggle the dark theme in DBGate's Settings — it persists across restarts.\n\n### Debug the MCP server with MCP Inspector\n\nThe [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the official web UI for poking at a stdio MCP server — list tools, call them with custom args, see raw responses, tail stderr.\n\n```bash\nmake inspect                           # against this checkout\nmake inspect REPO=/path/to/other/repo  # against another repo's databases\n```\n\n`make inspect` needs Node ≥ 20 active — the same modern Node CodeGraph requires (`nvm use 22`). Open the printed `http://localhost:…` URL with the one-time auth token. Use **Reconnect** to pick up code changes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtrdesign%2Fwhygraph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtrdesign%2Fwhygraph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtrdesign%2Fwhygraph/lists"}