Capabilities
Supported Languages
The 15 languages Bumpkit reads, what each one gets in blast radius, release checks, test skeletons and cross-repo impact, and the known limits per language.
Bumpkit reads 15 languages: Go, TypeScript and JavaScript, Python, Ruby, PHP, Java, Kotlin, Scala, C#, Dart, Elixir, Rust, C, C++ and Swift. TypeScript and JavaScript count as one language: they share one analyzer and get the same support. This page shows what each language gets, and where support is partial.
Beta. Blast radius, release checks, behavior checks, test evolution, code quality and cross-repo impact are Beta features in early access. If your workspace isn't on the list yet, the dashboard shows an early-access page where you can sign up. See Release Checks & Blast Radius, Code Quality & Architecture and Cross-Repo Impact.
"Yes" means Bumpkit does it for that language. "Limited" means it works with a gap described in the notes below the table. "No" means it doesn't.
Code graph features
These features read your code at --head as a graph of what calls what: bumpkit blast-radius, bumpkit predict, bumpkit history, bumpkit rollback, the blast_radius findings in bumpkit check and bumpkit gate, bumpkit tests and bumpkit quality.
| Language | Extensions | Blast radius and code graph | Test skeletons (bumpkit tests) |
Code quality (bumpkit quality) |
Cross-repo impact (service graph) |
|---|---|---|---|---|---|
| Go | .go |
Yes | Yes | Yes | Yes |
| TypeScript and JavaScript | .ts, .tsx, .mts, .cts, .js, .jsx, .mjs, .cjs |
Yes | Yes | Yes | Yes |
| Python | .py |
Yes | Yes | Yes | Yes |
| Ruby | .rb, .rake, .ru |
Yes | Yes | Limited ³ | Yes |
| PHP | .php |
Yes | Yes | Limited ³ | Yes |
| Java | .java |
Yes | Yes | Limited ³ | Yes |
| Kotlin | .kt, .kts |
Yes | Yes | Limited ³ | Yes |
| Scala | .scala, .sc |
Yes | Yes | Limited ³ | Yes |
| C# | .cs |
Yes | Yes | Limited ³ | Yes |
| Dart | .dart |
Yes | Yes | Limited ³ | Yes |
| Elixir | .ex, .exs |
Yes | Yes | Limited ³ | Yes |
| Rust | .rs |
Yes | Yes | Limited ³ | Yes |
| C | .c, .h |
Limited ¹ | Yes | Limited ³ | Yes |
| C++ | .cc, .cpp, .cxx, .hpp, .hh, .hxx, and .h files that contain C++ |
Limited ¹ | Yes | Limited ³ | Yes |
| Swift | .swift |
Limited ² | Yes | Limited ³ | Yes |
- C and C++ blast radius is limited. In large, template-heavy C++ headers (single-header libraries and test frameworks, for example), some callers don't show up. Plain C files are much less affected. Release checks are unaffected: they read the diff lines, not the graph.
- Swift blast radius is limited. A few Swift calls are missed, and very slow-to-read files are left out of the graph. Release checks are unaffected.
- Code quality is limited. Architecture drift (module cycles, layer rules, fan-out) and the code-quality analyses (copied code, single-implementation interfaces, pass-through functions, unused symbols, function size, comment-heavy files) read every supported language. The performance analyses (queries inside loops, blocking IO and unbounded work on code reached from HTTP handlers) are tuned for Go, TypeScript, JavaScript and Python, and find little or nothing in other languages.
With bumpkit tests --coverage, the coverage profile must be a Go cover profile. In other languages, a function counts as tested when a test refers to it by name.
Release checks
These checks run in bumpkit check, bumpkit gate and POST /v1/checks. They read the changed lines of the diff, so they work the same on every file of a language, however large. See Checkers and finding kinds.
| Language | Public API (exports) |
HTTP routes (routes) |
Env vars (config) |
Dependency manifests (dependencies) |
Vulnerability lookup (vulnerabilities) |
Behavior checks |
|---|---|---|---|---|---|---|
| Go | Yes | Yes | Yes | Yes: go.mod |
Yes | Yes |
| TypeScript and JavaScript | Yes | Yes | Yes | Yes: package.json |
Yes | Yes |
| Python | Yes | Yes | Yes | Limited ⁴: requirements*.txt |
Yes | Yes |
| Ruby | Yes | Yes | Yes | Yes: Gemfile, *.gemspec |
No | Yes |
| PHP | Yes | Yes | Yes | Yes: composer.json |
No | Yes |
| Java | Yes | Yes | Yes | Limited ⁵: build.gradle, build.gradle.kts, *.versions.toml, pom.xml |
No | Yes |
| Kotlin | Yes | Yes | Yes | Yes: same as Java | No | Yes |
| Scala | Yes | Yes | Yes | Yes: *.sbt, plus the Java manifests |
No | Yes |
| C# | Yes | Yes | Yes | Yes: *.csproj, *.props, packages.config |
No | Yes |
| Dart | Yes | Yes | Yes | Yes: pubspec.yaml |
No | Yes |
| Elixir | Yes | Yes | Yes | Yes: mix.exs |
No | Limited ⁶ |
| Rust | Yes | Yes | Yes | Yes: Cargo.toml |
Yes | Yes |
| C | Yes | No | Yes | Yes: CMakeLists.txt, conanfile.txt, conanfile.py, vcpkg.json |
No | Yes |
| C++ | Yes | No | Yes | Yes: same as C | No | Yes |
| Swift | Yes | Yes | Yes | Yes: Package.swift |
No | Yes |
- Python's release dependency check reads
requirements*.txtfiles only.pyproject.tomldependencies aren't checked there, although cross-repo impact reads them. - In
pom.xml, the release dependency check sees<x.version>properties only, because a<dependency>block spans several lines. Gradle files and version catalogs are read in full, and cross-repo impact parses full poms. - Elixir's
if ... doguard checks are skipped by design. Removedraise,rescuehandling and validation calls are still reported.
Vulnerability lookups use the OSV database for Go modules, npm, PyPI and crates.io packages. The other ecosystems aren't looked up yet.
Migration, secret, sensitive-area and untested-change checks don't depend on the language. Migration rules cover SQL and the Rails and Django migration APIs. Laravel Schema:: calls, EF Core migrationBuilder calls and Ecto's remove, rename and modify are recognized as new migrations, but their drops and renames aren't scored yet.
Large repositories
Bumpkit reads each file once. After the first run, it reads only the files that changed, so the next check on the same repository is fast even in a large monorepo.
Measured on an Apple M1 Pro (10 cores, 16 GB memory) with the cache on local disk. Times for public repositories are the median of five runs; times for the synthetic repository are the average of five.
| Repository | Files analyzed | First run | Same commit again | One file changed | Peak memory |
|---|---|---|---|---|---|
| Synthetic monorepo (Go, TypeScript, Python) | 50,003 | 1.6 s | 0.19 s | 0.69 s | 627 MiB |
kubernetes/kubernetes at 3c690c1 |
9,200 | 1.5 s | 0.32 s | 1.2 s | 695 MiB |
microsoft/vscode at 11ba54a |
10,515 | 2.9 s | 0.28 s | 1.9 s | 1.4 GiB |
Kubernetes has 31,647 files at that commit. Besides the 9,200 analyzed, 8,917 are vendored, build output or test files, 13,482 aren't in a supported language, 2 are over 1 MB, 5 are symlinks, and 41 are go.mod files that Bumpkit reads to find module paths. "One file changed" includes rebuilding the call graph across the whole repository, which is most of that time in large repositories.
Files Bumpkit doesn't analyze
Every blast radius report says which files it left out, with the same wording in bumpkit blast-radius, in the notes field of the blast_radius MCP tool and its --json output, and in the dashboard:
- Files over 1 MB, for example
4 files over 1 MB not analyzed. - Test, vendored or build output files: files under
vendor,node_modules,third_party,dist,build,testdata,test,tests,__tests__,coverage,.next,__pycache__,site-packagesand virtual environments, plus.min.jsand.d.tsfiles and test files. - Other files: anything not in a supported language, like images, Markdown, YAML or code in other languages, for example
12 other files not analyzed. - Files that failed to parse.
- Symlinks and submodules, for example
2 symlinks or submodules not analyzed. A submodule is its own repository, so add it to Bumpkit separately.
When a change reaches more callers than a report can hold, the report also says Some callers were left out to keep the report bounded; every area listed is still reached.
Known limits by language
Go
- Public API is exported names outside
internalandcmddirectories. - HTTP routes are
HandleandHandleFunccalls and router methods such as.Get("/x"). bumpkit verifycalls each changed exported Go function with the same generated inputs at both versions. That comparison is Go only.
TypeScript and JavaScript
- Public API is
exportdeclarations. Type declarations (.d.ts) and minified files are skipped by the code graph. - HTTP routes are Express-style router calls (
.get("/x"),.post,.all) and Next.jsapp/**/routeandpages/apifiles. - Calls on values of unknown type are matched by method name and shown as "matched by name", which lowers a blast-radius finding's confidence to medium.
Python
- Public API is top-level
defandclass. - HTTP routes are decorators such as
@app.get("/x")and@bp.route("/x"). - Dependencies: see note 4.
Ruby
- Methods after
privateorprotected(orprivate def) aren't public API. Files underbin,exe,script,config,db,vendorandlib/tasksaren't public API. - HTTP routes: Rails (
get,post,resources,resource,match), Sinatra and Grape. - Postfix guards (
return if x) andunlessaren't read as guards yet. - Rails migrations under
db/migrateare checked with the migration rules (drop_table,remove_column,rename_columnand raw SQL).
PHP
privateandprotectedmembers aren't public API, and neither are Blade templates or files underbin,config,database,bootstrap,public,resources,routesandvendor.- Parameters are compared by name, because named arguments make a rename breaking. A type change alone isn't reported.
- HTTP routes: Laravel
Route::calls, Slim and Lumen$app->get(...), and Symfony#[Route]attributes. - Laravel and Doctrine migrations are recognized, but
Schema::drop,dropColumnandrenameColumnaren't scored yet.
Java, Kotlin and Scala
- Calls resolve across all three languages. Overloads share one name, so a call reaches every overload of that name.
- JVM sources all start with
src/main, so setgate.blast_radius.approve_areasto package words (for example[owner, billing]) to get useful area names. - HTTP routes: Spring mapping annotations, JAX-RS
@Path, Micronaut, Ktor and Play's Scala and Java routing DSLs. Play'sconf/routesfile, Akka and Pekko HTTP, and http4s aren't read. Class-level prefixes aren't joined to method paths. - A Kotlin or Scala parameter list that spans several lines is compared only on its first line, and a Scala
def x: Intgaining a parameter list isn't reported as a signature change. - Projects whose package path contains
samplesorexampleare skipped by the release checks, like other sample code. - Liquibase changelogs and Flyway Java migrations aren't checked. Flyway
V1__name.sqlfiles are.
C#
- Properties, fields, events, operators, indexers and anything
internal,privateorprotectedaren't public API. Generated files and EF Core migrations aren't either. - A parameter list that spans several lines is compared only on its first line.
- HTTP routes: MVC
[HttpGet]-style and[Route]attributes, and minimal APIs (MapGet,MapPost,Map,MapMethods). An[HttpGet]with no template isn't reported, and[Route]andMapGroupprefixes aren't joined to the action's template. - With central package management, a version change shows up in
Directory.Packages.props, where the version lives.
Dart
- Public API is names without a leading
_, in files underlib. Generated files (.g.dart,.freezed.dartand similar) aren't public API. - Named parameters and signatures that
dart formatsplits over several lines aren't compared. - HTTP routes: shelf_router and
@Routeannotations. dart_frog file routes aren't read, and Flutter apps have no HTTP routes. - SDK, path and git dependencies without a version aren't reported.
Elixir
- Public API is
def,defmacro,defguard,defdelegateand modules in files underlib. Signatures are compared by arity. - Calls on variables and Erlang modules aren't linked in the code graph, and
usemacros aren't expanded. - HTTP routes: Phoenix and Plug.Router. A
scope "/prefix"isn't joined to the path, so moving a route into a new scope reads as one removed and one new route. - Behavior checks: see note 6. Ecto
drop table(...)is reported, butremove,renameandmodify ... null: falsearen't scored yet.
Rust
pub(crate),pub(super)andpub(in ...)items aren't public API, and neither is code insrc/main.rs,src/bin,build.rs,examples,benches,tests,fuzzorxtask.- Tests inside
#[cfg(test)] mod testsare left out of the code graph. - With axum-style
.route("/x", get(h)), the route's method is shown asANY. - A Cargo
0.xminor bump (0.6 to 0.7) is reported as a version change, not as a major upgrade.
C and C++
- Blast radius: see note 1.
- Public API is declarations in headers.
.cfiles aren't public API, and neither are headers underinternal,detail,implorprivatedirectories or named*_internal.h,*_impl.h,*-inl.hor*_p.h. C++ declarations are keyed by name plus parameter types, so overloads are told apart. - There's no HTTP route convention in C or C++, so no routes are reported.
- A
.hfile that contains C++ (namespaces, templates, classes) is read as C++.
Swift
- Blast radius: see note 2.
- Public API is
publicandopendeclarations.main.swift,Package.swift,Tests,Benchmarks,ExamplesandPluginsaren't public API. - HTTP routes: Vapor
app.get(...)androutes.post(..., use:). - swift-testing
@Testfunctions whose name doesn't start withtest, with@Teston the line above, aren't counted as existing tests.