gitvisualise
Turn any GitHub repo into an interactive, animated, narrated architecture tour: on the website, from the command line, as a Claude Code skill, or as a GitHub Action. Zero dependencies, no API keys.
Interactive diagram requires JavaScript. Static summary below.
Components
- Website logic (entry): The website's brain. Reads a pasted link or a picked repo, shows progress, then plays the resulting tour. It runs entirely in the visitor's browser and writes to the page with textContent only, because repo text is untrusted.
site/app.js:172-192 - Website page (ui): The landing page: link box, account repo picker, optional token, progress view, and the sandboxed frame that plays the tour.
site/index.html:55-55, site/index.html:279-279 - CLI (entry): Command-line entry point. Parses the command (scan, generate, validate, build, all, serve), resolves a local path or GitHub URL, and runs the pipeline in order.
skills/repo-architecture/scripts/gitvisualise.mjs:57-73, skills/repo-architecture/scripts/gitvisualise.mjs:260-276 - Site builder (disk) (service): Node adapter that writes the static site to a folder: index.html plus the viewer script and styles.
skills/repo-architecture/scripts/lib/build.mjs:9-19 - Page renderer (service): Pure page rendering shared by the CLI and the website: embeds architecture data and code snippets, escapes repo text, adds a no-JavaScript summary, and can inline everything into a single file.
skills/repo-architecture/scripts/lib/core/build-core.mjs:68-76 - Path helpers (util): A minimal POSIX path library so the core code runs in a browser, where node:path does not exist.
skills/repo-architecture/scripts/lib/core/posix.mjs:2-2 - Scanner core (service): Pure scanner shared by the CLI and the website. Given file paths and a read function, it records facts only: resolved imports, entry points, routes and declared dependencies. Nothing is guessed.
skills/repo-architecture/scripts/lib/core/scan-core.mjs:298-304 - Text helpers (util): Tiny pure helpers (escaping, slugs, line counts, GitHub URL normalising) that run in both Node and the browser.
skills/repo-architecture/scripts/lib/core/text.mjs:2-2 - Validator rules (service): Pure rules that check architecture.json against a repository view: source paths exist with exact case, line ranges are in bounds, steps reference real nodes and edges, and file paths named in prose exist.
skills/repo-architecture/scripts/lib/core/validate-core.mjs:17-23, skills/repo-architecture/scripts/lib/core/validate-core.mjs:40-46 - Baseline generator (service): Builds a first architecture.json from scan facts: files or packages become nodes, imports become edges, and a walk from the entry point becomes a flow with templated narration.
skills/repo-architecture/scripts/lib/generate.mjs:42-48 - GitHub cloning (CLI) (service): Turns a GitHub URL, owner/repo shorthand or a local path into a directory on disk, shallow-cloning public repos into a cache.
skills/repo-architecture/scripts/lib/github.mjs:7-15, skills/repo-architecture/scripts/lib/github.mjs:23-29 - Merge (keeps your edits) (service): Merges a fresh baseline into an existing architecture.json by id. Items marked claude, manual or locked, and hand-placed positions, survive regeneration.
skills/repo-architecture/scripts/lib/merge.mjs:11-11, skills/repo-architecture/scripts/lib/merge.mjs:44-50 - Scanner (disk) (service): Node adapter: walks a folder, reads files and asks git for the commit, then hands everything to the shared scanner core.
skills/repo-architecture/scripts/lib/scan.mjs:37-45 - Node helpers (util): File-system and git helpers used only in Node: JSON I/O, exact-case path checks, argument parsing.
skills/repo-architecture/scripts/lib/util.mjs:44-48 - Validator (disk) (service): Node adapter that presents a folder on disk to the validator rules as a read-only view.
skills/repo-architecture/scripts/lib/validate.mjs:10-16 - Browser GitHub loader (service): Analyses a GitHub repo from a browser with no server: two API calls for the commit and file tree, then raw file downloads. It prefers a tour the repo authors published, and otherwise runs the shared scanner, generator and validator.
skills/repo-architecture/scripts/lib/web/github-loader.mjs:169-179 - Tour page template (ui): HTML shell for the tour: diagram canvas, player controls, narration card and detail panel. The page renderer fills in the data.
skills/repo-architecture/viewer/index.template.html:34-34 - Viewer engine (ui): Generic renderer and playback engine. Lays out nodes, animates flow steps, drives play/pause/step controls, and reads narration aloud with the browser speech synthesizer. It contains no project-specific code.
skills/repo-architecture/viewer/viewer.js:63-67, skills/repo-architecture/viewer/viewer.js:593-601 - Site assembler (config): Copies the website, the shared core and the viewer into docs/ so GitHub Pages serves one consistent site. CI fails if docs/ is stale.
tools/build-site.mjs:15-15 - Viewer styles (ui): Theme tokens for light and dark mode, responsive layout for phones, and reduced-motion handling.
skills/repo-architecture/viewer/viewer.css:120-120 - architecture.json (data): The single source of truth: nodes, edges, flows and narration, every entry backed by a source reference. Generated, then curated, then rendered.
skills/repo-architecture/reference/schema.md, docs/architecture/architecture.json - Browser speech synthesis (external): The Web Speech API built into the browser. It speaks narration with no server, key or cost.
skills/repo-architecture/viewer/viewer.js:410-410 - GitHub API + raw files (external): api.github.com supplies the commit and file tree; raw.githubusercontent.com supplies file contents. Both allow browser requests, so the site needs no backend.
skills/repo-architecture/scripts/lib/web/github-loader.mjs:12-13 - Claude Code skill (config): SKILL.md tells Claude Code how to inspect a repo, write grounded architecture data and narration, validate it, and preserve manual edits.
skills/repo-architecture/SKILL.md:15-15 - GitHub Action (config): A composite action that runs the CLI in any repo's workflow, so the tour regenerates on every push and can be deployed to Pages.
action.yml:49-49 - exchange.mjs (module): JavaScript file, 180 lines. Defines allowedOrigins, handle.
server/github-oauth/exchange.mjs:14-34 - worker.mjs (module): JavaScript file, 7 lines.
server/github-oauth/worker.mjs - config.js (module): JavaScript file, 10 lines. Defines OAUTH.
site/config.js:10-10 - diff-core.mjs (service): JavaScript file, 105 lines. Defines diffArchitectures.
skills/repo-architecture/scripts/lib/core/diff-core.mjs:21-41 - http-core.mjs (service): JavaScript file, 125 lines. Defines pathSegments, matchScore, matchRequests, usesHttpClient and 3 more.
skills/repo-architecture/scripts/lib/core/http-core.mjs:9-29 - lang-java.mjs (service): JavaScript file, 116 lines. Defines javaImports, javaPackage, javaSymbols, buildJavaIndex and 4 more.
skills/repo-architecture/scripts/lib/core/lang-java.mjs:16-36 - lang-rust.mjs (service): JavaScript file, 181 lines. Defines expandUse, rustImports, parseCargo, buildRustContext and 3 more.
skills/repo-architecture/scripts/lib/core/lang-rust.mjs:14-34 - cache.mjs (service): JavaScript file, 76 lines. Defines cacheKey, memoryStore, DATA_VERSION, createCache.
skills/repo-architecture/scripts/lib/web/cache.mjs:9-29 - idb-store.mjs (service): JavaScript file, 34 lines. Defines idbStore.
skills/repo-architecture/scripts/lib/web/idb-store.mjs:4-24 - oauth.mjs (service): JavaScript file, 64 lines. Defines newState, authorizeUrl, readCallback, cleanUrl and 1 more.
skills/repo-architecture/scripts/lib/web/oauth.mjs:14-34 - route.mjs (service): Pure URL-state helpers for the website, kept out of app.js so they can be unit tested without a DOM.
skills/repo-architecture/scripts/lib/web/route.mjs:9-29 - lang-kotlin.mjs (service): JavaScript file, 36 lines. Defines kotlinImports, kotlinPackage, kotlinSymbols, hasKotlinMain.
skills/repo-architecture/scripts/lib/core/lang-kotlin.mjs:5-25 - data-core.mjs (service): JavaScript file, 163 lines. Defines SQL_RE, PRISMA_RE, DATA_FILE_RE, parseSql and 3 more.
skills/repo-architecture/scripts/lib/core/data-core.mjs:5-25 - export-core.mjs (service): Pure exporters: architecture.json -> Mermaid or PlantUML text, so a tour can be pasted into a README, a wiki page or a pull request (GitHub renders Mermaid natively).
skills/repo-architecture/scripts/lib/core/export-core.mjs:16-36 - infra-core.mjs (service): Infrastructure view: the services a Docker Compose file declares, how they depend on each other, and which directory of the repository each one is built from.
skills/repo-architecture/scripts/lib/core/infra-core.mjs:9-29 - lang-c.mjs (service): C and C++: `#include "local.h"` is a path, searched relative to the including file, then in the project's include directories (from CMake's include_directories / target_include_directories, `-I` flags in Makefiles, an...
skills/repo-architecture/scripts/lib/core/lang-c.mjs:9-29 - lang-csharp.mjs (service): C#: `using` directives name namespaces, not files, so resolution goes through an index of the namespaces and types the repository itself declares.
skills/repo-architecture/scripts/lib/core/lang-csharp.mjs:10-30 - lang-dart.mjs (service): Dart: `import 'package:my_app/src/foo.dart'` names a package and a path inside its lib/ directory, and relative imports are plain paths.
skills/repo-architecture/scripts/lib/core/lang-dart.mjs:9-29 - lang-php.mjs (service): PHP: `use Vendor\Package\Class;` names a class by namespace.
skills/repo-architecture/scripts/lib/core/lang-php.mjs:10-30 - lang-ruby.mjs (service): Ruby: `require_relative` is a path relative to the file; `require` searches the load path, which we take to be the repository's `lib` directories, its root, and `app` / `src` (the usual Bundler and Rails layouts).
skills/repo-architecture/scripts/lib/core/lang-ruby.mjs:8-28 - languages.mjs (service): Language plug-ins. Each language that has an import graph is one entry in PLUGINS; the scanner knows nothing else about it.
skills/repo-architecture/scripts/lib/core/languages.mjs:36-56 - yaml-lite.mjs (service): JavaScript file, 145 lines. Defines parseYaml.
skills/repo-architecture/scripts/lib/core/yaml-lite.mjs:69-89 - watch.mjs (service): Helpers for `gitvisualise watch`: which changes matter, and a debouncer.
skills/repo-architecture/scripts/lib/watch.mjs:9-29 - analyse.mjs (service): The CPU-heavy half of analysing a repository: scan the downloaded files, generate the architecture and validate it.
skills/repo-architecture/scripts/lib/web/analyse.mjs:9-29 - analysis-worker.mjs (service): Web Worker entry: runs the analysis off the main thread.
skills/repo-architecture/scripts/lib/web/analysis-worker.mjs - narrate-ai.mjs (service): Optional, opt-in narration written by a language model with the visitor's OWN API key.
skills/repo-architecture/scripts/lib/web/narrate-ai.mjs:16-36 - pr-comment.mjs (module): JavaScript file, 110 lines. Defines MARKER, buildComment, NO_CHANGES_BODY, postComment and 1 more.
skills/repo-architecture/scripts/pr-comment.mjs:13-33 - extension.js (module): JavaScript file, 106 lines.
vscode-extension/extension.js - lib.js (module): JavaScript file, 59 lines.
vscode-extension/lib.js - bundle-skill.mjs (module): Copies the CLI and the viewer from skills/repo-architecture into vscode-extension/skill, so a packaged extension carries everything it needs (`vsce package` after `npm run prepare`).
vscode-extension/scripts/bundle-skill.mjs - run-in-vscode.mjs (module): Runs the extension inside a real VS Code (its Extension Host) against a throwaway workspace.
vscode-extension/scripts/run-in-vscode.mjs - motion.js (module): JavaScript file, 551 lines.
site/motion.js
Relationships
- CLI → Node helpers (parseArgs, readJSON, writeJSON and 3 more)
- CLI → Scanner (disk) (scanRepo)
- CLI → Baseline generator (generate)
- CLI → Merge (keeps your edits) (mergeArchitecture)
- CLI → Validator (disk) (validate)
- CLI → Site builder (disk) (build)
- CLI → GitHub cloning (CLI) (parseTarget, ensureClone)
- Site builder (disk) → Validator (disk) (diskView)
- Site builder (disk) → Page renderer (2 imports)
- Page renderer → Text helpers (esc)
- Scanner core → Path helpers (posix)
- Scanner core → Text helpers (countLines)
- Validator rules → Text helpers (countLines)
- Baseline generator → Path helpers (posix)
- Baseline generator → Text helpers (slug)
- Scanner (disk) → Node helpers (toPosix, readText, git and 2 more)
- Scanner (disk) → Scanner core (scanCore, makeIgnorer, IGNORE_DIRS)
- Node helpers → Text helpers (esc, slug, countLines and 1 more)
- Validator (disk) → Node helpers (existsExact, readText)
- Validator (disk) → Validator rules (validateCore)
- Browser GitHub loader → Scanner core (makeIgnorer, filterPaths, UNIT_EXT and 2 more)
- Browser GitHub loader → Validator rules (validateCore)
- Browser GitHub loader → Baseline generator (isExamplePath, TOOLING_RE)
- Claude Code skill → CLI (drives)
- GitHub Action → CLI (runs)
- CLI → architecture.json (writes)
- Site builder (disk) → Tour page template (reads)
- Site builder (disk) → Viewer engine (copies)
- Site builder (disk) → Viewer styles (copies)
- Viewer engine → architecture.json (renders)
- Viewer engine → Browser speech synthesis (speaks with)
- Website logic → Browser GitHub loader (analyses with)
- Website logic → Page renderer (renders with)
- Website logic → Viewer engine (plays it in)
- Browser GitHub loader → GitHub API + raw files (reads)
- Website page → Website logic (loads)
- Site assembler → Scanner core (publishes)
- worker.mjs → exchange.mjs (handle)
- Website logic → config.js (OAUTH)
- CLI → diff-core.mjs (diffArchitectures)
- Scanner core → http-core.mjs (extractApiCalls, usesHttpClient)
- Baseline generator → http-core.mjs (matchRequests)
- Browser GitHub loader → diff-core.mjs (diffArchitectures)
- route.mjs → Browser GitHub loader (parseRepoInput)
- CLI → export-core.mjs (EXPORT_FORMATS)
- CLI → watch.mjs (classifyChange, debounce)
- infra-core.mjs → Path helpers (posix)
- infra-core.mjs → yaml-lite.mjs (parseYaml)
- infra-core.mjs → Text helpers (countLines)
- lang-c.mjs → Path helpers (posix)
- lang-csharp.mjs → Path helpers (posix)
- lang-dart.mjs → Path helpers (posix)
- lang-php.mjs → Path helpers (posix)
- lang-ruby.mjs → Path helpers (posix)
- languages.mjs → lang-java.mjs (javaImports, javaPackage, javaSymbols and 5 more)
- languages.mjs → lang-kotlin.mjs (kotlinImports, kotlinPackage, kotlinSymbols and 1 more)
- languages.mjs → lang-csharp.mjs (csharp)
- languages.mjs → lang-ruby.mjs (ruby)
- languages.mjs → lang-php.mjs (php)
- languages.mjs → lang-c.mjs (c)
- languages.mjs → lang-dart.mjs (dart)
- Scanner core → languages.mjs (PLUGINS, PLUGIN_BY_EXT, PLUGIN_LANG_NAMES)
- Scanner core → infra-core.mjs (extractInfra)
- Scanner core → data-core.mjs (extractDataModel)
- Baseline generator → languages.mjs (PACKAGE_EXTS)
- Scanner (disk) → languages.mjs (PLUGIN_MANIFEST_SRC)
- watch.mjs → Scanner core (IGNORE_DIRS)
- analyse.mjs → Scanner core (scanCore)
- analyse.mjs → Validator rules (validateCore)
- analyse.mjs → Baseline generator (generate)
- analysis-worker.mjs → analyse.mjs (analyseSources)
- Browser GitHub loader → analyse.mjs (makeView, runAnalysis)
- Browser GitHub loader → languages.mjs (PLUGIN_MANIFEST_SRC)
- Browser GitHub loader → infra-core.mjs (COMPOSE_RE)
- Browser GitHub loader → data-core.mjs (DATA_FILE_RE)
- narrate-ai.mjs → Validator rules (validateCore)
- pr-comment.mjs → diff-core.mjs (diffArchitectures)
- extension.js → lib.js (1 imports)
- CLI → Browser GitHub loader (parseRepoInput)
- CLI → route.mjs (badgeMarkdown)
From repo to interactive site (CLI)
- The skill takes charge: When you ask for an interactive architecture, Claude Code loads the skill. It does not guess: it runs the command line tool one stage at a time and checks each result. The GitHub Action drives the very same tool from a workflow.
- Find the repository: The tool accepts a local folder or a GitHub address. For a GitHub repo it makes a shallow clone into a cache, so the same steps work on any public repository.
- Scan for facts: A thin adapter walks the folder and reads files, then the scanner core records what is provably there: which file imports which, where execution starts, and which libraries are declared. These facts are the only raw material for the diagram.
- Draft a baseline: From those facts the generator drafts nodes, edges and a first walkthrough starting at the entry point. It works with no AI and no API key, and Claude then improves the wording and the relationships.
- Keep human and Claude edits: Before saving, the merge step compares the draft with any existing file. Anything marked as curated or locked is kept, so regenerating after a code change never wipes out careful work.
- Check every claim: The validator opens the repository and confirms that every referenced file exists, every line range is real, and every step points at a real component. Anything invented fails here, before it reaches a reader.
- Build the static site: The builder produces plain files: a page with the data and code snippets inlined, plus the viewer script and styles. There is nothing to install or host beyond static files, so GitHub Pages works.
- The viewer draws it: In the browser, the viewer reads the embedded data and lays the components out in layers. It knows nothing about this project, which is why the same viewer works for any repository.
- Play and listen: Press play and each step highlights its components while the browser reads the narration aloud. You can pause, step, change speed, pick a voice, or click any component to see its code.
From a pasted link to a tour (website)
- You paste a link: You paste a GitHub link, or pick a repository from an account. The page runs entirely in your browser. There is no server of ours in the loop, which is why it costs nothing to host.
- Ask GitHub for the file tree: The loader makes two requests to the public GitHub API: one to pin the exact commit, and one for the complete file listing. Pinning the commit is what keeps every Open Source link pointing at the code you analysed.
- Download only what matters: It skips tests, examples, tooling config and anything ignored by the repo, then downloads the shallowest source files first, up to a cap. Files come from raw.githubusercontent.com, which does not count against the API limit.
- Prefer the authors' own tour: If the repository already publishes a curated tour, the loader uses that instead and checks its references against the real files. If they have drifted, you are told, rather than shown stale claims as fact.
- The same brain as the CLI: Otherwise the loader hands the downloaded files to one function that runs the very same scanner, generator and validator the command line uses, in a Web Worker so the page stays responsive. There is one implementation with two front ends, so the website and the CLI cannot disagree.
- Build one self-contained page: The page renderer embeds the data and code snippets, escapes anything that came from the repository, and inlines the viewer, producing a single HTML document you can also download.
- Play it in a sandbox: The tour plays inside a sandboxed frame with no access to the surrounding page. Repository text is untrusted, and if you added a token, this keeps it out of reach of anything a repository could contain.
- Keep it or share it: Copy a share link that re-runs the analysis for anyone who opens it, or download the finished page and the architecture data. When you want narration written from your actual code, add the skill or the action to your repository.
What 1.1 added
- Tracing a request from client to server: A fetch or axios call is only linked to a server route when the HTTP method agrees and every path segment matches, with path parameters as the only wildcards. The generator turns each match into an http edge with evidence on both the call and the route, plus a request tour.
- Comparing two revisions: The loader analyses both revisions with the same node granularity, and the diff marks each component and relationship as added, removed, changed or same by id. Removed items keep their evidence pinned to the older commit, so nothing is invented.
- Languages are plug-ins: Each language is one small object registered in one file. It parses imports, builds an index of the repository once, and resolves an import to a file that really exists. Anything that resolves to nothing is dropped rather than guessed.
- Caching and shareable links: The website stores each analysed tour in IndexedDB, keyed by commit, so a repeat visit costs one request. Route helpers turn a repository, a folder, a comparison or a tour step into a link and back.
- Optional sign-in: Signing in with GitHub needs a client secret, so the code-for-token exchange lives in a tiny stateless function that never logs. The site only shows the button when config.js turns it on.
How the code is wired
- Start at app.js: Execution starts at app.js. Entry point: conventional entry filename. Follow the highlighted connections to see how the rest of the code is wired together.
- app.js → config.js: app.js imports config.js — 1 import (OAUTH). JavaScript file, 10 lines.
- Not reached by imports: These modules are not reachable from the entry point through static imports: exchange.mjs, worker.mjs, index.html, motion.js, gitvisualise.mjs, build.mjs and 43 more. They may be loaded dynamically, run separately, or be unused.
Components by role
- Entry (2): 2 entry parts: app.js — Entry point: conventional entry filename; gitvisualise.mjs — Entry point: package.json "bin".
- Ui (2): 2 ui parts: index.html — landing; index.template.html — HTML file, 101 lines.
- Service (36): 36 service parts: build.mjs — Node adapter: builds the static site (index.html + viewer.js + viewer.css) on disk; build-core.mjs — Pure site building: snippets + page rendering; data-core.mjs — JavaScript file, 163 lines; diff-core.mjs — JavaScript file, 105 lines; and more.
- Module (11): 11 general parts: exchange.mjs — JavaScript file, 180 lines; worker.mjs — JavaScript file, 7 lines; config.js — JavaScript file, 10 lines; motion.js — JavaScript file, 551 lines; and more.