Claude-skill-registry kotlin-multiplatform-reviewer
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/kotlin-multiplatform-reviewer" ~/.claude/skills/majiayu000-claude-skill-registry-kotlin-multiplatform-reviewer && rm -rf "$T"
manifest:
skills/data/kotlin-multiplatform-reviewer/SKILL.mdsource content
Kotlin Multiplatform Reviewer Skill
Purpose
Reviews Kotlin Multiplatform (KMP) project structure and patterns including shared code design, expect/actual mechanism, and iOS interop.
When to Use
- KMP project code review
- "expect/actual", "shared module", "commonMain", "multiplatform" mentions
- iOS/Android code sharing design review
- Projects with
pluginkotlin("multiplatform")
Project Detection
plugin inkotlin("multiplatform")build.gradle.kts
,src/commonMain
,src/androidMain
directoriessrc/iosMain
orshared
module existscommon
Workflow
Step 1: Analyze Structure
**Kotlin**: 2.0.x **Targets**: Android, iOS (arm64, simulatorArm64) **Shared Module**: shared **Source Sets**: - commonMain (shared code) - androidMain (Android specific) - iosMain (iOS specific)
Step 2: Select Review Areas
AskUserQuestion:
"Which areas to review?" Options: - Full KMP pattern check (recommended) - Module structure/dependencies - expect/actual implementation - Platform code separation - iOS interop (Swift/ObjC) multiSelect: true
Detection Rules
Module Structure
| Check | Recommendation | Severity |
|---|---|---|
| Bloated shared module | Split by layer | MEDIUM |
| Circular dependencies | Unidirectional deps | HIGH |
| Platform code in commonMain | Move to androidMain/iosMain | HIGH |
| Missing test module | Add commonTest | MEDIUM |
Recommended Structure:
project/ ├── shared/ │ └── src/ │ ├── commonMain/kotlin/ # Shared business logic │ ├── commonTest/kotlin/ # Shared tests │ ├── androidMain/kotlin/ # Android specific │ ├── iosMain/kotlin/ # iOS specific │ └── iosTest/kotlin/ ├── androidApp/ # Android app └── iosApp/ # iOS app (Xcode)
expect/actual Patterns
| Check | Recommendation | Severity |
|---|---|---|
| actual without expect | expect declaration required | CRITICAL |
| Missing actual impl | Provide actual for all targets | CRITICAL |
| Excessive expect/actual | Consider interface + DI | MEDIUM |
| Direct platform API in actual | Add abstraction layer | MEDIUM |
// commonMain - expect declaration expect class Platform() { val name: String fun getDeviceId(): String } // androidMain - actual implementation actual class Platform actual constructor() { actual val name: String = "Android ${Build.VERSION.SDK_INT}" actual fun getDeviceId(): String = Settings.Secure.getString( context.contentResolver, Settings.Secure.ANDROID_ID ) } // iosMain - actual implementation actual class Platform actual constructor() { actual val name: String = UIDevice.currentDevice.systemName() actual fun getDeviceId(): String = UIDevice.currentDevice .identifierForVendor?.UUIDString ?: "" }
BAD: expect/actual overuse
// BAD: expect/actual for simple values expect val platformName: String actual val platformName: String = "Android" // GOOD: interface + DI interface PlatformInfo { val name: String } // androidMain class AndroidPlatformInfo : PlatformInfo { override val name = "Android" }
Platform Separation
| Check | Recommendation | Severity |
|---|---|---|
| Platform import in commonMain | Move to platform source set | CRITICAL |
| Java class in commonMain | expect/actual or pure Kotlin | HIGH |
| UIKit/Android SDK in common | Separate to platform source set | CRITICAL |
// BAD: Android import in commonMain // commonMain/kotlin/Repository.kt import android.content.Context // Compile error! // GOOD: expect/actual separation // commonMain expect class DataStore { fun save(key: String, value: String) fun get(key: String): String? } // androidMain actual class DataStore(private val context: Context) { private val prefs = context.getSharedPreferences("app", Context.MODE_PRIVATE) actual fun save(key: String, value: String) { prefs.edit().putString(key, value).apply() } actual fun get(key: String): String? = prefs.getString(key, null) } // iosMain actual class DataStore { actual fun save(key: String, value: String) { NSUserDefaults.standardUserDefaults.setObject(value, key) } actual fun get(key: String): String? = NSUserDefaults.standardUserDefaults.stringForKey(key) }
iOS Interop
| Check | Recommendation | Severity |
|---|---|---|
| Missing @ObjCName | Swift-friendly naming | LOW |
| Sealed class iOS exposure | Use enum or @ObjCName | MEDIUM |
| Direct Flow exposure to iOS | Provide wrapper function | HIGH |
| suspend function iOS call | Provide completion handler wrapper | HIGH |
// BAD: Direct suspend function exposure class Repository { suspend fun fetchData(): Data // Hard to call from iOS } // GOOD: iOS wrapper provided class Repository { suspend fun fetchData(): Data // iOS completion handler wrapper fun fetchDataAsync(completion: (Data?, Error?) -> Unit) { MainScope().launch { try { val data = fetchData() completion(data, null) } catch (e: Exception) { completion(null, e) } } } }
Flow iOS Exposure:
// BAD: Direct Flow exposure val dataFlow: Flow<Data> // GOOD: iOS wrapper fun observeData(onEach: (Data) -> Unit): Closeable { val job = MainScope().launch { dataFlow.collect { onEach(it) } } return object : Closeable { override fun close() { job.cancel() } } }
Dependency Management
| Check | Recommendation | Severity |
|---|---|---|
| Platform library in commonMain | Use multiplatform library | HIGH |
| Version mismatch | Use Version Catalog | MEDIUM |
| Unused dependencies | Remove unused | LOW |
Multiplatform Library Recommendations:
| Purpose | Library |
|---|---|
| HTTP | Ktor Client |
| Serialization | Kotlinx Serialization |
| Async | Kotlinx Coroutines |
| DI | Koin, Kodein |
| Date/Time | Kotlinx Datetime |
| Settings | Multiplatform Settings |
| Logging | Napier, Kermit |
| DB | SQLDelight |
Response Template
## KMP Project Review Results **Project**: [name] **Kotlin**: 2.0.x **Targets**: Android, iOS (arm64, simulatorArm64) ### Module Structure | Status | Item | Issue | |--------|------|-------| | OK | Source set separation | commonMain/androidMain/iosMain correct | | MEDIUM | Tests | Add commonTest recommended | ### expect/actual | Status | File | Issue | |--------|------|-------| | OK | Platform.kt | expect/actual correctly implemented | | HIGH | DataStore.kt | Missing iosMain actual implementation | ### iOS Interop | Status | Item | Issue | |--------|------|-------| | HIGH | Repository.kt | suspend function needs iOS wrapper | | MEDIUM | UiState.kt | Add @ObjCName to sealed class | ### Recommended Actions 1. [ ] Add DataStore iosMain actual implementation 2. [ ] Add completion handler wrapper to fetchData() 3. [ ] Add commonTest source set
Best Practices
- Share Scope: Business logic > Data layer > UI (optional)
- expect/actual: Minimize usage, prefer interface + DI
- iOS Interop: Use SKIE library or manual wrappers
- Testing: Test shared logic in commonTest
- Dependencies: Prefer multiplatform libraries
Integration
skill: Android specific codekotlin-android-reviewer
skill: Server shared codekotlin-spring-reviewer
skill: General code qualitycode-reviewer
Notes
- Based on Kotlin 2.0+
- KMP 1.9.20+ recommended (Stable)
- Compose Multiplatform requires separate review