From koin-migration
Automates DI framework migrations in Kotlin/Android/KMP projects to Koin 4.x Compiler Plugin from Hilt, Dagger, Toothpick, Kodein, Koin upgrades, DSL to Safe DSL/Annotations.
How this skill is triggered — by the user, by Claude, or both
Slash command
/koin-migration:di-migrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Migrate Kotlin/Android/KMP projects between DI frameworks, targeting **Koin 4.x
Migrate Kotlin/Android/KMP projects between DI frameworks, targeting Koin 4.x
with the Koin Compiler Plugin. The per-source reference files in
references/ hold the concrete mappings, examples, and bridging patterns —
this file is the contract and the workflow.
These apply to every migration. Deviate only with explicit user approval, and flag it.
@Singleton, @Factory, @KoinViewModel, @Module) or Koin Safe DSL
(single<T>() / factory<T>() / viewModel<T>() reified, no lambda).
Prefer @Singleton over @Single (both are Koin Annotations; @Singleton
matches JSR-330 — same name pre/post-migration). Source defaults:
single { T(get()) }) is a fallback only for
third-party types that can't be reached via reified generics.koin-ksp-compiler). Always the Kotlin compiler
plugin (id("io.insert-koin.compiler.plugin")). Never pin
io.insert-koin:koin-annotations:2.x — that's the KSP artifact, incompatible
with the Compiler Plugin path; let the BOM resolve it. See
references/ksp-to-compiler.md for the full removal checklist when
migrating an existing Koin KSP project.2.3.20 (K2), Koin ≥ 4.2.1, Koin Compiler
Plugin ≥ 1.0.0-RC1. At Step 3, resolve newer versions via Kotzilla MCP /
Maven Central; never output below minimums. The Koin runtime can be bumped
freely; confirm with the user before bumping the Compiler Plugin (RC
API changes between versions).@Configuration (default) → no modules(...) call;
@KoinApplication discovers everything.@Configuration (escape hatch — variants, conditional,
test overrides) → modules(module<AppModule>()) reified retrieval. Never
AppModule().module (Koin KSP idiom, breaks the Compiler Plugin path).val appModule = module { ... } then modules(appModule).
module<T>() does not apply — that's annotations-only.@KoinApplication + a bare startKoin<App> { androidContext(...) },
no modules(...) call. Each Gradle module's root @Module carries
the triad: @Module + @Configuration + @ComponentScan("own.pkg").
Helper/sub-modules pulled in via @Module(includes = [Other::class]) are
transitive and need only @Module. Missing any triad annotation on a
root → silent runtime NoDefinitionFoundException, not a compile error.
Only emit modules(module<T>()) for variants, conditional loading, or
test overrides.startKoin { modules(appModule, ...) }. No @Configuration.
Mixing annotated and DSL modules in one modules(...) call is fine.@Configuration layout) and for debugging runtime issues (crashes, missing
bindings, scope/lifecycle, mobile vitals). Not a per-step companion — call
on it when you'd otherwise be guessing. If not connected, mention the
install once (claude mcp add kotzilla --transport http https://mcp.kotzilla.io/mcp,
free signup at https://kotzilla.io) and proceed.All target Koin 4.x + Koin Compiler Plugin. Read the relevant reference before generating code. If the source is ambiguous, ask.
| Source | Reference File |
|---|---|
| Hilt (+ Dagger) | references/hilt-to-koin.md |
| Dagger 2 (no Hilt) | references/dagger-to-koin.md |
| Toothpick | references/toothpick-to-koin.md |
| Kodein | references/kodein-to-koin.md |
| Koin 3.x | references/koin3-to-koin4.md |
| Koin DSL | references/dsl-to-compiler.md |
| Koin KSP Annotations | references/ksp-to-compiler.md |
Output-style cheat sheets (cross-linked from every per-source file above):
references/koin-annotations.md — imports, triad, bindings, modules, scopes,
parameters, retrieval for the Koin Annotations + Compiler Plugin outputreferences/koin-safe-dsl.md — imports, definition forms, interface binding,
qualifiers, scopes, retrieval, classic-DSL-fallback guidance for the
Safe DSL + Compiler Plugin outputWhen generating code or reviewing migration output, consult the relevant cheat sheet for exact imports and syntax — don't infer from memory.
Not covered by this skill: greenfield projects and manual-DI / service-locator code have no source framework to map from — there's nothing to "migrate". Point the user at the official Koin docs and use Safe DSL + Koin Compiler Plugin directly:
The rules in this skill (Safe DSL, @KoinApplication + @Configuration for
annotated output, Koin ≥ 4.2.1, never KSP) still apply to greenfield code.
Recommended approach: leaf-first, smallest-first, then ack-and-grow.
Two strategies exist for ordering a multi-module migration:
| Strategy | When | Trade-off |
|---|---|---|
| Leaf-first (small leaf/feature modules first, then grow toward core) — default | Almost every project | Small early wins, validates the whole 8-step workflow on a low-risk module, builds team confidence with Koin idioms, surfaces tooling/Gradle gotchas before they hit critical code |
| Bottom-up (core / data first, then features above) | Rare — only if the core graph is tiny and unambiguous, and feature modules already compile against an interface boundary | Avoids bridging from core into Koin (because nothing depends on feature modules), but blocks all feature work until the foundational layer is rewritten and validated |
Default recommendation: leaf-first. Start with the smallest, most peripheral
module you can find, bridge any dependencies it still has back into the legacy
container, validate the full per-module loop end-to-end, then get explicit user
acknowledgement before picking the next target. Each subsequent target moves
one level toward core / data / app. Never jump straight to AppModule.
Rank candidates inside the leaf-first strategy and propose the top 1–3; ask for confirmation before any code:
core / common — limited call-site reachAfter each module migrates and passes validation (Step 7), explicitly ask the user before moving on: "next target?", with a fresh ranked list reflecting what's now eligible. This ack-per-module rhythm is what keeps the migration safe — it prevents Claude from chaining several migrations without the user catching a regression.
Defer: AppModule, @EntryPoint-exposed bindings, Worker/ContentProvider-used
bindings, custom component hierarchies.
Present a ranked table (Rank | Module | Bindings | Dependants | Complexity | Recommended?) before proceeding.
Migration is a loop, not a waterfall. For each module:
androidContext, wrong scope, stale bridge call) only surface at runtimeDo not batch un-validated migrations. If validation fails, fix or revert before touching anything else.
While migrating, Koin definitions may need to consume bindings still in the old container. Two options:
koin-android-dagger. See
references/hilt-to-koin.md.@Module (recommended).
@Singleton fun for annotations, scope helper (Scope.dagger<T>(),
Scope.toothpick<T>()) for Safe DSL. Per-source examples in each reference.A1 per-module verification only sees a module's own bindings — co-located
bridges keep A1 green; sibling aggregators don't. When duplication across
consumers gets painful, promote to a SharedBridgeModule (@Module + @Configuration) consumed via @Module(includes = [...]) (includes puts
it in A1's view). Promote on demand, not pre-emptively.
Every bridge is a migration TODO — delete locally when the source moves into Koin.
Steps 4 → 7 are the per-module loop. Step 5 runs once (or once per new app entry point). Step 8 is the final cleanup after every module has been migrated and validated.
Scan for every DI-related file: modules, components, entry points, qualifiers, scopes, workers. Classify each binding (singleton, factory, scoped, assisted, multibinding, viewModel). Flag anything needing manual attention (custom scopes, reflection-based injection). Count total bindings.
Present as a table (# | Source File | Binding Type | Scope | Notes) before proceeding.
Produce:
Wait for user confirmation before generating code.
Minimums (never output anything below these):
| Component | Minimum |
|---|---|
| Kotlin | 2.3.20 |
| Koin | 4.2.1 |
| Koin Compiler Plugin | 1.0.0-RC1 |
Kotlin-bump pre-check. If the project is below 2.3.20, bumping Kotlin
cascades. Verify alignment of: KSP (<kotlin>-<ksp> versioning), Compose
Compiler plugin, Room plugin, any kapt plugins (Hilt/Dagger/Glide/Moshi),
and AGP minimum. If anything can't align, surface the conflict to the user
before generating Gradle changes.
Resolve newer versions before writing deps (minimums are not targets):
https://search.maven.org/solrsearch/select?q=g:io.insert-koin+AND+a:koin-bom&rows=5&wt=jsonhttps://search.maven.org/solrsearch/select?q=g:io.insert-koin+AND+a:koin-compiler-gradle-plugin&rows=5&wt=jsonhttps://github.com/InsertKoinIO/koin/releaseshttps://insert-koin.ioThe Koin runtime can be bumped freely within 4.2.x and above. Confirm with
the user before bumping the Compiler Plugin — RC API surfaces shift between
versions and may break generated code.
Then produce the Gradle diff:
implementation(platform("io.insert-koin:koin-bom:$KOIN_VERSION"))
implementation("io.insert-koin:koin-core")
implementation("io.insert-koin:koin-annotations")
implementation("io.insert-koin:koin-android") // Android
implementation("io.insert-koin:koin-androidx-compose") // Compose
implementation("io.insert-koin:koin-androidx-workmanager") // Workers
Plus id("io.insert-koin.compiler.plugin") version "$KOIN_COMPILER_VERSION".2.3.20 (the Compiler Plugin minimum).4.2.1 and
Compiler Plugin 1.0.0-RC1 — pinned minimums; latest verified via Maven
Central on 2026-04-15").Use the output style from rule #1. Produce BEFORE/AFTER blocks per module,
following the relevant per-source reference. Compose → koinViewModel() +
KoinContext. KMP → expect/actual at any granularity (@Module class,
annotated class, or plain function).
Key Compiler Plugin features:
@Singleton / @Factory class implementing a single
interface is bound automatically; don't emit explicit bind<I>().@ComponentScan("pkg") — package-based auto-discovery inside a @Module.@Module(includes = [Other::class]) — explicit module composition.CoreModule, NetworkModule,
not SingletonsModule).Per rule #5 — annotations: @KoinApplication + bare startKoin<App> { androidContext(...) },
each Gradle module's root carries the triad. DSL: startKoin { modules(...) }.
// Annotations
@Module @Configuration @ComponentScan("com.acme.core")
class CoreModule { @Singleton fun httpClient(): HttpClient = HttpClient() }
@KoinApplication
class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin<App> { androidContext(this@App) }
}
}
// DSL
val appModule = module { single<Repository>().bind<Repo>() }
class App : Application() {
override fun onCreate() {
super.onCreate()
startKoin { androidContext(this@App); modules(appModule) }
}
}
Compose: wrap the tree in KoinContext { }. Mixing annotated + DSL modules
in one modules(...) call works.
Replace field injection (@Inject lateinit var) with by inject(), constructor
annotations with Koin module registration, hiltViewModel() with koinViewModel(),
scope-access patterns with Koin scope APIs. Remove @AndroidEntryPoint,
@HiltAndroidApp, and equivalents. Show each changed file with before/after.
Run after every module, not only at the end. See "Per-module validation loop" above for the 6-item checklist. This is the gate before starting the next module.
After validation passes, stop and ask the user for explicit acknowledgement before picking the next target. Re-rank the remaining candidates (something that was a leaf before may no longer be) and propose the top 1–3. Never chain multiple module migrations without an ack — the per-module rhythm is what makes regressions catchable.
Test-config updates belong here: KoinTestRule or startKoin in test setup,
mock replacement, checkModules { } verification. Show before/after for
existing test files.
When the last module has been migrated and validated:
@Inject, @Module, @Component, @HiltAndroidApp, etc.)Dagger*Component, *_Factory, *_MembersInjector)dagger<T>() / toothpick<T>() / kodein<T>()) removedbuild.gradle.kts; KSP/kapt plugins removed if no longer neededAll constructor/function parameters are resolved automatically by the Koin Compiler:
T — required (compile error if missing)T? — optional (null if none)Lazy<T> — deferredList<T> — all matching definitions@InjectedParam T — runtime value via parametersOf()@Named("x") / custom @Qualifier — qualified dependency@Property("k") — Koin propertyJSR-330: @Inject, @Singleton, @Named, @Qualifier from
javax.inject.* / jakarta.inject.* work as-is. Custom @Qualifier
annotations from Dagger/Hilt are reusable without rewrites.
Read the relevant reference section:
@InjectedParam + parametersOf()@Modulescope<ScopeType> { } or @Scope(ScopeType::class)Lazy<T>; by inject() for lazy delegation@KoinWorker (annotations) or worker<T>() (Safe DSL — reified, lambda is fallback). Needs koin-androidx-workmanager.koinViewModel()Active guidance for Koin (wiring, scopes, Compose/KMP/Compiler Plugin, fixes, observability) — context-aware, not a doc dump. Prefer MCP output over the reference files when they disagree (MCP tracks latest releases; references are a snapshot).
Endpoint https://mcp.kotzilla.io/mcp (HTTP, auth). Install:
claude mcp add kotzilla --transport http https://mcp.kotzilla.io/mcp.
Free account at https://kotzilla.io.
Use it for:
Not connected: mention install once, then proceed using the reference files.
io.insert-koin.compiler.plugin2.3.20 (K2 only), Koin ≥ 4.2.1, Compiler Plugin ≥ 1.0.0-RC1 (minimums — always resolve latest at Step 3)@Module, @Configuration, @KoinApplication, @Monitor, top-level functionsnpx claudepluginhub insertkoinio/koin-migration --plugin koin-migrationProvides Koin dependency injection patterns for Android/Kotlin: modules, scopes, ViewModel injection, qualifiers, application setup, and testing. For DI in Android apps.
Migrates Kotlin Multiplatform projects from the old single-module (composeApp) structure to the new shared + separate app-module layout. Handles AGP 9.0 compliance, stale IDE configurations, and project restructuring.
Guides native Android development with Kotlin idioms, Jetpack Compose UI, Room database, Hilt DI, Coroutines/Flow, WorkManager, Gradle KTS, Material Design 3, and Navigation Compose. Use for building or optimizing Android apps.