kotlin-tooling-agp9-migration
Migrates Kotlin Multiplatform (KMP) projects to Android Gradle Plugin 9.0+. Handles plugin replacement (com.android.kotlin.multiplatform.library), module splitting, DSL migration, and the new default project structure. Use when upgrading AGP, when build fails due to KMP+AGP incompatibility, or when the user mentions AGP 9.0, android multiplatform plugin, KMP migration, or com.android.kotlin.multiplatform.library.
What this skill does
# KMP AGP 9.0 Migration
Android Gradle Plugin 9.0 makes the Android application and library plugins incompatible
with the Kotlin Multiplatform plugin in the same module. This skill guides you through the
migration.
## Step 0: Analyze the Project
Before making any changes, understand the project structure:
1. Read `settings.gradle.kts` (or `.gradle`) to find all modules
2. For each module, read its `build.gradle.kts` to identify which plugins are applied
3. Check if the project uses a Gradle version catalog (`gradle/libs.versions.toml`). If it exists,
read it for current AGP/Gradle/Kotlin versions. If not, find versions directly in `build.gradle.kts`
files (typically in the root `buildscript {}` or `plugins {}` block). **Adapt all examples in this
guide accordingly** — version catalog examples use `alias(libs.plugins.xxx)` while direct usage
uses `id("plugin.id") version "x.y.z"`
4. Read `gradle/wrapper/gradle-wrapper.properties` for the Gradle version
5. Check `gradle.properties` for any existing workarounds (`android.enableLegacyVariantApi`)
6. Check for `org.jetbrains.kotlin.android` plugin usage — AGP 9.0 has built-in Kotlin and this plugin must be removed
7. Check for `org.jetbrains.kotlin.kapt` plugin usage — incompatible with built-in Kotlin, must migrate to KSP or `com.android.legacy-kapt`
8. Check for third-party plugins that may be incompatible with AGP 9.0 (see "Plugin Compatibility" section below)
If Bash is available, run `scripts/analyze-project.sh` from this skill's directory to get a structured summary.
### Classify Each Module
For each module, determine its type:
| Current plugins | Migration path |
|--------------------------------------------------------------------------|---------------------------------------------|
| `kotlin.multiplatform` + `com.android.library` | **Path A** — Library plugin swap |
| `kotlin.multiplatform` + `com.android.application` | **Path B** — Mandatory Android split |
| `kotlin.multiplatform` with multiple platform entry points in one module | **Path C** — Full restructure (recommended) |
| `com.android.application` or `com.android.library` (no KMP) | See "Pure Android Tips" below |
### Determine Scope
- **Path B is mandatory** for any module combining KMP + Android application plugin
- **Path C is recommended** when the project has a monolithic `composeApp` (or similar) module
containing entry points for multiple platforms (Android, Desktop, Web). This aligns with the
new JetBrains default project structure where each platform gets its own app module.
- **Ask the user** whether they want Path B only (minimum required) or Path C (recommended full restructure)
## Path A: Library Module Migration
Use this when a module applies `kotlin.multiplatform` + `com.android.library`.
See [references/MIGRATION-LIBRARY.md](references/MIGRATION-LIBRARY.md) for full before/after code.
Summary:
1. **Replace plugin**: `com.android.library` → `com.android.kotlin.multiplatform.library`
2. **Remove `org.jetbrains.kotlin.android`** plugin if present (AGP 9.0 has built-in Kotlin support)
3. **Migrate DSL**: Move config from top-level `android {}` block into `kotlin { android {} }`:
```kotlin
kotlin {
android {
namespace = "com.example.lib"
compileSdk = 35
minSdk = 24
}
}
```
4. **Rename source directories** (only if the module uses classic Android layout instead of KMP layout):
- `src/main` → `src/androidMain`
- `src/test` → `src/androidHostTest`
- `src/androidTest` → `src/androidDeviceTest`
- If the module already uses `src/androidMain/`, no directory renames are needed
5. **Move dependencies** from top-level `dependencies {}` into `sourceSets`:
```kotlin
kotlin {
sourceSets {
androidMain.dependencies {
implementation("androidx.appcompat:appcompat:1.7.0")
}
}
}
```
6. **Enable resources** explicitly if the module uses Android or Compose Multiplatform resources:
```kotlin
kotlin {
android {
androidResources { enable = true }
}
}
```
7. **Enable Java** compilation if module has `.java` source files:
```kotlin
kotlin {
android {
withJava()
}
}
```
8. **Enable tests** explicitly if the module has unit or instrumented tests:
```kotlin
kotlin {
android {
withHostTest { isIncludeAndroidResources = true }
withDeviceTest {
instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
}
}
```
9. **Update Compose tooling dependency**:
```kotlin
// Old:
debugImplementation(libs.androidx.compose.ui.tooling)
// New:
androidRuntimeClasspath(libs.androidx.compose.ui.tooling)
```
10. **Publish consumer ProGuard rules** explicitly if applicable:
```kotlin
kotlin {
android {
consumerProguardFiles.add(file("consumer-rules.pro"))
}
}
```
11. **Resolve Sub-dependency Variants (Product Flavors / Build Types)**:
Because the new KMP Android library plugin enforces a single-variant architecture, it does not natively understand how to resolve dependencies that publish multiple variants (like `debug`/`release` build types, or product flavors like `free`/`paid`). Configure fallback behaviors using `localDependencySelection`:
```kotlin
kotlin {
android {
localDependencySelection {
// Determine which build type to consume from Android library dependencies, in order of preference
selectBuildTypeFrom.set(listOf("debug", "release"))
// If the dependency has a 'tier' dimension, select the 'free' flavor
productFlavorDimension("tier") {
selectFrom.set(listOf("free"))
}
}
}
}
```
## Path B: Android App + Shared Module Split
Use this when a module applies `kotlin.multiplatform` + `com.android.application`. This is **mandatory** for AGP 9.0 compatibility.
See [references/MIGRATION-APP-SPLIT.md](references/MIGRATION-APP-SPLIT.md) for full guide.
Summary:
1. **Create `androidApp` module** with its own `build.gradle.kts`:
```kotlin
plugins {
alias(libs.plugins.androidApplication)
// Do NOT apply kotlin-android — AGP 9.0 includes Kotlin support
alias(libs.plugins.composeMultiplatform) // if using Compose
alias(libs.plugins.composeCompiler) // if using Compose
}
android {
namespace = "com.example.app"
compileSdk = 35
defaultConfig {
applicationId = "com.example.app"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
}
buildFeatures { compose = true }
}
dependencies {
implementation(projects.shared) // or whatever the shared module is named
implementation(libs.androidx.activity.compose)
}
```
2. **Move Android entry point code** from `src/androidMain/` to `androidApp/src/main/`:
- `MainActivity.kt` (and any other Activities/Fragments)
- `AndroidManifest.xml` (app-level manifest with `<application>` and launcher `<activity>`) — verify `android:name` on `<activity>` uses the fully qualified class name in its new location
- Android Application class if present
- App-level resources (launcher icons, theme, etc.)
3. **Add to `settings.gradle.kts`**: `include(":androidApp")`
4. **Add to root `build.gradle.kts`**: plugin declarations with `apply false`
5. **Convert original module** from application to library using Path A steps
6. **Ensure different namespaces**: app module and library module must have distinct namespaces
7. **Remove from shared module**: `appliRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.