From kotlin-skills
Essential reference for working in any Kotlin Multiplatform (KMP) project. Use whenever developing, building, or debugging a KMP app or library. Covers expect/actual patterns, source set hierarchy, file naming conventions, platform-specific Gradle task naming (compilation, linking, testing), and multiplatform dependency configuration.
How this skill is triggered — by the user, by Claude, or both
Slash command
/kotlin-skills:kotlin-multiplatform-developmentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- ALWAYS use small platform-specific Gradle tasks, NEVER use the generic large tasks like `build`.
build../gradlew tasks to list available tasks.iosSimulatorArm64) unless all are specifically needed.Use platform suffixes to distinguish files with the same name across platforms:
FileManager.kt → common expectFileManager.android.kt → Android actualFileManager.ios.kt → iOS actual// Common
expect class Platform()
expect fun createPlatform(): Platform
// Android
actual class Platform actual constructor()
actual fun createPlatform(): Platform = Platform()
// iOS
actual class Platform actual constructor()
actual fun createPlatform(): Platform = Platform()
// Common
expect fun getPlatformName(): String
// Android
actual fun getPlatformName(): String = "Android ${Build.VERSION.SDK_INT}"
// iOS
actual fun getPlatformName(): String = UIDevice.currentDevice.systemName + " " + UIDevice.currentDevice.systemVersion
// Common
expect object Logger {
fun log(message: String)
}
// Android
actual object Logger {
actual fun log(message: String) = Log.d("App", message)
}
// iOS
actual object Logger {
actual fun log(message: String) = NSLog(message)
}
// Common
expect val isDebug: Boolean
// Android
actual val isDebug: Boolean = BuildConfig.DEBUG
// iOS
actual val isDebug: Boolean = Platform.isDebugBinary
// Common
expect class NativeDate
// Android
actual typealias NativeDate = java.util.Date
// iOS
actual typealias NativeDate = platform.Foundation.NSDate
// Common
interface DeviceInfo {
val platformName: String
val osVersion: String
}
expect fun createDeviceInfo(): DeviceInfo
// Android
class AndroidDeviceInfo : DeviceInfo {
override val platformName = "Android"
override val osVersion = Build.VERSION.RELEASE
}
actual fun createDeviceInfo(): DeviceInfo = AndroidDeviceInfo()
// iOS
class IosDeviceInfo : DeviceInfo {
override val platformName = "iOS"
override val osVersion = UIDevice.currentDevice.systemVersion
}
actual fun createDeviceInfo(): DeviceInfo = IosDeviceInfo()
| Pattern | Use When |
|---|---|
| Interface + Factory | Default choice. Flexible, testable, multiple implementations per platform |
| Expect/actual fun | Simple factory functions or standalone platform-specific logic |
| Expect/actual object | Singletons with a fixed API |
| Expect/actual typealias | Wrapping existing platform types |
| Expect/actual class | Only when inheriting from platform-specific base classes |
expect/actual declarationsexpect/actual class when an interface would suffice| Pattern | Examples |
|---|---|
compileKotlin<Target> | compileKotlinJvm, compileKotlinJs, compileKotlinIosArm64, compileKotlinIosSimulatorArm64, compileKotlinWasmJs |
compile<BuildType>KotlinAndroid | compileDebugKotlinAndroid, compileReleaseKotlinAndroid |
compile<SourceSet>KotlinMetadata | compileCommonMainKotlinMetadata, compileAppleMainKotlinMetadata, compileIosMainKotlinMetadata |
| Pattern | Examples |
|---|---|
link<BuildType>Framework<Target> | linkDebugFrameworkIosArm64, linkReleaseFrameworkIosSimulatorArm64, linkDebugFrameworkIosX64 |
linkDebugTest<Target> | linkDebugTestIosArm64, linkDebugTestIosSimulatorArm64 |
| Pattern | Examples |
|---|---|
allTests | allTests (runs all targets) |
<target>Test | iosSimulatorArm64Test, jvmTest, jsTest, jsBrowserTest, wasmJsTest |
test<BuildType>UnitTest | testDebugUnitTest, testReleaseUnitTest |
connected<BuildType>AndroidTest | connectedDebugAndroidTest |
Exact source sets depend on your configured targets. The plugin automatically creates intermediate source sets based on declared targets.
commonMain
├── androidMain
├── jvmMain
├── webMain
│ ├── jsMain
│ └── wasmMain
│ ├── wasmJsMain
│ └── wasmWasiMain
└── nativeMain
├── appleMain
│ ├── iosMain
│ │ ├── iosArm64Main
│ │ └── iosSimulatorArm64Main
│ ├── macosMain
│ │ ├── macosX64Main
│ │ └── macosArm64Main
│ ├── tvosMain
│ └── watchosMain
├── linuxX64Main
└── mingwX64Main
Intermediate source sets for shared logic:
webMain → JS and Wasm targets (Kotlin 2.2.20+)nativeMain → all Kotlin/Native targetsappleMain → iOS, macOS, watchOS, tvOSiosMain → all iOS targets (iosArm64, iosSimulatorArm64)Create custom intermediate source sets with dependsOn:
kotlin {
applyDefaultHierarchyTemplate()
sourceSets {
val jvmAndroidMain by creating {
dependsOn(commonMain.get())
}
androidMain.get().dependsOn(jvmAndroidMain)
jvmMain.get().dependsOn(jvmAndroidMain)
}
}
Add dependencies per source set. Dependencies in parent source sets propagate to children.
kotlin {
sourceSets {
commonMain.dependencies {
implementation("group:artifact:version")
api("group:exposed-artifact:version")
}
// Platform-specific (artifact suffix varies by library)
androidMain.dependencies {
implementation("group:artifact-<android>:version")
}
iosMain.dependencies {
implementation("group:artifact-<ios>:version")
}
// Custom source sets
// - "by getting": reference existing source sets
// - "by creating": create new custom source sets
val androidMain by getting
val jvmMain by getting
val jvmAndroidMain by creating {
dependsOn(commonMain.get())
}
jvmAndroidMain.dependencies {
implementation("group:artifact-<jvm-android>:version")
}
androidMain.dependsOn(jvmAndroidMain)
jvmMain.dependsOn(jvmAndroidMain)
}
}
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub yasanglass/agent-skills --plugin kotlin-skills