name: kmp-gradle-doctor description: Diagnose and fix Kotlin Multiplatform Gradle, source-set, dependency, Android target, Compose plugin, KGP/AGP, testing, static-analysis, and CI issues.
KMP Gradle Doctor
Set $PLUGIN_ROOT ($env:PLUGIN_ROOT in PowerShell; same path suffix) once: host plugin-root variable when defined (Claude Code: PLUGIN_ROOT="$CLAUDE_PLUGIN_ROOT"), else this plugin root's absolute path. Bundled commands use it.
Use for KMP build failures; Gradle DSL changes; plugin version alignment; target declarations; source-set hierarchy; Android-KMP plugin migration; dependency placement; KSP/KAPT; detekt/ktlint; Compose compiler; CI; test task selection.
Diagnosis Flow
- Read:
settings.gradle(.kts)- root/module
build.gradle(.kts) gradle/libs.versions.tomlgradle.propertiesgradle/wrapper/gradle-wrapper.properties
- Run:
python3 "$PLUGIN_ROOT/scripts/kmp_inspector.py" --root <project-root> - Classify modules:
- KMP library
- Android app shell
- pure Android library
- iOS Xcode app
- desktop/web/server app
- convention plugin or build logic
- Find smallest failing task. Avoid
cleanunless cache state is suspected. - Check official docs for current DSL/version-sensitive guidance before edits.
- If the failure looks host-specific on macOS/iOS, separate project diagnosis from environment diagnosis. Use
kdoctoronly if installed or explicitly approved to install; scope: host/toolchain readiness.
Environment Triage
Use project static inspection first. Then consider host diagnostics when symptoms include Xcode selection, CocoaPods/Ruby, Android Studio plugin, JDK/JAVA_HOME, simulator, or iOS Gradle task failures unrelated to source changes.
Useful checks:
xcode-select -p
xcodebuild -version
java -version
./gradlew -version
kdoctor -v
Do not install/update KDoctor, CocoaPods, Ruby, Xcode, Android Studio, JDKs, or SDK tools unless the user explicitly asked for environment setup.
Build Governance
Medium/large KMP projects: inspect whether repeated configuration is centralized.
- Prefer included-build
build-logic/orbuildSrc/convention plugins when many modules repeat setup. - Prefer version catalogs for plugin/dependency coordinates.
- Prefer central
pluginManagementanddependencyResolutionManagementin settings. - Avoid ad hoc repositories in module build files.
- Keep stack-specific choices (DI, database, obfuscation, codegen, publishing) opt-in by module role.
Source-Set Rules
- Prefer default hierarchy template when the target combination is covered.
- Manual
dependsOn()edges can disable the default hierarchy template; keep them only for real non-default sharing needs. - Declare targets before source-set references.
- Place dependencies in narrowest valid source sets:
- shared/target-published libraries:
commonMain - Android-only artifacts:
androidMain - iOS-only bindings:
iosMainor exact native source set - JVM/Desktop-only artifacts:
jvmMainor named desktop source set
- shared/target-published libraries:
- Before moving to
commonMain, verify every configured target publishes the artifact.
Android-KMP Rules
Android-targeting KMP library modules on modern AGP:
- Prefer
com.android.kotlin.multiplatform.library. - Keep Android config in
kotlin { android { ... } }. - Do not use a top-level
android {}block after Android-KMP library plugin migration. - Android-KMP library plugin is single-variant: no
buildTypesorproductFlavorsin that module. - Enable only used features:
androidResources { enable = true }if Android resources or Compose resources need Android resource processing.withJava()for Java sources.- host/device test builders for Android tests.
localDependencySelectionfor variant-rich Android library consumption.
- For Compose preview tooling in Android-KMP library modules, verify current workaround before using debug-only configurations.
Build And Test Commands
Prefer the narrowest proof:
./gradlew :shared:compileKotlinMetadata
./gradlew :shared:compileKotlinIosSimulatorArm64
./gradlew :shared:jvmTest
./gradlew :shared:allTests
./gradlew :androidApp:assembleDebug
./gradlew :desktopApp:run
Task names vary by module/target; use ./gradlew :module:tasks --all when uncertain.
Static Analysis
- detekt often needs explicit KMP source-set inputs/config; do not assume root
detektchecks allcommonMain,iosMain, andandroidMaincode. - Type-resolution can explode runtime in large KMP monorepos; prefer scoped tasks; avoid enabling all Android variants unless required.
- KSP must match Kotlin versions; verify compatibility before bumping KGP or KSP.
- KAPT is modern Android/KMP migration risk; prefer KSP or isolate legacy processors.
- For published KMP libraries, check whether Kotlin ABI validation is configured or intentionally skipped.
- If a module exposes many
api(...)dependencies, review whether public surface is too broad.
CI Pattern
- Split jobs by cost/platform: common/JVM tests first on Linux; Android builds on Linux; iOS simulator/Apple framework checks on macOS.
- Use official Gradle setup action and one shared Java/Gradle setup path.
- Upload test reports/platform artifacts.
- Keep signing, notarization, and store publishing separate from ordinary PR validation.