Repowise / languages
Code analysis by language: 42 languages in one graph
repowise supports 42 languages on a five-rung ladder, 28 of them parsed to an AST. Every language in a repository lands in one graph, so dead code, call graphs, code health and git history (hotspots, ownership, co-change) run in one pass across a polyglot codebase, with framework-aware entry points and zero LLM calls.
Last reviewed: November 2026
Five-rung ladder
42 languages, and what each tier gets
The top three rungs (28 languages) are parsed to an AST. Tier names match the open-source language support reference.
| Tier | Languages | What you get |
|---|---|---|
| Full (15) | Python, TypeScript, JavaScript, Svelte, Vue, Astro, Java, Kotlin, Go, Rust, C++, C#, Scala, Ruby, Apex | AST symbols, import resolution, a resolved call graph, inheritance, docstrings, framework edges and the full health suite |
| Good (11) | C, Swift, PHP, Dart, Object Pascal, COBOL, GDScript, VB.NET, Elixir, F#, Objective-C | Symbols, imports, call graph and inheritance; health is partial (PHP, Dart and Object Pascal get markers, C, Swift, COBOL, F# and Objective-C get complexity) |
| Partial (2) | Luau, Razor | Luau: symbols and require() resolution, no health. Razor: component symbols, call edges from @code and tags, C# health, no import edges |
| Lightweight (6) | Clojure, Haskell, Lean 4, Erlang, HTML, QML | A real file-to-file import graph, no symbol-level claims |
| Structural (8) | R, Zig, Julia, Elm, OCaml, Crystal, Nim, D | Git history only: blame, hotspots, co-change, ownership, bug history |
Per-language pages
What repowise detects, language by language
Polyglot repositories
Find dead code across a polyglot codebase
How do I find unused code across multiple languages in one repo?
Run one tool over one graph instead of one tool per language. Single-language tools (Vulture for Python, Knip for TypeScript, staticcheck and deadcode for Go, the rustc lint, Roslyn analyzers for C#, PMD and detekt on the JVM) are good inside their ecosystem, and each sees only its own files. In a repository with a Python API, a TypeScript frontend and a Go worker, that is three tools, three output formats and three confidence models, and none of them knows when a file in another language reaches the code.
repowise indexes every language into one graph per repository, then runs a single dead-code pass with the same rules everywhere:
- Framework-aware entry points. Django URLconfs, FastAPI routers, Spring beans, Next.js routes, ASP.NET controllers, Rails routes, Laravel providers, Flutter routes, JCL steps and more are roots, so framework wiring is not reported as dead.
- Confidence from git history. An unreachable file untouched for a year starts at 1.0, one edited in the last 90 days at 0.4. Dynamic loading (importlib, require.context, Class.forName, dlopen, const_get and peers) caps nearby files at the review tier.
- A deletion-readiness gate. Only unused exports at 0.7 or higher are marked safe_to_delete, and only when the symbol is unused in its own file too, the path carries no runtime-load risk, it is not docs or example code, and the language has full import resolution. Unreachable files, zombie packages and unused internals stay review findings.
- History and health on the same graph. Each finding names the file's primary owner; hotspots, co-change and the health score sit on the same files.
- No LLM, runs offline. The whole pass is deterministic and local.
uv tool install repowise
repowise init --yes --no-prose
repowise dead-code # every language, one report
repowise dead-code --min-confidence 0.7 --safe-only # deletion-ready only
repowise dead-code --format json > dead-code.json # for CI or an agentCoding agents get the same findings through the get_dead_code MCP tool: get_dead_code(tier="high", safe_only=True) returns the deletion-ready list with confidence, reason, evidence and owner, so Claude Code, Codex or Cursor can delete with a reason attached.
Which cross-language links count inside one repository
These edges exist in single-repository mode, so code reached only from another language is not reported:
- Java, Kotlin and Scala
- One JVM package index, so a Java class used only from Kotlin is reached.
- Svelte, Vue and Astro
- Component scripts are projected to TypeScript and resolve through the TypeScript resolver.
- Razor and Blazor
- C# regions are parsed with the C# grammar.
- Apex and Salesforce metadata
- LWC, Aura, Visualforce, Flows and object metadata link to Apex classes and methods.
- COBOL, JCL, BMS and CICS CSD
- JCL steps, CSD definitions and CICS maps link to the programs and mapsets they name.
- Terraform and Lambda handlers
- aws_lambda_function handler strings link to the handler source file.
- SQL and dbt
- ref() and source() resolve to models when the repository has a dbt_project.yml.
What is not linked inside one repository: an HTTP call from one language to a route served by another. A TypeScript fetch to a FastAPI endpoint is not a graph edge. That rarely produces a false finding, because route handlers are framework entry points already. Across repositories, a repowise workspace matches HTTP, gRPC, topic and OpenAPI contracts, and a finding another repository consumes drops to 30 percent of its confidence and names the consumer.
When per-language tools are the better pick
In a single-language repository, the native tool usually wins on precision: rustc and the Go deadcode tool use the compiler's view, Knip can delete what it finds, and IDE inspections run as you type. Use them there. repowise earns its place when the repository mixes languages, when framework entry points cause false positives, when an agent needs ranked findings it can act on, or when you want history and health next to the cleanup list.
Questions
What people ask before they try it.
What is the fastest way to find unused code in a multi-language repository?
Index the repository once and run one dead-code pass over the shared graph. With repowise: repowise init --yes --no-prose, then repowise dead-code. Every language with import resolution lands in the same graph, so the report lists unreachable files, unused exports and zombie packages for Python, TypeScript, Go, Java and the rest together, each with a 0 to 1 confidence, a reason, and the file's owner. Keep the native tool per language (Vulture, Knip, staticcheck) for in-editor checks.
How many languages does repowise support?
42 on a five-rung ladder: 15 Full, 11 Good, 2 Partial, 6 Lightweight and 8 Structural. 28 of them (Full, Good and Partial) are parsed to an AST. Lightweight languages get a file-level import graph, and Structural languages get git history only.
Does a TypeScript fetch call to a Python API route count as a use?
Route handlers are framework entry points (FastAPI, Django, Flask, Express, Spring, ASP.NET and others), so they are never reported as dead. Across repositories, a repowise workspace matches HTTP, gRPC, topic and OpenAPI contracts, and a dead-code finding that another repository consumes drops to 30 percent of its confidence and names the consumer.
Which languages get deletion-ready findings?
Unused exports are marked safe to delete under a strict bar, so an agent can delete them without a second look: confidence 0.7 or higher, unused in their own file too, on a path with no runtime-load risk, outside docs and example code, in a language with full import resolution where fewer than half the repository's call edges in that language are guesses. Scala, Apex, Razor and the partial-import languages get ranked review findings with a confidence, a reason and an owner. COBOL files and programs are protected from dead-code reports.
Does it need an LLM or network access?
No. Parsing, graphs, dead code, health and git analysis make zero LLM calls. The COBOL and Apex grammars download on first use, and can be staged for air-gapped machines with repowise grammars fetch and REPOWISE_GRAMMAR_DIR.
Index a polyglot repository.
Public repositories are free on repowise.dev. The CLI is open source and runs on your machine with no API key.