CodeTour
# CodeTour
Animated, LLM-driven **"explain like I'm five" tours of GitHub pull requests**.
CodeTour is an [MCP](https://modelcontextprotocol.io) server paired with a local browser
viewer. Claude (or any MCP-driving LLM) calls CodeTour's tools step by step; the viewer
animates through the pull request — file tree, diffs, pulsing line highlights — while the
narration is shown as captions and spoken aloud via the browser's built-in text-to-speech.
Every stop links back to GitHub so viewers can dig into the detail themselves.
## How it works
```
Claude ──(MCP stdio)──▶ codetour ──(WebSocket)──▶ your browser
│
└──(REST)──▶ GitHub API
```
1. The LLM calls `get_pr_info` / `get_file_diff` to read the PR through CodeTour, so its
narration matches exactly what is displayed.
2. `start_tour` opens the viewer in your browser and waits for you to click **Start**
(the click also enables audio).
3. `show_overview` and a series of `show_step` calls animate through the changes. Each
call blocks until the narration finishes speaking, so the tour paces itself naturally.
4. `end_tour` shows a closing summary with a link to the PR on GitHub.
## Installation
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
```sh
git clone <this repo> && cd CodeTour
uv sync
```
Register with Claude Code at **user scope**, so the tools are available in every repo:
```sh
claude mcp add --scope user codetour -- uv --directory /path/to/CodeTour run codetour
```
Then just ask:
> Give me an executive tour of https://github.com/owner/repo/pull/123
## The `codetour` skill
The repo ships a Claude Code skill ([skills/codetour/SKILL.md](skills/codetour/SKILL.md))
that teaches Claude the craft of a good tour: auto-detecting the current branch's PR via
`gh`, planning 3–7 stops before opening the viewer, ELI5 narration style rules, and how
to recover when the viewer is closed. Install it by linking (or copying) it into your
personal skills directory:
```sh
ln -s /path/to/CodeTour/skills/codetour ~/.claude/skills/codetour
```
With the skill installed, a plain "tour this PR" in any repo does the right thing.
Restart your Claude Code session after installing the MCP server or the skill.
## GitHub authentication
Public PRs work unauthenticated (low rate limit). For private repos or a higher limit,
CodeTour uses the first of: `GITHUB_TOKEN`, `GH_TOKEN`, or the `gh` CLI's stored token
(`gh auth login`).
## Configuration
| Env var | Default | Meaning |
| --- | --- | --- |
| `CODETOUR_PORT` | `8765` | Viewer port (probes upward if busy) |
| `CODETOUR_NO_BROWSER` | unset | Set to `1` to never auto-open the browser |
| `CODETOUR_MAX_FILES` | `300` | Max changed files fetched per PR |
| `CODETOUR_MAX_PATCH_BYTES` | `100000` | Per-file diff cap before truncation |
## Viewer controls
The tour plays itself as the LLM narrates, but the viewer can take over at any point:
| Control | Action |
| --- | --- |
| `⏸` / `▶`, or space | Pause or resume, mid-sentence |
| `‹` / `›`, or ← / → | Previous / next stop, at your own pace |
| Progress dots | Jump straight to a stop |
| `↻` | Replay the whole tour from the beginning |
| Voice menu | Choose the narration voice (remembered next time) |
| `🔊` | Mute or unmute the narration |
Navigating is local to the browser: it re-narrates the stop you land on and never
disturbs the LLM. If you browse backwards or pause while the LLM is still adding stops,
the view stays where you are and new stops simply extend the dots — the viewer keeps
acknowledging them so the LLM is never left waiting. Step forward to the newest stop and
the viewer follows along live again.
## Development
```sh
uv run pytest # unit tests, including the frontend harness
uv run ruff check . # lint
uv run codetour --demo # web viewer only, replays a canned tour on a loop
```
`tests/frontend/dom_harness.mjs` runs `app.js` under Node against a stub DOM to test the
viewer's navigation state machine without a browser (needs `node`; no npm packages). Run
it directly for a readable pass/fail list:
```sh
node tests/frontend/dom_harness.mjs
```
Demo mode is the quickest way to iterate on the frontend: it needs no MCP client and no
GitHub access — open the printed URL, click Start, and watch the canned tour.
## MCP tools
| Tool | Purpose |
| --- | --- |
| `get_pr_info(pr_url)` | PR metadata + per-file hunk line ranges (call first) |
| `get_file_diff(pr_url, path)` | Full parsed diff for one file |
| `start_tour(pr_url, tour_title?)` | Open the viewer, wait for Start |
| `show_overview(narration, key_points?)` | PR summary card, spoken |
| `show_step(file, narration, line_start?, line_end?, side?, style?)` | Animated stop on a file/lines |
| `end_tour(summary)` | Closing card with GitHub link |
| `tour_status()` | Diagnostics |
TDQS
Scored across 7 tools
Each tool has a distinctly different role: fetching PR metadata, fetching file diffs, starting the tour, showing overview/step/end screens, and checking diagnostics. No two tools overlap in purpose, making selection unambiguous.
Most tools follow a clear verb_noun pattern (get_pr_info, get_file_diff, start_tour, show_overview, show_step, end_tour). 'tour_status' is the one outlier, reading as a noun phrase rather than a verb-driven action.
Seven tools is well-scoped for a PR tour workflow: two for data retrieval, four for tour progression, and one for diagnostics. Each tool serves a necessary function without redundancy.
The tool surface covers the full tour lifecycle: retrieving PR context, reading diffs, starting the tour, showing overview and steps, ending cleanly, and diagnosing state. No obvious dead ends or missing operations for the stated purpose.