skills/moai-lang-kotlin/SKILL.md
Kotlin 2.0 Multiplatform Enterprise Development with KMP, Coroutines, Compose Multiplatform, and Context7 MCP integration. Advanced patterns for mobile, backend, and cross-platform development.
npx skillsauth add ajbcoding/claude-skill-eval moai-lang-kotlinInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Kotlin 2.0 Multiplatform enterprise development with advanced async patterns, KMP architecture, and Compose Multiplatform UI. This skill provides patterns for mobile, backend, and cross-platform development with full Context7 MCP integration for real-time documentation access.
Automatic activation:
Manual invocation:
| Component | Version | Purpose | Status | |-----------|---------|---------|--------| | Kotlin | 2.0.20 | Core language | Current | | Coroutines | 1.8.0 | Async programming | Current | | Compose Multiplatform | 1.6.10 | UI framework | Current | | Serialization | 1.7.1 | JSON/data serialization | Current | | Ktor | 2.3.12 | HTTP client/server | Current | | Android Gradle Plugin | 8.5.0 | Android build | Current |
Kotlin's null safety is a game-changer for enterprise development:
// Smart null handling
val name: String? = "John"
val length = name?.length ?: 0 // Safe navigation + Elvis operator
// Type-safe IDs with inline classes
@JvmInline
value class UserId(val value: String)
// Sealed hierarchies for domain modeling
sealed class Result<T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
}
Key Benefits:
NullPointerException at compile timeEnterprise async patterns with built-in safety:
// Structured concurrency scope
coroutineScope {
val result1 = async { fetchData("API1") }
val result2 = async { fetchData("API2") }
awaitAll(result1, result2)
} // All coroutines cancelled if scope exits
// Context switching
withContext(Dispatchers.IO) {
val data = blockingIoCall() // Safe switching
}
// Error isolation with supervisor scope
supervisorScope {
launch { riskyOperation1() } // Failure doesn't affect others
launch { riskyOperation2() }
}
Key Benefits:
Powerful language extension without inheritance:
// Domain-specific languages (DSLs)
fun html(block: HtmlBuilder.() -> Unit): String {
val builder = HtmlBuilder()
builder.block()
return builder.build()
}
// Usage
val page = html {
h1("Welcome")
p("This is a paragraph")
}
// See examples.md for complete DSL patterns
kmp-enterprise-app/
├── shared/
│ ├── src/
│ │ ├── commonMain/kotlin/
│ │ │ ├── domain/ # Business logic
│ │ │ ├── data/ # Data layer
│ │ │ └── presentation/ # State management
│ │ ├── androidMain/kotlin/
│ │ ├── iosMain/kotlin/
│ │ └── commonTest/kotlin/
├── androidApp/
├── iosApp/
└── webApp/
// commonMain: Define interface
expect class PlatformDatabase {
suspend fun saveData(data: String): Result<Unit>
}
// androidMain: Android implementation
actual class PlatformDatabase {
actual suspend fun saveData(data: String) = try {
room.insert(data)
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
// iosMain: iOS implementation
actual class PlatformDatabase {
actual suspend fun saveData(data: String) = try {
coreData.save(data)
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
Key Pattern:
commonMain// Create cold flow (lazy)
fun getUsersFlow(): Flow<User> = flow {
while (true) {
val users = repository.fetchUsers()
emit(users)
delay(5000) // Refresh every 5 seconds
}
}
// Compose flows
getUsersFlow()
.map { it.copy(name = it.name.uppercase()) }
.filter { it.isActive }
.distinctUntilChanged()
.collect { updateUI(it) }
class CounterViewModel {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increment() { _count.value++ }
fun decrement() { _count.value-- }
}
// Observe state changes
viewModel.count.collect { count ->
updateUI("Count: $count")
}
@Composable
fun UserListScreen(users: List<User>) {
Column(modifier = Modifier.fillMaxSize()) {
Text("Users", style = MaterialTheme.typography.headlineLarge)
LazyColumn {
items(users) { user ->
UserCard(user)
}
}
}
}
@Composable
fun UserCard(user: User) {
Card(modifier = Modifier.fillMaxWidth().padding(8.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
Text(user.name, style = MaterialTheme.typography.titleMedium)
Text(user.email, color = Color.Gray)
}
}
}
Key Concepts:
val appModule = module {
single { HttpClient() }
single { UserRepository(get()) }
viewModel { UserListViewModel(get()) }
}
// Usage
val userService: UserService = get() // Injected automatically
// Result wrapper for safe operations
suspend fun fetchData(): Result<String> = try {
Result.success(apiCall())
} catch (e: Exception) {
Result.failure(e)
}
// Chain operations safely
fetchData()
.onSuccess { data -> updateUI(data) }
.onFailure { error -> showError(error) }
@Test
fun testAsync() = runTest {
val result = someAsyncFunction()
assertEquals("expected", result)
}
@Test
fun testWithMock() {
val repo = mockk<Repository>()
coEvery { repo.fetch("1") } returns "data"
// Verify behavior
coVerify { repo.fetch("1") }
}
This skill integrates with Context7 for real-time access to official documentation:
/kotlin/kotlin/kotlin/kotlinx.coroutines/kotlin/kotlin.multiplatform/jetbrains/compose-multiplatform/ktor/ktor/kotlin/kotlinx.serialization// Get latest coroutine patterns
val docs = mcp__context7__get-library-docs(
context7CompatibleLibraryID = "/kotlin/kotlinx.coroutines"
)
Use Sequence for lazy evaluation:
(1..1_000_000).asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.toList() // Only processes what's needed
Inline classes for zero-overhead:
@JvmInline
value class UserId(val value: String) // No allocation at runtime
Primitive arrays instead of boxed:
val intArray = IntArray(1000) // More efficient than Array<Int>
Tail recursion:
tailrec fun factorial(n: Int, acc: Int = 1): Int =
if (n <= 1) acc else factorial(n - 1, n * acc)
Coroutine pooling (automatic with structured concurrency)
// GOOD
coroutineScope {
val result = async { fetchData() }
}
// AVOID
GlobalScope.launch { fetchData() } // Never use
// GOOD
val user = repository.findUser(id)
?.let { updateUI(it) }
?: showNotFound()
// AVOID
val user = repository.findUser(id)!! // Unsafe
// GOOD
File("data.txt").bufferedReader().use { reader ->
reader.readLines()
} // Auto-closes
// GOOD
try {
// Use resource
} finally {
resource.close()
}
data class SecureUserInput(val email: String) {
init {
require(email.contains("@")) { "Invalid email" }
require(email.length <= 254) { "Email too long" }
}
}
expect class SecureStorage {
suspend fun store(key: String, value: String)
suspend fun retrieve(key: String): String?
}
// Certificate pinning
val client = HttpClient {
install(Auth) {
bearer {
loadTokens { getBearerTokens() }
}
}
}
| Category | Target | Tools | |----------|--------|-------| | Unit Tests | 80% | Kotest, MockK, runTest | | Integration Tests | 15% | Kotest, testcontainers | | UI Tests | 5% | Compose Test |
moai-foundation-trust (TRUST 5 quality gates)moai-foundation-security (Enterprise security)moai-foundation-testing (Testing strategies)moai-cc-mcp-integration (MCP integration)moai-essentials-debug (Debugging)examples.md (29 examples covering all patterns)reference.md (installation, commands, troubleshooting)Last updated: 2025-11-13
content-media
Download YouTube video transcripts when user provides a YouTube URL or asks to download/get/fetch a transcript from YouTube. Also use when user wants to transcribe or get captions/subtitles from a YouTube video.
development
Transform learning content (like YouTube transcripts, articles, tutorials) into actionable implementation plans using the Ship-Learn-Next framework. Use when user wants to turn advice, lessons, or educational content into concrete action steps, reps, or a learning quest.
tools
Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.
tools
Replace with description of the skill and when Claude should use it.