kotlin-multiplatform
Assists with KMP architectural decisions, including source set placement and managing cross-platform abstraction patterns.
Install
mkdir -p .claude/skills/kotlin-multiplatform && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2190" && unzip -o skill.zip -d .claude/skills/kotlin-multiplatform && rm skill.zipInstalls to .claude/skills/kotlin-multiplatform
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Platform abstraction decision-making for Amethyst KMP project. Guides when to abstract vs keep platform-specific,
source set placement (commonMain, jvmAndroid, platform-specific), expect/actual patterns. Covers primary targets
(Android, JVM/Desktop, iOS) with web/wasm future considerations. Integrates with gradle-expert for dependency issues.
Triggers on: abstraction decisions ("should I share this?"), source set placement questions, expect/actual creation,
build.gradle.kts work, incorrect placement detection, KMP dependency suggestions.Key capabilities
- →Advises on abstraction vs. duplication tradeoffs
- →Determines appropriate source set placement
- →Manages expect/actual pattern implementation
- →Detects platform-specific code in common modules
- →Suggests KMP dependency strategies
How it works
It applies a decision tree to evaluate if code should reside in `commonMain` or platform-specific sets based on platform API dependency and reuse frequency.
Inputs & outputs
When to use kotlin-multiplatform
- →Decide if code should be shared
- →Determine source set placement
- →Create expect/actual implementations
- →Detect incorrect platform code placement
About this skill
Kotlin Multiplatform: Platform Abstraction Decisions
Expert guidance for KMP architecture in Amethyst - deciding what to share vs keep platform-specific.
When to Use This Skill
Making platform abstraction decisions:
- "Should I create expect/actual or keep Android-only?"
- "Can I share this ViewModel logic?"
- "Where does this crypto/JSON/network implementation belong?"
- "This uses Android Context - can it be abstracted?"
- "Is this code in the wrong module?"
- Preparing for iOS/web/wasm targets
- Detecting incorrect placements
Abstraction Decision Tree
Central question: "Should this code be reused across platforms?"
Follow this decision path (< 1 minute):
Q: Is it used by 2+ platforms?
├─ NO → Keep platform-specific
│ Example: Android-only permission handling
│
└─ YES → Continue ↓
Q: Is it pure Kotlin (no platform APIs)?
├─ YES → commonMain
│ Example: Nostr event parsing, business rules
│
└─ NO → Continue ↓
Q: Does it vary by platform or by JVM vs non-JVM?
├─ By platform (Android ≠ iOS ≠ Desktop)
│ → expect/actual
│ Example: Secp256k1Instance (uses different security APIs)
│
├─ By JVM (Android = Desktop ≠ iOS/web)
│ → jvmAndroid
│ Example: Jackson JSON parsing (JVM library)
│
└─ Complex/UI-related
→ Keep platform-specific
Example: Navigation (Activity vs Window too different)
Final check:
Q: Maintenance cost of abstraction < duplication cost?
├─ YES → Proceed with abstraction
└─ NO → Duplicate (simpler)
Real Examples from Codebase
Crypto → expect/actual:
// commonMain - expect declaration
expect object Secp256k1Instance {
fun signSchnorr(data: ByteArray, privKey: ByteArray): ByteArray
}
// androidMain - uses Android Keystore
// jvmMain - uses Desktop JVM crypto
// iosMain - uses iOS Security framework
Why: Each platform has different security APIs.
JSON parsing → jvmAndroid:
// quartz/build.gradle.kts
val jvmAndroid = create("jvmAndroid") {
api(libs.jackson.module.kotlin)
}
Why: Jackson is JVM-only, works on Android + Desktop, not iOS/web.
Navigation → platform-specific:
- Android:
MainActivity(Activity + Compose Navigation) - Desktop:
Window+ sidebar + MenuBar Why: UI paradigms fundamentally different.
Mental Model: Source Sets as Dependency Graph
Think of source sets as a dependency graph, not folders.
┌─────────────────────────────────────────────┐
│ commonMain = Contract (pure Kotlin) │
│ - Business logic, protocol, data models │
│ - No platform APIs │
└────────────┬────────────────────────────────┘
│
├──────────────────────┬────────────────────
│ │
▼ ▼
┌───────────────────┐ ┌──────────────────┐
│ jvmAndroid │ │ iosMain │
│ JVM libs shared │ │ iOS common │
│ - Jackson │ │ │
│ - OkHttp │ └────┬─────────────┘
└───┬───────────┬───┘ │
│ │ │
▼ ▼ ├─→ iosArm64Main
┌─────────┐ ┌──────────┐ └─→ iosSimulatorArm64Main
│android │ │jvmMain │
│Main │ │(Desktop) │
└─────────┘ └──────────┘
Future: jsMain, wasmMain
Key insight: jvmAndroid is NOT a platform - it's a shared JVM layer.
The jvmAndroid Pattern
Unique to Amethyst. Shares JVM libraries between Android + Desktop.
When to Use jvmAndroid
Use jvmAndroid when:
- ✅ JVM-specific libraries (Jackson, OkHttp, url-detector)
- ✅ Android implementation = Desktop implementation (same JVM)
- ✅ Library doesn't work on iOS/web
Do NOT use jvmAndroid for:
- ❌ Pure Kotlin code (use commonMain)
- ❌ Platform-specific APIs (use androidMain/jvmMain)
- ❌ Code that should work on all platforms
Example from quartz/build.gradle.kts
// Must be defined BEFORE androidMain and jvmMain
val jvmAndroid = create("jvmAndroid") {
dependsOn(commonMain.get())
dependencies {
api(libs.jackson.module.kotlin) // JSON parsing - JVM only
api(libs.url.detector) // URL extraction - JVM only
implementation(libs.okhttp) // HTTP client - JVM only
}
}
// Both depend on jvmAndroid
jvmMain { dependsOn(jvmAndroid) }
androidMain { dependsOn(jvmAndroid) }
Why Jackson in jvmAndroid, not commonMain?
- Jackson is JVM-specific library
- Works on Android (runs on JVM)
- Works on Desktop (runs on JVM)
- Does NOT work on iOS (not JVM) or web (not JVM)
Web/wasm consideration: For future web support, consider migrating from Jackson → kotlinx.serialization (see Target-Specific Guidance).
What to Abstract vs Keep Platform-Specific
Quick decision guidelines based on codebase patterns:
Always Abstract
- Crypto (Secp256k1, encryption, signing)
- Core protocol logic (Nostr events, NIPs)
- Why: Needed everywhere, platform security APIs vary
Often Abstract
- I/O operations (file reading, caching)
- Logging (platform logging systems differ)
- Serialization (if using kotlinx.serialization)
- Why: Commonly reused, platform implementations available
Sometimes Abstract
- Business logic: YES - state machines, data processing
- ViewModels: YES - state + business logic shareable (StateFlow/SharedFlow)
- Screen layouts: NO - platform-native (Window vs Activity)
- Why: ViewModels contain platform-agnostic state; Screens render differently per platform
Rarely Abstract
- Complex UI components (composables with heavy platform dependencies)
- Why: Platform paradigms can differ significantly
Never Abstract
- Navigation (Activity vs Window fundamentally different)
- Permissions (Android vs iOS APIs incompatible)
- Platform UX patterns
- Why: Too platform-specific, abstraction creates leaky APIs
Evidence from shared-ui-analysis.md
| Component | Shared? | Rationale |
|---|---|---|
| PubKeyFormatter, ZapFormatter | ✅ YES | Pure Kotlin, no platform APIs |
| TimeAgoFormatter | ⚠️ ABSTRACTED | Needs StringProvider for localized strings |
| ViewModels (state + logic) | ✅ YES | StateFlow/SharedFlow platform-agnostic, Compose Multiplatform lifecycle compatible |
| Screen layouts (Scaffold, nav) | ❌ NO | Window vs Activity, sidebar vs bottom nav fundamentally different |
| Image loading (Coil) | ⚠️ ABSTRACTED | Coil 3.x supports KMP, needs expect/actual wrapper |
expect/actual Mechanics
When to use: Code needed by 2+ platforms, varies by platform.
Pattern Categories from Codebase
Objects (singletons):
// 24 expect declarations found, common pattern:
expect object Secp256k1Instance { ... }
expect object Log { ... }
expect object LibSodiumInstance { ... }
Classes (instantiable):
expect class AESCBC { ... }
expect class DigestInstance { ... }
Functions (utilities):
expect fun platform(): String
expect fun currentTimeSeconds(): Long
See references/expect-actual-catalog.md for complete catalog with rationale.
Target-Specific Guidance
Android, JVM (Desktop), iOS - Current Primary Targets
Status: Mature patterns, stable APIs
Android (androidMain):
- Uses Android framework (Activity, Context, etc.)
- secp256k1-kmp-jni-android (
0.23.0inlibs.versions.toml) for crypto - AndroidX libraries
Desktop JVM (jvmMain):
- Uses Compose Desktop (Window, MenuBar, etc.)
- secp256k1-kmp-jni-jvm (same
0.23.0line) for crypto - Pure JVM libraries
iOS (iosMain):
- Mature target — actively built and tested
- Architecture targets: iosArm64, iosSimulatorArm64, iosX64 (plus macosArm64 for host tooling)
- Platform APIs via platform.posix, Security framework
Web, wasm - Future Targets
Status: Not yet implemented, consider for future-proofing
Constraints to know:
- ❌ No platform.posix (file I/O different)
- ❌ No JVM libraries (Jackson, OkHttp won't work)
- ❌ Different async model (JS event loop vs threads)
Future-proofing tips:
- Prefer pure Kotlin in commonMain
- Use kotlinx.* libraries:
- kotlinx.serialization instead of Jackson
- ktor instead of OkHttp (ktor supports web)
- kotlinx.datetime instead of custom date handling
- Avoid platform.posix for file operations
- Test abstractions work without JVM assumptions
Example migration path:
// Current: jvmAndroid (JVM-only)
api(libs.jackson.module.kotlin)
// Future: commonMain (all platforms)
api(libs.kotlinx.serialization.json)
Integration: When to Invoke Other Skills
Invoke gradle-expert
Trigger gradle-expert skill when encountering:
- Dependency conflicts (e.g., secp256k1-android vs secp256k1-jvm version mismatch)
- Build errors related to source sets
- Version catalog issues (libs.versions.toml)
- "Duplicate class" errors
- Performance/build time issues
Example trigger:
Error: Duplicate class found: fr.acinq.secp256k1.Secp256k1
→ Invoke gradle-expert for dependency conflict resolution.
Flags to Raise
Platform code in commonMain:
// ❌ INCORRECT - Android API in commonMain
expect fun getContext(): Context // Context is Android-only!
→ Flag: "Android API in commonMain won't compile on other platforms"
Duplicated business logic:
// ❌ INCORRECT - Same logic in both
// androidMain/.../CryptoUtils.kt
fun validateSignature(...) { ... }
// jvmMain/.../CryptoUtils.kt
fun validateSignature(...) { ... } // Duplicated!
→ Flag: "Business logic duplicated, should be in commonMain or expect/actual"
Reinventing wheel - suggest KMP alternatives:
- Custom date/time → kotlinx.datetime
- OkHttp → ktor (supports web)
- Jackson → kotlinx.serialization
- Custom UUID → kotlinx.uuid (when stable)
Common Pitfalls
1. Over-Abstraction
Problem: Creating expect/actual for UI components
// ❌ BAD
expect fun Navigatio
---
*Content truncated.*
When not to use it
- →Pure Android-only application development
- →Projects not intended for multiplatform sharing
- →Cases where abstraction costs exceed duplication benefits
Limitations
- →Abstraction recommendations are subjective to project goals
- →Requires knowledge of the specific target platforms
- →Complex UI logic remains difficult to abstract
How it compares
It provides architectural guidance specific to the KMP ecosystem rather than general coding advice.
Compared to similar skills
kotlin-multiplatform side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| kotlin-multiplatform (this skill) | 32 | 3mo | Review | Advanced |
| android-clean-architecture | 0 | 1mo | No flags | Intermediate |
| android-kotlin-development | 268 | 5mo | Review | Advanced |
| backend-microservice-development | 2 | 3mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by vitorpamplona
View all by vitorpamplona →You might also like
android-clean-architecture
farhankabir133
Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns.
android-kotlin-development
aj-geddes
Develop native Android apps with Kotlin. Covers MVVM with Jetpack, Compose for modern UI, Retrofit for API calls, Room for local storage, and navigation architecture.
backend-microservice-development
TencentBlueKing
后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。
kmp-cmp-app-builder
firdaus1453
>
android-architecture
huyhunhngc
>
mobile-architect-agent
srednoff888-art
Agent profile for coordinate mobile app architecture across iOS, Android, Expo/React Native, offline states, permissions, and releases. Use when Codex needs a specialist agent perspective for planning, implementation, review, debugging, validation, or handoff in this domain.