https://github.com/mtrdesign/whygraph
MCP server that gives Claude Code the rationale behind a symbol before editing - synthesized from git history, PRs, and call-graph context.
https://github.com/mtrdesign/whygraph
claude-code codegraph mcp-server
Last synced: 27 days ago
JSON representation
MCP server that gives Claude Code the rationale behind a symbol before editing - synthesized from git history, PRs, and call-graph context.
- Host: GitHub
- URL: https://github.com/mtrdesign/whygraph
- Owner: mtrdesign
- Created: 2026-05-04T12:50:40.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-21T21:03:23.000Z (about 1 month ago)
- Last Synced: 2026-05-21T21:12:15.133Z (about 1 month ago)
- Topics: claude-code, codegraph, mcp-server
- Language: Python
- Homepage:
- Size: 775 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# whygraph
Rationale layer over [CodeGraph](https://github.com/colbymchenry/codegraph): explains *why* code exists, not just what it does.
For 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.
> **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.
## Prerequisites
- **[uv](https://docs.astral.sh/uv/)** — Python toolchain. Installs Python 3.11+ automatically.
- **git** — repo history is the primary evidence source.
- **[`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.
- **Node ≥ 22** — required by CodeGraph (used for graph queries). `whygraph init` bootstraps this for you via nvm if needed.
- **`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.
## Quickstart
Install WhyGraph once (see [Installation](#installation) below), then in the repository you want to analyse:
```bash
# 1. Bootstrap CodeGraph (Node ≥ 22, then runs `codegraph init -i`).
whygraph init
# 2. Scan: walks git history, fetches PRs/issues, runs TF-IDF scoring,
# generates an LLM diff description per commit. Writes to
# .whygraph/whygraph.db in the current repo.
whygraph scan
# 3. Verify the MCP server can launch.
whygraph-mcp # Ctrl-C to exit
```
The full scan touches every commit on the default branch. On large or remote-heavy repos you may want to bound the LLM phase only:
```bash
# Run scan + LLM only on the 50 most recent commits. Other phases
# (git crawl, GitHub fetch, TF-IDF scoring) still cover full history.
whygraph scan --llm-recent 50
```
## Installation
WhyGraph 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 ` wires up each individual project so its agent can launch the MCP server.
Pick whichever install path fits where the project is in its lifecycle:
### From PyPI (stable releases)
```bash
uv tool install whygraph # or: pipx install whygraph
```
> **Status:** WhyGraph is not yet published to PyPI. Use one of the GitHub or local-checkout paths below until v1 ships.
### From GitHub (latest / pre-release)
For unreleased features on `main`, a specific feature branch, or a tag:
```bash
# Latest from main:
uv tool install "git+https://github.com/cvetty/whygraph.git"
# A specific branch (e.g. an in-flight feature):
uv tool install "git+https://github.com/cvetty/whygraph.git@feature/scan-and-scoring"
# A specific tag (once tagged):
uv tool install "git+https://github.com/cvetty/whygraph.git@v1.3.0"
```
Re-running upgrades in place. To switch refs, add `--force` (or `uv tool uninstall whygraph` first). `pipx` accepts the same `git+https://…` URLs.
### From a local checkout (contributors)
```bash
git clone https://github.com/cvetty/whygraph.git
uv tool install --editable ./whygraph
```
`--editable` lets your local edits show up immediately, without reinstalling.
### Verify
```bash
whygraph version
which whygraph-mcp
```
Both should resolve to the global tool install (under `~/.local/bin/` or `uv`'s shim directory).
### Wire each project
```bash
cd /path/to/your-project
whygraph init --agent claude # Claude Code: writes .mcp.json + drops bundled assets in .claude/
```
`whygraph init --agent claude` writes `.mcp.json` at the repo root and copies the bundled agent / command / skill markdown into `/.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.
### Migration from the Claude Code plugin
Earlier 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:
```
# In your Claude Code session:
/plugin uninstall whygraph@whygraph
/plugin marketplace remove whygraph
# Then in each project where you want WhyGraph:
whygraph init --agent claude
```
## Wire WhyGraph into your editor
WhyGraph'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.
Run from the repo you want WhyGraph to analyse:
```bash
whygraph init # DB only, no agent wiring (safe default)
whygraph init --agent claude # writes .mcp.json + populates .claude/
whygraph init --agent cursor # writes .cursor/mcp.json
whygraph init --agent vscode # writes .vscode/mcp.json (alias: copilot)
whygraph init --agent codex # prints snippet for ~/.codex/config.toml
whygraph init --agent claude-desktop # prints snippet for Claude Desktop config
whygraph init --agent X --print # prints the MCP snippet, never writes it
whygraph init --agent claude --no-install-assets # MCP only, skip .claude/ copy
whygraph init --agent claude --force # overwrite existing .claude/* files
whygraph init --list-agents # show all supported agents + paths
```
**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.
`--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.
## CLI commands
| Command | Purpose |
|---|---|
| `whygraph version` | Print installed package version. |
| `whygraph init [-y]` | Bootstrap CodeGraph in the current repo. Detects/installs Node ≥ 22 via nvm if needed, then runs `codegraph init -i`. |
| `whygraph scan` | Walk first-parent history and populate `.whygraph/whygraph.db`: commits + GitHub PRs/issues + TF-IDF scoring + per-commit LLM diff descriptions. Idempotent. |
| `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. |
| `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. |
| `whygraph-mcp` | Launch the FastMCP stdio server. Referenced by the `.mcp.json` files `whygraph init --agent X` writes into each project. |
### `whygraph scan` flags
| Flag | Default | Purpose |
|---|---|---|
| `--no-score` | off | Skip TF-IDF scoring after data collection. |
| `--no-llm-description` | off | Skip the per-commit LLM diff-description phase entirely. |
| `--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. |
| `--llm-workers N` | `4` | Parallel `claude` subprocesses in the LLM phase. |
| `--llm-recent N` | unbounded | Limit the LLM phase to the most recent N commits on the default branch. Other phases still cover full history. |
| `--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. |
## MCP surface
The `.mcp.json` written by `whygraph init --agent claude` (and the equivalents for other agents) launches `whygraph-mcp`, which registers:
### Resources
- `whygraph://repo/overview` — counts, scan freshness, scoring + LLM coverage, top contributors.
- `whygraph://commit/{sha}` — full commit row + linked PRs + closing issues.
- `whygraph://pr/{number}` — full PR row + closing issues.
- `whygraph://issue/{number}` — full issue row + closing PRs.
### Tools
- **`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.
- **`whygraph_search`** — LIKE-match query across commits/PRs/issues, ranked by TF-IDF.
- **`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).
- **`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.
- **`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.
### Prompts
Orchestration recipes that wire the tools above into common workflows:
- `explain_change` — pre-edit rationale for a code chunk.
- `debug_history` — find historical candidate causes for a bug symptom.
- `team_pulse` — per-author + per-path velocity over a rolling window.
- `changelog(since, until, scope?)` — themed markdown changelog of merged PRs in a date window.
- `feature_timeline(since, until)` — Mermaid `timeline` of merged PRs and issues opened in the window.
- `user_profile(identity, since, until)` — per-user contribution profile (commits, PRs, areas owned, issues closed).
- `whygraph_plan(task)` — composes search → CodeGraph (for symbol resolution) → rationale_brief into an ordered implementation plan.
### Composition with CodeGraph
WhyGraph deliberately does not expose graph-traversal tools. The split:
| Layer | Owns |
|---|---|
| **CodeGraph** (its MCP server / Claude's Explore agent) | "what is connected to what" — `findUsages`, `getCallers`, `find_symbols`, type hierarchy |
| **WhyGraph** | "why does this exist + when did it change" — evidence, rationale, windowed analytics |
The `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.
### Slash command
`/whygraph-plan [--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/`:
- **`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.
- **`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`).
- **`whygraph-synthesizer`** — fan-in combiner. Folds the three reports into the final plan markdown with a confidence floor = lowest researcher confidence.
Auto-mode heuristic: single-pass when working set < 5 nodes OR > 60% of rationale cards are empty/low-confidence; fan-out otherwise. `--shallow` and `--deep` override.
### Skill
`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.
## HTML viewer
```bash
whygraph render --open # static, self-contained HTML
whygraph serve --open # localhost viewer with on-demand rationale
```
`render` writes `.whygraph/whygraph.html` — a single self-contained file (Cytoscape.js vendored inline) with three tabs:
- **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.
- **Dashboard** — repo overview (commits/PRs/issues counts), top contributors over the last 90 days, hottest path-prefixes, monthly activity bars.
- **Authors** — list of identities (resolved through the `authors` table); click → recent activity over the last 180 days.
`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.
## Environment variables
| Variable | Default | Purpose |
|---|---|---|
| `WHYGRAPH_DB` | `/.whygraph/whygraph.db` | Where WhyGraph stores its evidence + rationale cache. Used by both the CLI and the MCP tools. |
| `CODEGRAPH_DB` | `/.codegraph/codegraph.db` | CodeGraph SQLite location. Required for `qualified_name` targeting on `whygraph_evidence_for`. |
| `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. |
## Layout
```
.
├── src/whygraph/
│ ├── cli.py # `whygraph` CLI (init, scan, version)
│ ├── agents.py # agent registry + MCP snippet writers
│ ├── assets.py # .claude/ asset installer (skip-if-exists + --force)
│ ├── assets/claude-code/ # bundled Claude Code assets (shipped in the wheel)
│ │ ├── agents/ # planner / researcher / synthesizer / implementor
│ │ ├── commands/ # /rationale, /whygraph-plan, /whygraph-implement
│ │ └── skills/ # ask-why / plan-change / pre-edit / implement-plan
│ ├── init.py # CodeGraph bootstrap (nvm + codegraph init -i)
│ ├── mcp_server.py # FastMCP stdio server (resources/tools/prompts)
│ ├── mcp_queries.py # composite SQL for the MCP layer
│ ├── backend.py # GraphBackend Protocol + SqliteCodegraphBackend
│ ├── llm_subprocess.py # `claude` CLI invocation helpers
│ └── scan/
│ ├── runner.py # parallel crawler orchestration
│ ├── git.py / github.py # data sources
│ ├── db.py # WhyGraph SQLite schema + migrations
│ ├── scoring.py # TF-IDF + ValueGate
│ ├── authors.py # identity dedup + resolver
│ └── llm_descriptions.py # per-commit diff-description phase
├── tests/
└── pyproject.toml # uv-managed
```
## Develop
```bash
uv sync # bootstrap .venv and install deps
uv run pytest # full test suite
uv run pytest tests/test_smoke.py::test_imports # single test
uv run whygraph version # CLI sanity check
uv run whygraph-mcp # launch MCP server on stdio
```
If `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`.
A `Makefile` wraps the common dev tasks; run `make` to list them — `make sync`, `make test`, `make scan`, `make db` / `make db-down`, `make inspect`.
### Browse the databases
WhyGraph 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:
```bash
cp docker-compose.example.yml docker-compose.yml # one-time; the copy is git-ignored
make db # DBGate at http://localhost:8081
make db-down # stop the viewer
```
Both 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.
### Debug the MCP server with MCP Inspector
The [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.
```bash
make inspect # against this checkout
make inspect REPO=/path/to/other/repo # against another repo's databases
```
`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.