A local-first developer tool that performs static analysis on codebases (TypeScript, Go, Python), builds function-level call graphs, and renders them as interactive 3D visualizations. It detects dead code and unused parameters.
Requires Node.js 18+.
npm install -g @lemonberrylabs/codegraphOr run without installing:
npx @lemonberrylabs/codegraph analyze| Language | Requirement | Notes |
|---|---|---|
| TypeScript | None (built-in) | Uses the TypeScript Compiler API |
| Go | Go toolchain 1.24+ | Type-aware analysis with interface dispatch resolution |
| Python | Python 3.8+ | AST-based analysis via helper script |
Building from source? The Go helper binary is not shipped in the repo. The CLI auto-builds it on first run using your local Go toolchain. You can also build it manually:
cd src/analyzer/go/go-helper && go build -o go-helper .
# Analyze a project (auto-detects language)
codegraph analyze
# Analyze and open the 3D viewer
codegraph serve
# Analyze with live-reload on file changes
codegraph serve --watchCodeGraph auto-detects the language from project files (tsconfig.json/package.json for TypeScript, go.mod for Go, pyproject.toml/setup.py/requirements.txt for Python).
# Analyze a Next.js project, marking route handlers as entry points
codegraph serve -r ./my-app --include "src/**/*.ts" --entry "src/routes/**/*.ts"
# Analyze with a custom tsconfig
codegraph analyze --tsconfig ./tsconfig.build.jsonGo analysis uses golang.org/x/tools/go/packages for type-aware call graph construction. It resolves interface method calls to all concrete implementations — so when handler.ServeHTTP() is called through an http.Handler interface, edges are created to every type that implements ServeHTTP.
# Analyze a Go project with an entry point
codegraph serve -r /path/to/go/project -e internal/http/server.go
# Analyze with live reload — re-analyzes as you edit Go files
codegraph serve -r /path/to/go/project -e cmd/api/main.go --watchRequirements:
- Go 1.24+ on your
PATH - A valid
go.modin the project root (required for type-aware analysis) - Dependencies fetched (
go mod download— the analyzer loads packages via the Go build system)
If go.mod is missing or the project has compilation errors, the analyzer falls back to AST-only analysis (no interface dispatch, no cross-package type resolution).
What gets detected automatically:
main()andinit()functions are always entry pointsTestXxx,BenchmarkXxx, andExampleXxxfunctions are entry points- Exported vs unexported visibility
- Unused function parameters
codegraph serve -r ./my-python-app --include "src/**/*.py" --entry "src/main.py"Run static analysis and output a call graph JSON file.
codegraph analyze [options]| Option | Description |
|---|---|
-l, --language <lang> |
Language to analyze (typescript, go, python) |
-i, --include <patterns...> |
File glob patterns to include |
-x, --exclude <patterns...> |
File glob patterns to exclude |
-e, --entry <patterns...> |
Entry point file patterns |
-o, --output <path> |
Output JSON file path (default: ./codegraph-output.json) |
-c, --config <path> |
Path to config file |
--tsconfig <path> |
Path to tsconfig.json (TypeScript only) |
-r, --root <path> |
Project root directory (default: .) |
Run analysis and start the interactive 3D web viewer.
codegraph serve [options]Supports all analyze options, plus:
| Option | Description |
|---|---|
-p, --port <port> |
Server port (default: 8080) |
--no-open |
Do not auto-open browser (opens by default) |
--watch |
Re-analyze on file changes and live-update the viewer |
Example:
codegraph serve --watch --port 3000Place a codegraph.config.json (or codegraph.config.yaml) at the root of your project. CLI flags override config file values.
Entry points prevent externally-invoked functions from being falsely flagged as dead code. Any function reachable from an entry point through the call graph is considered "live."
| Type | Description | Example |
|---|---|---|
file |
All exported functions in matched files | { "type": "file", "pattern": "src/routes/**/*.ts" } |
function |
Specific function by name | { "type": "function", "name": "main" } |
decorator |
Functions with a matching decorator | { "type": "decorator", "name": "app.route" } |
export |
All exported symbols from matched files | { "type": "export", "pattern": "src/index.ts" } |
Go main(), init(), TestXxx, BenchmarkXxx, and ExampleXxx functions are automatically treated as entry points.
The viewer renders your call graph as an interactive 3D force-directed graph.
| Color | Meaning |
|---|---|
| Green/Gray | Live function — reachable from an entry point |
| Red | Dead code — no callers, unreachable from any entry point |
| Yellow | Has unused parameters |
| Orange | Dead code AND has unused parameters |
| Blue | Entry point (externally invoked) |
- Orbit — Click and drag to rotate
- Zoom — Scroll wheel
- Pan — Right-click drag or Shift+left-click drag
- Fly-to — Double-click a node to center on it
- Select — Click a node to view details in the side panel
- Multi-select — Ctrl/Cmd+click to add/remove from selection
| Key | Action |
|---|---|
/ or Ctrl+K |
Open search |
Escape |
Deselect all / close panels |
R |
Reset camera to overview |
F |
Toggle fullscreen |
1 |
Show all nodes |
2 |
Show only dead code |
3 |
Show only unused params |
4 |
Show only entry points |
H |
Toggle edge visibility |
L |
Toggle labels |
C |
Toggle cluster coloring (color by package) |
A |
Toggle auto-rotate |
Space |
Pause/resume force simulation |
Tab |
Cycle through flagged nodes |
? |
Show help overlay |
Press / to open fuzzy search across function names, file paths, and parameter names. The viewer also provides filter toggles for status, package, connection count, lines of code, visibility, and function kind.
The viewer can export:
- PNG screenshot of the current viewport
- JSON dead code report — list of all dead functions
- CSV dead code report — for spreadsheet import
- Markdown report — summary with tables
With --watch, the viewer live-updates when source files change. Changed files are re-analyzed, and the graph animates the updates — new nodes fade in, removed nodes fade out, color changes transition smoothly.
The analyze command produces a JSON file containing:
metadata— analysis timestamp, language, file/function/edge counts, timingnodes— all functions with name, file path, lines, parameters, status, and coloredges— all call relationships with source, target, call site location, and kindentryNode— virtual node representing external callersclusters— package/module groupingsstats— dead code and unused parameter summaries by package
git clone https://github.com/lemonberrylabs/codegraph.git
cd codegraph
pnpm installpnpm run build:cli # Build CLI (TypeScript → dist/)
pnpm run build:viewer # Production build for viewer (Vite → dist/viewer/)
pnpm run build # BothThere are three ways to run CodeGraph from source, depending on what you're working on:
Build the CLI once, then point it at any project:
pnpm run build:cli
node ./dist/bin/codegraph.js serve -r /path/to/projectRe-analyzes and pushes graph updates to the browser whenever target project files change. Use this when you're exploring a codebase and editing its source:
pnpm run build:cli
node ./dist/bin/codegraph.js serve -r /path/to/project -e main.go --watchThe browser graph updates automatically via WebSocket — no page refresh needed.
If you're developing CodeGraph itself (changing viewer code, analyzer logic, etc.), run two processes:
# Terminal 1 — Vite dev server with hot module reload (port 3000)
pnpm run dev:viewer
# Terminal 2 — Backend API server (port 8080)
pnpm run build:cli
node ./dist/bin/codegraph.js serve -r /path/to/project --no-open --watchOpen http://localhost:3000 — the Vite dev server proxies /api and /ws to the backend on port 8080. Viewer changes hot-reload instantly; analyzer changes require re-running pnpm run build:cli and restarting terminal 2.
The Go helper binary is built automatically on first use. To rebuild manually after making changes to src/analyzer/go/go-helper/main.go:
cd src/analyzer/go/go-helper
go build -o go-helper .Cross-compile for all platforms:
./scripts/build-go-helper.shpnpm run test # Run all tests
pnpm run typecheck # Type checking onlysrc/
├── cli/ # CLI commands (analyze, serve)
├── analyzer/
│ ├── base-analyzer.ts # Shared analyzer logic
│ ├── types.ts # Shared types
│ ├── ts/ # TypeScript analyzer (Compiler API)
│ ├── go/ # Go analyzer
│ │ ├── go-analyzer.ts # TypeScript orchestrator
│ │ └── go-helper/ # Go binary (type-aware analysis)
│ │ └── main.go # packages.Load + go/types + interface dispatch
│ └── python/ # Python analyzer
│ ├── py-analyzer.ts
│ └── py-helper/
├── viewer/ # Three.js 3D viewer (Vite app)
│ ├── main.ts
│ ├── scene/ # 3D rendering
│ ├── interaction/ # Mouse, keyboard, selection
│ ├── layout/ # Force-directed layout (Web Worker)
│ └── ui/ # Panels, search, filters
test/
├── fixtures/ # Test projects (go-basic, go-interfaces, ts-*, py-*)
└── analyzer/ # Analyzer test suites
MIT

{ "language": "typescript", "include": ["src/**/*.ts", "lib/**/*.ts"], "exclude": ["**/*.test.ts", "**/*.spec.ts"], // Entry points — functions invoked externally that should NOT be flagged as dead code. "entryPoints": [ { "type": "file", "pattern": "src/routes/**/*.ts" }, { "type": "function", "name": "main" }, { "type": "decorator", "name": "app.route" }, { "type": "export", "pattern": "src/index.ts" } ], "output": "./codegraph-output.json", // Language-specific options "typescript": { "tsconfig": "./tsconfig.json" }, "go": { "module": "", "buildTags": [] }, "python": { "pythonVersion": "3.10", "venvPath": "", "sourceRoots": [] } }