Make your AI coding tool actually understand Kotlin-Compose Multiplatform. Backed by real JetBrains and Google architecture docs — not vibes.
A Claude Code skill that turns any Claude agent into an expert in Kotlin Multiplatform (KMP) and Compose Multiplatform development — following Google's official architecture guidelines and JetBrains best practices.
Without this skill, Claude gives you generic Android advice. With it, Claude understands shared commonMain source sets, expect/actual declarations, Koin multiplatform DI, Room KMP setup, Ktor client configuration, and the full Clean Architecture layer separation that makes KMP projects maintainable across Android and iOS.
| Area | Details |
|---|---|
| Architecture | Clean Architecture, feature-based modularization, feature flags, inter-feature comms, proto DataStore |
| UI | Compose Multiplatform, Material 3, @Stable, state hoisting, focus management, text field a11y, dynamic type |
| Navigation | Deep links, cross-module contracts, predictive back, nested nav, back handling, transitions, SavedStateHandle |
| DI | Koin Multiplatform — modules, named qualifiers, ViewModels + SavedStateHandle, scopes, platform DI |
| Networking | Ktor — auth bearer, HttpRequestRetry, cert pinning, backoff jitter, 429 handling, caching |
| Persistence | Room KMP + DataStore KMP — migrations, reactive queries, Paging 3, FTS, type converters |
| State | UDF pattern, StateFlow, SharedFlow buffer strategies, stateIn(), Resource sealed class |
| Error Handling | Typed AppError, recoverable vs fatal, 429, error analytics/breadcrumbs, retry with backoff |
| Build System | Convention plugins, R8/ProGuard, Maven publishing, CI Gradle daemon, KSP, version catalog |
| iOS | SPM wrapper, SKIE (sealed enum edge cases), Kotlin/Native memory model, iOS performance, Swift interop |
| Testing | Fakes + Turbine, SharedFlow event tests, Paging tests, screenshot/golden tests, Compose UI tests |
| Logging | Log levels, Timber + CrashlyticsTree (Android), os_log (iOS), sensitive data redaction |
| i18n | String resources, plurals, RTL support, dynamic locale change, locale-aware number/currency formatting |
git clone https://github.com/felipechaux/kmp-compose-multiplatform-skill
cp -r kmp-compose-multiplatform-skill/.claude/skills/kmp-compose-multiplatform .claude/skills/git clone https://github.com/felipechaux/kmp-compose-multiplatform-skill
cp -r kmp-compose-multiplatform-skill/.claude/skills/kmp-compose-multiplatform ~/.claude/skills/git submodule add https://github.com/felipechaux/kmp-compose-multiplatform-skill .claude/kmp-skill
cp -r .claude/kmp-skill/.claude/skills/kmp-compose-multiplatform .claude/skills/That's it. Claude Code automatically picks up skill directories from
.claude/skills/. No configuration required.
Once installed, invoke the skill in Claude Code:
/kmp-compose-multiplatform
Or reference it inline:
Using the kmp-compose-multiplatform skill, create a new feature module for user authentication
Using the kmp-compose-multiplatform skill, review my ViewModel for UDF violations
Using the kmp-compose-multiplatform skill, set up Room KMP for both Android and iOS
Using the kmp-compose-multiplatform skill, configure Ktor client with auth interceptor and error handling
Using the kmp-compose-multiplatform skill, generate a Koin module for my data layer
| Without skill | With skill |
|---|---|
| Generic Android ViewModel patterns | UDF pattern with StateFlow, SharedFlow events, stateIn(), buffer strategies |
| Android-only Room setup | Room KMP with migrations, reactive Flow<List<T>> queries, Paging 3, FTS |
Hilt / Dagger suggestions |
Koin Multiplatform with named qualifiers, SavedStateHandle, scopes, test teardown |
| Single-platform Retrofit | Ktor with auth bearer, cert pinning, backoff jitter, 429 handling, caching |
Raw String errors everywhere |
Typed AppError sealed class, recoverable vs fatal, error analytics, 429 retry |
| Mixed architecture advice | Strict Clean Architecture with feature flags and inter-feature communication patterns |
| Guessed iOS integration | SPM wrapper, SKIE sealed enum edge cases, Kotlin/Native memory model, iOS performance |
println() for debugging |
Timber + CrashlyticsTree (Android), os_log (iOS), sensitive data redaction |
| Hardcoded UI strings | String resources, plurals, RTL support, dynamic locale change |
| No accessibility guidance | Focus management, text field a11y, 48dp touch targets, screen reader semantics |
| No screenshot regression tests | Paparazzi golden tests, SharedFlow event tests, Paging tests |
| No build optimization | R8/ProGuard rules, Maven publishing, CI Gradle daemon config, convention plugins |
The skill (.claude/skills/kmp-compose-multiplatform/) is structured as a precise instruction set Claude follows when invoked:
SKILL.md — core instruction set:
- Core Principles — Foundational rules for KMP development
- Project Structure — Module and package layout conventions
- Architecture Guidelines — Layer responsibilities, dependency rules, typed error handling
- KMP Patterns —
expect/actual, source sets, platform configuration - Dependency Injection — Koin modules, named qualifiers,
SavedStateHandle, scopes - Build System — Version catalog, BuildKonfig, KSP setup
- Data Persistence — Room KMP (migrations, reactive queries, Paging 3, FTS) and DataStore
- Networking — Ktor with auth, cert pinning, backoff jitter, caching, 429 handling
- Internationalization — String resources, plurals, RTL support, dynamic locale change
- Testing Strategy — Fakes, SharedFlow event tests, Paging tests, screenshot tests
- Logging —
expect/actuallog functions, Timber + CrashlyticsTree (Android),os_log(iOS) - Common Pitfalls — 24 mistakes to avoid in KMP projects
- Official References — Links to authoritative documentation
references/ — deep-dive guides:
architecture.md— module structures, feature flags, inter-feature comms, proto DataStore, state managementcompose-best-practices.md—@Stable, focus management, text field a11y, dynamic type, Material 3, performanceerror-handling.md—AppErrorhierarchy, recoverable vs fatal, 429, error analytics,safeApiCall, retry logictesting.md— fakes, Turbine, SharedFlow event testing, Paging tests, screenshot/golden tests, Compose UI testsios-interop.md— Swift naming, SKIE sealed class edge cases, Kotlin/Native memory model, iOS performancenavigation.md— deep links, cross-module contracts, predictive back, deep link validation, transitionsbuild-system.md— convention plugins, R8/ProGuard, Maven publishing, CI Gradle daemon, KSP, build performancei18n.md— string resources, plurals, RTL support, dynamic locale change, locale-aware number/currency formatting
This skill implements the architecture pattern shown below, directly inspired by Now in Android:
┌─────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ ViewModel → UiState → Composable Screen │
└─────────────────────┬───────────────────────────────────┘
│ uses
┌─────────────────────▼───────────────────────────────────┐
│ Domain Layer │
│ UseCase → Repository Interface → Model │
└─────────────────────┬───────────────────────────────────┘
│ implements
┌─────────────────────▼───────────────────────────────────┐
│ Data Layer │
│ Repository Impl → Remote/Local Source → DTO │
└─────────────────────────────────────────────────────────┘
feature/
└── auth/
├── data/
│ ├── local/ ← Room entities, DAOs
│ ├── remote/ ← Ktor API services
│ ├── repository/ ← Repository implementations
│ └── mapper/ ← DTO ↔ Domain mappers
├── domain/
│ ├── model/ ← Pure Kotlin domain models
│ ├── repository/ ← Repository interfaces
│ └── usecase/ ← Business logic (one action per class)
├── presentation/
│ ├── ui/ ← Composable screens
│ ├── viewmodel/ ← State holders
│ └── state/ ← UiState sealed classes
└── di/ ← Koin module
src/
├── commonMain/ ← Shared business logic, UI, ViewModels
├── androidMain/ ← Android-specific implementations
├── iosMain/ ← iOS-specific implementations
├── commonTest/ ← Shared unit tests with fakes
├── androidUnitTest/ ← Android-specific tests
└── iosTest/ ← iOS-specific tests
The recommended pattern for distributing the KMP shared module to an iOS app is a SPM Wrapper target — this is required because a binaryTarget (the compiled XCFramework) cannot declare Swift package dependencies on its own.
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyShared",
platforms: [.iOS(.v16)],
products: [
// Expose the wrapper, not the binary directly
.library(name: "MyShared", targets: ["MySharedWrapper"]),
],
dependencies: [
// Add Swift-only dependencies here (RevenueCat, Firebase, etc.)
.package(url: "https://github.com/RevenueCat/purchases-hybrid-common.git", exact: "17.32.0"),
],
targets: [
// Binary target — the compiled XCFramework from Kotlin/Native
.binaryTarget(
name: "MySharedBinary",
url: "https://github.com/org/repo/releases/download/v1.0.0/MyShared.xcframework.zip",
checksum: "abc123..." // sha256 — auto-computed in CI
),
// Wrapper target — bridges the binary with Swift dependencies
.target(
name: "MySharedWrapper",
dependencies: [
"MySharedBinary",
.product(name: "PurchasesHybridCommon", package: "purchases-hybrid-common"),
]
)
]
)Why the Wrapper pattern?
binaryTargetcannot declare Swift package dependencies directly- The wrapper is an empty Swift target whose only job is to re-export the binary alongside any Swift-only dependencies
- Your iOS app only needs to
import MyShared— no knowledge of the wrapper internals
Remote (production) — add published releases via SPM:
File → Add Package Dependencies- Enter your GitHub repo URL
- Select version rule → Add Package
import MySharedin your Swift files
Local (development) — use your local build directly:
File → Add Package Dependencies → Add Local- Select the root folder containing
Package.swift - No checksum needed — uses the local XCFramework build
// iosMain/MainViewController.kt
fun MainViewController(): UIViewController = ComposeUIViewController {
initKoin()
AppTheme { AppNavigation() }
}// ContentView.swift
import SwiftUI
import MyShared
struct ContentView: View {
var body: some View {
ComposeView().ignoresSafeArea(.all)
}
}
struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}Your GitHub Actions release workflow should:
- name: Build XCFramework
run: ./gradlew :shared:assembleReleaseXCFramework
- name: Zip XCFramework
run: zip -r MyShared.xcframework.zip shared/build/XCFrameworks/release/MyShared.xcframework
- name: Compute checksum
run: echo "CHECKSUM=$(swift package compute-checksum MyShared.xcframework.zip)" >> $GITHUB_ENV
- name: Update Package.swift
run: |
sed -i '' "s|url: \".*xcframework.zip\"|url: \"https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/MyShared.xcframework.zip\"|" Package.swift
sed -i '' "s|checksum: \".*\"|checksum: \"$CHECKSUM\"|" Package.swift
- name: Commit Package.swift
run: |
git config user.email "ci@github.com"
git config user.name "GitHub Actions"
git add Package.swift
git commit -m "chore: update Package.swift for ${{ github.ref_name }} [skip ci]"
git pushNever edit
Package.swiftmanually — it should be generated by CI on every release.
| Concern | Library | Version |
|---|---|---|
| UI | Compose Multiplatform | 1.8.0+ |
| DI | Koin | 4.1.1+ |
| Networking | Ktor | 3.0.3+ |
| DB | Room KMP | 2.8.4+ |
| Prefs | DataStore KMP | 1.1.1+ |
| Nav | Navigation Compose | 2.9.1+ |
| Images | Coil 3 | 3.0.4+ |
| DateTime | kotlinx-datetime | 0.6.1+ |
| Serialization | kotlinx-serialization | 1.7.3+ |
| Config | BuildKonfig | 0.17.1+ |
| Code gen | KSP | 2.3.0+ |
See the examples/ directory for ready-to-use scaffolds:
examples/feature-template/— Complete feature module with all layers wiredexamples/build-logic/— Convention plugin examples for multi-module buildsexamples/core-template/— Core module setup (network, database, DI)
This skill is grounded in official, production-tested documentation:
- Now in Android — Google's official Android architecture reference app
- Android Architecture Guide — Official Google architecture documentation
- KMP Documentation — JetBrains official KMP docs
- Compose Multiplatform — JetBrains official CMP docs
- Real-world production KMP project patterns
- Kotlin Multiplatform
- Compose Multiplatform
- Android Architecture Guide
- Now in Android
- Room KMP
- DataStore KMP
- Koin Multiplatform
- Ktor Client
- Navigation Compose
- Compose State Guide
- Compose Layouts
- Compose Multiplatform Resources (i18n)
- Predictive Back Gesture
- Paging 3
Contributions that improve the skill are welcome:
- Fork the repository
- Create a branch:
git checkout -b improve/feature-name - Update the skill file with accurate, tested patterns
- Reference official documentation for any new patterns added
- Submit a pull request with a clear description
What makes a good contribution: new expect/actual patterns, corrected library APIs, additional common pitfalls, updated version references.
MIT License — see LICENSE