android-sdd 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +27 -0
  3. package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
  4. package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
  5. package/skills/Android Platform/Configuration/SKILL.md +201 -0
  6. package/skills/Android Platform/Filesystem/SKILL.md +216 -0
  7. package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
  8. package/skills/Android Platform/Manifest/SKILL.md +226 -0
  9. package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
  10. package/skills/Android Platform/Resources/SKILL.md +234 -0
  11. package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
  12. package/skills/Android Platform/State Restoration/SKILL.md +210 -0
  13. package/skills/Architecture/Bounded Context/SKILL.md +207 -0
  14. package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
  15. package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
  16. package/skills/Architecture/Entity Design/SKILL.md +243 -0
  17. package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
  18. package/skills/Architecture/MVI/SKILL.md +224 -0
  19. package/skills/Architecture/MVVM/SKILL.md +198 -0
  20. package/skills/Architecture/Modularization/SKILL.md +194 -0
  21. package/skills/Architecture/Offline First/SKILL.md +249 -0
  22. package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
  23. package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
  24. package/skills/Architecture/State Management/SKILL.md +229 -0
  25. package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
  26. package/skills/Architecture/Use Case Design/SKILL.md +244 -0
  27. package/skills/Architecture/Value Object/SKILL.md +226 -0
  28. package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
  29. package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
  30. package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
  31. package/skills/Build System/Build Cache/SKILL.md +233 -0
  32. package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
  33. package/skills/Build System/Build Variant/SKILL.md +215 -0
  34. package/skills/Build System/Convention Plugin/SKILL.md +288 -0
  35. package/skills/Build System/Dependency Management/SKILL.md +261 -0
  36. package/skills/Build System/Gradle/SKILL.md +284 -0
  37. package/skills/Build System/Incremental Build/SKILL.md +199 -0
  38. package/skills/Build System/KAPT/SKILL.md +198 -0
  39. package/skills/Build System/KSP/SKILL.md +263 -0
  40. package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
  41. package/skills/Build System/Specialized/C++/SKILL.md +308 -0
  42. package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
  43. package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
  44. package/skills/Build System/Version Catalog/SKILL.md +304 -0
  45. package/skills/Concurrency/Background Processing/SKILL.md +185 -0
  46. package/skills/Concurrency/Channel/SKILL.md +207 -0
  47. package/skills/Concurrency/Coroutine/SKILL.md +200 -0
  48. package/skills/Concurrency/Flow/SKILL.md +179 -0
  49. package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
  50. package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
  51. package/skills/Concurrency/StateFlow/SKILL.md +175 -0
  52. package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
  53. package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
  54. package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
  55. package/skills/Core Language/DSL/SKILL.md +186 -0
  56. package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
  57. package/skills/Core Language/Immutability/SKILL.md +156 -0
  58. package/skills/Core Language/KMP/SKILL.md +182 -0
  59. package/skills/Core Language/Kotlin/SKILL.md +187 -0
  60. package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
  61. package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
  62. package/skills/Core Language/Serialization/SKILL.md +191 -0
  63. package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
  64. package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
  65. package/skills/Data Layer/DAO/SKILL.md +225 -0
  66. package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
  67. package/skills/Data Layer/DataStore/SKILL.md +264 -0
  68. package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
  69. package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
  70. package/skills/Data Layer/File Storage/SKILL.md +247 -0
  71. package/skills/Data Layer/Indexing/SKILL.md +184 -0
  72. package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
  73. package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
  74. package/skills/Data Layer/Migration/SKILL.md +243 -0
  75. package/skills/Data Layer/Paging/SKILL.md +264 -0
  76. package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
  77. package/skills/Data Layer/Room/SKILL.md +244 -0
  78. package/skills/Data Layer/SQLite/SKILL.md +255 -0
  79. package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
  80. package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
  81. package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
  82. package/skills/Dependency Injection/Koin/SKILL.md +282 -0
  83. package/skills/Developer Experience/Detekt/SKILL.md +272 -0
  84. package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
  85. package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
  86. package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
  87. package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
  88. package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
  89. package/skills/Media/Audio/SKILL.md +257 -0
  90. package/skills/Media/Camera/SKILL.md +229 -0
  91. package/skills/Media/CameraX/SKILL.md +295 -0
  92. package/skills/Media/ExoPlayer/SKILL.md +258 -0
  93. package/skills/Media/Video/SKILL.md +228 -0
  94. package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
  95. package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
  96. package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
  97. package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
  98. package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
  99. package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
  100. package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
  101. package/skills/Navigation/Navigation/SKILL.md +215 -0
  102. package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
  103. package/skills/Networking/API Contract/SKILL.md +220 -0
  104. package/skills/Networking/Authentication/SKILL.md +210 -0
  105. package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
  106. package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
  107. package/skills/Networking/Ktor/SKILL.md +219 -0
  108. package/skills/Networking/Multipart Upload/SKILL.md +213 -0
  109. package/skills/Networking/OkHttp/SKILL.md +193 -0
  110. package/skills/Networking/REST/SKILL.md +178 -0
  111. package/skills/Networking/Rate Limiting/SKILL.md +170 -0
  112. package/skills/Networking/Retrofit/SKILL.md +241 -0
  113. package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
  114. package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
  115. package/skills/Networking/WebSocket/SKILL.md +224 -0
  116. package/skills/Observability/Crash Reporting/SKILL.md +219 -0
  117. package/skills/Observability/Logging/SKILL.md +168 -0
  118. package/skills/Observability/Metrics/SKILL.md +227 -0
  119. package/skills/Observability/Structured Logging/SKILL.md +234 -0
  120. package/skills/Performance/ANR Prevention/SKILL.md +192 -0
  121. package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
  122. package/skills/Performance/App Startup/SKILL.md +183 -0
  123. package/skills/Performance/Baseline Profile/SKILL.md +205 -0
  124. package/skills/Performance/Battery Optimization/SKILL.md +192 -0
  125. package/skills/Performance/Benchmark/SKILL.md +182 -0
  126. package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
  127. package/skills/Performance/Compose Optimization/SKILL.md +187 -0
  128. package/skills/Performance/Heap Management/SKILL.md +184 -0
  129. package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
  130. package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
  131. package/skills/Performance/Rendering Performance/SKILL.md +205 -0
  132. package/skills/Performance/Startup Optimization/SKILL.md +219 -0
  133. package/skills/Security/Biometric/SKILL.md +224 -0
  134. package/skills/Security/Certificate Transparency/SKILL.md +158 -0
  135. package/skills/Security/Cryptography/SKILL.md +244 -0
  136. package/skills/Security/Encrypted Storage/SKILL.md +273 -0
  137. package/skills/Security/Frida Detection/SKILL.md +230 -0
  138. package/skills/Security/Hook Detection/SKILL.md +197 -0
  139. package/skills/Security/Keystore/SKILL.md +272 -0
  140. package/skills/Security/Network Security Config/SKILL.md +186 -0
  141. package/skills/Security/Obfuscation/SKILL.md +226 -0
  142. package/skills/Security/Proguard/SKILL.md +202 -0
  143. package/skills/Security/R8/SKILL.md +234 -0
  144. package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
  145. package/skills/Security/Root Detection/SKILL.md +220 -0
  146. package/skills/Security/Secure Networking/SKILL.md +220 -0
  147. package/skills/System Integration/AlarmManager/SKILL.md +182 -0
  148. package/skills/System Integration/App Widget/SKILL.md +182 -0
  149. package/skills/System Integration/Deep Link/SKILL.md +187 -0
  150. package/skills/System Integration/Foreground Service/SKILL.md +212 -0
  151. package/skills/System Integration/Notification/SKILL.md +237 -0
  152. package/skills/System Integration/WorkManager/SKILL.md +256 -0
  153. package/skills/System Integration/clipboard/SKILL.md +155 -0
  154. package/skills/System Integration/share-intent/SKILL.md +182 -0
  155. package/skills/Testing/Compose Testing/SKILL.md +296 -0
  156. package/skills/Testing/Espresso/SKILL.md +292 -0
  157. package/skills/Testing/Fake Data/SKILL.md +245 -0
  158. package/skills/Testing/Integration Testing/SKILL.md +288 -0
  159. package/skills/Testing/Mocking/SKILL.md +229 -0
  160. package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
  161. package/skills/Testing/UI Testing/SKILL.md +293 -0
  162. package/skills/Testing/Unit Testing/SKILL.md +309 -0
  163. package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
  164. package/skills/UI System/Compose/SKILL.md +296 -0
  165. package/skills/UI System/Compose Animation/SKILL.md +281 -0
  166. package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
  167. package/skills/UI System/Compose Navigation/SKILL.md +255 -0
  168. package/skills/UI System/Compose Performance/SKILL.md +274 -0
  169. package/skills/UI System/Design System/SKILL.md +217 -0
  170. package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
  171. package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
  172. package/skills/UI System/Loading Strategy/SKILL.md +254 -0
  173. package/skills/UI System/Material 3/SKILL.md +279 -0
  174. package/skills/UI System/RTL/SKILL.md +179 -0
  175. package/src/index.ts +182 -0
  176. package/tsconfig.json +19 -0
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: extension-functions-design
3
+ description: >
4
+ Design principles and patterns for Kotlin extension functions in Android.
5
+ Load this skill when deciding whether to use an extension function,
6
+ where to place it, how to scope it, and how to avoid common misuse patterns.
7
+ ---
8
+
9
+ # Extension Functions Design
10
+
11
+ ## Overview
12
+
13
+ Extension functions add behavior to existing types without inheritance or modification. They are one of Kotlin's most powerful features but must be used with discipline — overuse leads to scattered, hard-to-discover code.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Extensions are **discoverable utilities**, not replacements for proper design
20
+ - Only extend types **you don't own** or when inheritance is impossible
21
+ - If you own the type, **add the method directly** — don't use an extension
22
+ - Extensions must be **stateless and pure** — no side effects, no hidden dependencies
23
+ - Place extensions **close to where they're used** — not in a global utils file
24
+
25
+ ---
26
+
27
+ ## When to Use Extension Functions
28
+
29
+ | Situation | Use Extension? |
30
+ | ---------------------------------------------------------------- | ---------------------------------- |
31
+ | Adding utility to stdlib types (`String`, `List`, `Int`) | ✅ Yes |
32
+ | Adding Android-specific helpers to `Context`, `View`, `Fragment` | ✅ Yes |
33
+ | Adding behavior to a class you own | ❌ No — add method directly |
34
+ | Replacing a utility class method | ✅ Yes |
35
+ | Adding domain logic to a domain model | ❌ No — add to the class or UseCase |
36
+ | Bypassing encapsulation to access internals | ❌ Never |
37
+
38
+ ---
39
+
40
+ ## Placement Strategy
41
+
42
+ ```
43
+ // ✅ Place extensions next to the type they extend
44
+ // If extending Context → ContextExtensions.kt
45
+ // If extending String → StringExtensions.kt
46
+ // If extending View → ViewExtensions.kt
47
+
48
+ // ✅ Place feature-specific extensions inside the feature package
49
+ // feature/auth/AuthExtensions.kt — extensions only used in auth
50
+ // NOT in a global utils/Extensions.kt that grows forever
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Stdlib Extensions
56
+
57
+ ```kotlin
58
+ // ✅ String utilities
59
+ fun String.toSlug(): String =
60
+ lowercase().replace(" ", "-").replace(Regex("[^a-z0-9-]"), "")
61
+
62
+ fun String.isValidEmail(): Boolean =
63
+ android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches()
64
+
65
+ fun String?.orEmpty(): String = this ?: ""
66
+
67
+ // ✅ Number formatting
68
+ fun Int.toPx(context: Context): Int =
69
+ (this * context.resources.displayMetrics.density).toInt()
70
+
71
+ fun Long.toFormattedDate(): String =
72
+ SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(this))
73
+
74
+ // ✅ Collection utilities
75
+ fun <T> List<T>.second(): T = this[1]
76
+ fun <T> List<T>.indexOfFirstOrNull(predicate: (T) -> Boolean): Int? =
77
+ indexOfFirst(predicate).takeIf { it >= 0 }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Android Platform Extensions
83
+
84
+ ```kotlin
85
+ // ✅ Context extensions
86
+ fun Context.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
87
+ Toast.makeText(this, message, duration).show()
88
+ }
89
+
90
+ fun Context.getColorCompat(@ColorRes colorRes: Int): Int =
91
+ ContextCompat.getColor(this, colorRes)
92
+
93
+ fun Context.dpToPx(dp: Float): Int =
94
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()
95
+
96
+ // ✅ View extensions
97
+ fun View.show() { visibility = View.VISIBLE }
98
+ fun View.hide() { visibility = View.GONE }
99
+ fun View.invisible() { visibility = View.INVISIBLE }
100
+
101
+ fun View.setOnSingleClickListener(action: () -> Unit) {
102
+ var lastClickTime = 0L
103
+ setOnClickListener {
104
+ val now = System.currentTimeMillis()
105
+ if (now - lastClickTime > 500) {
106
+ lastClickTime = now
107
+ action()
108
+ }
109
+ }
110
+ }
111
+
112
+ // ✅ Fragment extensions
113
+ fun Fragment.hideKeyboard() {
114
+ val imm = requireContext().getSystemService(InputMethodManager::class.java)
115
+ imm.hideSoftInputFromWindow(requireView().windowToken, 0)
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Flow / Coroutine Extensions
122
+
123
+ ```kotlin
124
+ // ✅ Lifecycle-aware collection helper
125
+ fun <T> Flow<T>.collectWithLifecycle(
126
+ lifecycleOwner: LifecycleOwner,
127
+ state: Lifecycle.State = Lifecycle.State.STARTED,
128
+ block: suspend (T) -> Unit
129
+ ) {
130
+ lifecycleOwner.lifecycleScope.launch {
131
+ lifecycleOwner.repeatOnLifecycle(state) {
132
+ collect { block(it) }
133
+ }
134
+ }
135
+ }
136
+
137
+ // ✅ Result extensions
138
+ fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
139
+ if (isSuccess) action(getOrThrow())
140
+ return this
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Scoping with Companion Objects
147
+
148
+ ```kotlin
149
+ // ✅ Scope extension to a specific context using companion object
150
+ class UserValidator {
151
+ companion object // empty companion — allows scoped extensions
152
+ }
153
+
154
+ fun UserValidator.Companion.isValidAge(age: Int): Boolean = age in 18..120
155
+
156
+ // Usage
157
+ UserValidator.isValidAge(25)
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Anti-Patterns
163
+
164
+ ```kotlin
165
+ // ❌ Extending a class you own — add the method directly
166
+ class User(val name: String)
167
+ fun User.displayName() = name.trim() // wrong — add to User class
168
+
169
+ // ❌ Extension that accesses internal state via reflection or casting
170
+ fun Any.forceGetField(name: String): Any? { ... } // bypasses encapsulation
171
+
172
+ // ❌ Extension with hidden dependencies
173
+ fun String.sendToAnalytics() {
174
+ AnalyticsSingleton.track(this) // hidden side effect — not obvious from signature
175
+ }
176
+
177
+ // ❌ Giant global Extensions.kt file
178
+ // utils/Extensions.kt with 500 lines of unrelated extensions
179
+ // → split by type and feature
180
+
181
+ // ❌ Extension that duplicates stdlib
182
+ fun List<Int>.mySum() = reduce { acc, i -> acc + i } // use sum() instead
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Related Skills
188
+
189
+ - `kotlin` — core Kotlin language conventions
190
+ - `dsl` — extension functions as DSL building blocks
191
+ - `reactive-streams` — Flow extension patterns
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: immutability
3
+ description: >
4
+ Immutability patterns and enforcement for Android/Kotlin development.
5
+ Load this skill when designing data models, state classes, collections,
6
+ or any shared data structure to ensure thread safety and predictable behavior.
7
+ ---
8
+
9
+ # Immutability
10
+
11
+ ## Overview
12
+
13
+ Immutability means that once an object is created, its state cannot change. In Android development, immutability is critical for thread safety, predictable UI state, and preventing hard-to-debug side effects.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - Default to `val` — only use `var` when mutation is genuinely required
20
+ - Default to immutable collections — only use mutable when building
21
+ - State should flow in one direction — never mutate state from outside
22
+ - Shared data across threads must always be immutable
23
+
24
+ ---
25
+
26
+ ## Properties
27
+
28
+ ```kotlin
29
+ // ✅ val by default
30
+ data class User(val id: String, val name: String, val email: String)
31
+
32
+ // ✅ var only when genuinely needed (e.g., local accumulator)
33
+ var count = 0
34
+ repeat(10) { count++ }
35
+
36
+ // ❌ var on a data class field shared across layers
37
+ data class User(var name: String) // mutability leaks outside
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Data Classes and copy()
43
+
44
+ ```kotlin
45
+ // ✅ Use copy() to produce new state — never mutate
46
+ data class UiState(
47
+ val isLoading: Boolean = false,
48
+ val items: List<Item> = emptyList(),
49
+ val error: String? = null
50
+ )
51
+
52
+ // In ViewModel
53
+ _uiState.update { it.copy(isLoading = true) }
54
+ _uiState.update { it.copy(isLoading = false, items = newItems) }
55
+
56
+ // ❌ Never do this
57
+ _uiState.value.items = newItems // not possible with val, but don't expose mutable state
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Collections
63
+
64
+ ```kotlin
65
+ // ✅ Expose immutable collections from all public APIs
66
+ class UserRepository {
67
+ fun getUsers(): List<User> = _users.toList() // defensive copy
68
+ }
69
+
70
+ // ✅ Build with mutable, expose as immutable
71
+ val users: List<User> = buildList {
72
+ add(User("1", "Ali"))
73
+ add(User("2", "Sara"))
74
+ }
75
+
76
+ // ✅ StateFlow always holds immutable state
77
+ private val _uiState = MutableStateFlow(UiState())
78
+ val uiState: StateFlow<UiState> = _uiState.asStateFlow()
79
+
80
+ // ❌ Never expose MutableStateFlow or MutableList
81
+ val uiState = MutableStateFlow(UiState()) // external code can modify
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Immutable State in ViewModel
87
+
88
+ ```kotlin
89
+ // ✅ Correct pattern — immutable state, controlled updates
90
+ class UserViewModel : ViewModel() {
91
+
92
+ private val _state = MutableStateFlow(UserUiState())
93
+ val state: StateFlow<UserUiState> = _state.asStateFlow()
94
+
95
+ fun onNameChanged(name: String) {
96
+ _state.update { it.copy(name = name) }
97
+ }
98
+ }
99
+
100
+ // ✅ State class — all vals
101
+ data class UserUiState(
102
+ val name: String = "",
103
+ val isLoading: Boolean = false,
104
+ val error: String? = null
105
+ )
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Immutability Across Layers
111
+
112
+ | Layer | Rule |
113
+ | ----------------------- | ------------------------------------------------ |
114
+ | Domain models | Always immutable (`data class` with `val`) |
115
+ | DTOs | Always immutable (`data class` with `val`) |
116
+ | UI State | Always immutable — update via `copy()` |
117
+ | Repository return types | Return `List<T>` not `MutableList<T>` |
118
+ | Exposed flows | Always `StateFlow`/`Flow` not `MutableStateFlow` |
119
+
120
+ ---
121
+
122
+ ## Thread Safety Through Immutability
123
+
124
+ ```kotlin
125
+ // ✅ Immutable objects are safe to share across coroutines
126
+ data class Config(val baseUrl: String, val timeout: Long)
127
+
128
+ // Safe — no synchronization needed
129
+ val config = Config("https://api.example.com", 30_000)
130
+ launch(Dispatchers.IO) { fetchData(config) }
131
+ launch(Dispatchers.Default) { processData(config) }
132
+
133
+ // ❌ Mutable shared state requires synchronization
134
+ class Config {
135
+ var baseUrl: String = "" // race condition if accessed from multiple threads
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Anti-Patterns
142
+
143
+ - `var` properties on domain models or state classes
144
+ - Exposing `MutableList`, `MutableMap`, or `MutableStateFlow` from public APIs
145
+ - Mutating a list after exposing it — always return a defensive copy
146
+ - Using `apply {}` to mutate an object after it's been shared
147
+ - Casting `List<T>` to `MutableList<T>` — breaks immutability contract
148
+
149
+ ---
150
+
151
+ ## Related Skills
152
+
153
+ - `kotlin` — `val`/`var` and data class conventions
154
+ - `state-management` — UI state modeling with immutable data
155
+ - `coroutine` — thread safety with immutable shared state
156
+ - `repository-pattern` — immutable return types from repositories
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: kmp
3
+ description: >
4
+ Kotlin Multiplatform (KMP) setup, structure, and best practices.
5
+ Load this skill when setting up a KMP project, sharing code between
6
+ Android and other platforms, or deciding what belongs in shared vs
7
+ platform-specific modules.
8
+ ---
9
+
10
+ # Kotlin Multiplatform (KMP)
11
+
12
+ ## Overview
13
+
14
+ KMP allows sharing Kotlin code across platforms (Android, iOS, Desktop, Web) while keeping platform-specific implementations separate. The goal is to maximize shared logic while respecting platform boundaries.
15
+
16
+ ---
17
+
18
+ ## Core Principles
19
+
20
+ - Share **business logic** — not UI, not platform APIs
21
+ - Use `expect/actual` only when necessary — prefer interface + DI
22
+ - Keep shared code free of any platform dependency
23
+ - The `commonMain` module must never import Android or iOS specific APIs
24
+
25
+ ---
26
+
27
+ ## Module Structure
28
+
29
+ ```
30
+ project/
31
+ ├── shared/
32
+ │ ├── src/
33
+ │ │ ├── commonMain/kotlin/ ← shared business logic
34
+ │ │ ├── commonTest/kotlin/ ← shared unit tests
35
+ │ │ ├── androidMain/kotlin/ ← Android actual implementations
36
+ │ │ └── iosMain/kotlin/ ← iOS actual implementations
37
+ ├── androidApp/ ← Android UI & entry point
38
+ └── iosApp/ ← iOS UI & entry point
39
+ ```
40
+
41
+ ---
42
+
43
+ ## What Goes Where
44
+
45
+ | Layer | commonMain | androidMain / iosMain |
46
+ | -------------------------- | ---------- | --------------------- |
47
+ | Domain models | ✅ | ❌ |
48
+ | Use cases | ✅ | ❌ |
49
+ | Repository interfaces | ✅ | ❌ |
50
+ | Repository implementations | ❌ | ✅ |
51
+ | Network (Ktor) | ✅ | ❌ |
52
+ | Database (SQLDelight) | ✅ schema | ✅ driver |
53
+ | UI | ❌ | ✅ |
54
+ | Platform APIs | ❌ | ✅ |
55
+
56
+ ---
57
+
58
+ ## expect / actual Pattern
59
+
60
+ ### Prefer interface + DI over expect/actual
61
+
62
+ ```kotlin
63
+ // ✅ Preferred — interface in commonMain, implementation injected
64
+ interface PlatformLogger {
65
+ fun log(message: String)
66
+ }
67
+
68
+ // androidMain
69
+ class AndroidLogger : PlatformLogger {
70
+ override fun log(message: String) = Log.d("App", message)
71
+ }
72
+ ```
73
+
74
+ ### Use expect/actual only for simple platform utilities
75
+
76
+ ```kotlin
77
+ // commonMain
78
+ expect fun getCurrentTimeMillis(): Long
79
+
80
+ // androidMain
81
+ actual fun getCurrentTimeMillis(): Long = System.currentTimeMillis()
82
+
83
+ // iosMain
84
+ actual fun getCurrentTimeMillis(): Long =
85
+ NSDate().timeIntervalSince1970.toLong() * 1000
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Networking — Ktor (shared)
91
+
92
+ ```kotlin
93
+ // commonMain — use Ktor, not Retrofit (Retrofit is Android-only)
94
+ val client = HttpClient {
95
+ install(ContentNegotiation) {
96
+ json(Json { ignoreUnknownKeys = true })
97
+ }
98
+ install(HttpTimeout) {
99
+ requestTimeoutMillis = 30_000
100
+ }
101
+ }
102
+ ```
103
+
104
+ ## Database — SQLDelight (shared schema)
105
+
106
+ ```kotlin
107
+ // commonMain — define schema in .sq files
108
+ // androidMain — provide AndroidSqliteDriver
109
+ // iosMain — provide NativeSqliteDriver
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Coroutines in KMP
115
+
116
+ ```kotlin
117
+ // ✅ Use kotlinx.coroutines in commonMain
118
+ // ✅ Use Dispatchers.Default for CPU work in common code
119
+ // ✅ Use platform dispatcher injection for UI thread
120
+
121
+ // androidMain
122
+ val uiDispatcher: CoroutineDispatcher = Dispatchers.Main
123
+
124
+ // iosMain
125
+ val uiDispatcher: CoroutineDispatcher = Dispatchers.Main
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Gradle Setup (libs.versions.toml)
131
+
132
+ ```toml
133
+ [versions]
134
+ kotlin = "2.0.0"
135
+ kmp = "2.0.0"
136
+
137
+ [plugins]
138
+ kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
139
+ ```
140
+
141
+ ```kotlin
142
+ // shared/build.gradle.kts
143
+ kotlin {
144
+ androidTarget()
145
+ iosX64()
146
+ iosArm64()
147
+ iosSimulatorArm64()
148
+
149
+ sourceSets {
150
+ commonMain.dependencies {
151
+ implementation(libs.ktor.client.core)
152
+ implementation(libs.kotlinx.coroutines.core)
153
+ implementation(libs.kotlinx.serialization.json)
154
+ }
155
+ androidMain.dependencies {
156
+ implementation(libs.ktor.client.okhttp)
157
+ }
158
+ iosMain.dependencies {
159
+ implementation(libs.ktor.client.darwin)
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Anti-Patterns
168
+
169
+ - Importing `android.*` in `commonMain` — breaks iOS compilation
170
+ - Using Retrofit in shared code — it's Android-only; use Ktor
171
+ - Putting UI logic in `commonMain` — UI must stay platform-specific
172
+ - Overusing `expect/actual` — prefer interface + DI for testability
173
+ - Sharing ViewModels in commonMain — keep ViewModels platform-specific
174
+
175
+ ---
176
+
177
+ ## Related Skills
178
+
179
+ - `kotlin` — Kotlin language conventions
180
+ - `coroutine` — coroutine patterns in shared and platform code
181
+ - `serialization` — Kotlinx Serialization setup for KMP
182
+ - `ktor` — Ktor client setup and usage
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: kotlin
3
+ description: >
4
+ Kotlin language conventions and best practices for Android development.
5
+ Load this skill whenever writing, reviewing, or refactoring any Kotlin code.
6
+ Covers idioms, language features, and patterns that should be consistently
7
+ applied across the entire codebase.
8
+ ---
9
+
10
+ # Kotlin
11
+
12
+ ## Overview
13
+
14
+ Kotlin is the primary language for Android development. This skill defines which language features to use, when to use them, and which patterns to avoid.
15
+
16
+ ---
17
+
18
+ ## Core Principles
19
+
20
+ - Prefer **idiomatic Kotlin** over Java-style code
21
+ - Prefer **immutability** by default (`val` over `var`, `data class`, `copy()`)
22
+ - Prefer **null safety** at compile time — minimize nullable types
23
+ - Prefer **expression over statement** where it improves readability
24
+ - Never use `!!` — always handle nullability explicitly
25
+
26
+ ---
27
+
28
+ ## Language Features
29
+
30
+ ### Null Safety
31
+
32
+ ```kotlin
33
+ // ✅ Use safe call + elvis
34
+ val name = user?.name ?: "Unknown"
35
+
36
+ // ✅ Use let for nullable execution
37
+ user?.let { sendEmail(it) }
38
+
39
+ // ❌ Never force-unwrap
40
+ val name = user!!.name
41
+ ```
42
+
43
+ ### Data Classes
44
+
45
+ ```kotlin
46
+ // ✅ Use data class for value holders
47
+ data class User(val id: String, val name: String)
48
+
49
+ // ✅ Use copy() for mutation
50
+ val updated = user.copy(name = "Ali")
51
+
52
+ // ❌ Never mutate fields directly
53
+ user.name = "Ali"
54
+ ```
55
+
56
+ ### Sealed Classes
57
+
58
+ ```kotlin
59
+ // ✅ Use sealed class for exhaustive state modeling
60
+ sealed class Result<out T> {
61
+ data class Success<T>(val data: T) : Result<T>()
62
+ data class Error(val exception: Throwable) : Result<Nothing>()
63
+ object Loading : Result<Nothing>()
64
+ }
65
+
66
+ // ✅ Always use when exhaustively — no else branch
67
+ when (result) {
68
+ is Result.Success -> showData(result.data)
69
+ is Result.Error -> showError(result.exception)
70
+ is Result.Loading -> showLoading()
71
+ }
72
+ ```
73
+
74
+ ### Extension Functions
75
+
76
+ ```kotlin
77
+ // ✅ Use for adding behavior to existing types without inheritance
78
+ fun String.toFormattedDate(): String { ... }
79
+
80
+ // ✅ Use for scoping utility functions to a receiver
81
+ fun Context.showToast(message: String) {
82
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
83
+ }
84
+
85
+ // ❌ Don't use extension functions to bypass encapsulation
86
+ // ❌ Don't define extensions on types you own — add the method directly
87
+ ```
88
+
89
+ ### Scope Functions
90
+
91
+ ```kotlin
92
+ // ✅ let — nullable transformation or scoped execution
93
+ val length = text?.let { it.trim().length }
94
+
95
+ // ✅ apply — object configuration / builder pattern
96
+ val intent = Intent().apply {
97
+ putExtra("key", value)
98
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
99
+ }
100
+
101
+ // ✅ run — transformation on receiver
102
+ val result = user.run { "$name ($email)" }
103
+
104
+ // ✅ also — side effects (logging, debugging)
105
+ val user = createUser().also { log("User created: $it") }
106
+
107
+ // ❌ Don't nest scope functions more than 2 levels deep
108
+ // ❌ Don't use scope functions just for style — only when they add clarity
109
+ ```
110
+
111
+ ### When Expression
112
+
113
+ ```kotlin
114
+ // ✅ Use when as an expression
115
+ val label = when (status) {
116
+ Status.ACTIVE -> "Active"
117
+ Status.INACTIVE -> "Inactive"
118
+ Status.PENDING -> "Pending"
119
+ }
120
+
121
+ // ✅ Always exhaustive — avoid else on sealed/enum
122
+ // ❌ Don't use else on sealed class when — it hides new state cases
123
+ ```
124
+
125
+ ### Inline Classes / Value Classes
126
+
127
+ ```kotlin
128
+ // ✅ Use to add type safety to primitives
129
+ @JvmInline
130
+ value class UserId(val value: String)
131
+
132
+ @JvmInline
133
+ value class Email(val value: String)
134
+
135
+ // Prevents mixing up primitive parameters
136
+ fun findUser(id: UserId, email: Email) { ... }
137
+ ```
138
+
139
+ ### Collections
140
+
141
+ ```kotlin
142
+ // ✅ Use immutable collections by default
143
+ val items: List<String> = listOf("a", "b", "c")
144
+ val map: Map<String, Int> = mapOf("a" to 1)
145
+
146
+ // ✅ Use mutableListOf() only when mutation is required
147
+ val buffer = mutableListOf<String>()
148
+
149
+ // ✅ Prefer functional operators
150
+ val names = users.filter { it.isActive }.map { it.name }
151
+
152
+ // ❌ Don't use Java stream API — use Kotlin collections API
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Naming Conventions
158
+
159
+ | Element | Convention | Example |
160
+ | -------- | -------------------------- | -------------------------- |
161
+ | Class | PascalCase | `UserRepository` |
162
+ | Function | camelCase | `getUserById()` |
163
+ | Property | camelCase | `userName` |
164
+ | Constant | SCREAMING_SNAKE | `MAX_RETRY_COUNT` |
165
+ | Package | lowercase | `com.example.feature.auth` |
166
+ | File | PascalCase (matches class) | `UserRepository.kt` |
167
+
168
+ ---
169
+
170
+ ## Anti-Patterns
171
+
172
+ - `!!` — use safe calls and elvis instead
173
+ - `lateinit var` on types that could be `val` — redesign initialization
174
+ - `object` for classes that hold state — use class with DI instead
175
+ - Returning `null` to signal error — use `Result<T>` or sealed class
176
+ - Java-style getters/setters — use Kotlin properties
177
+ - `companion object` holding mutable state — use DI or top-level properties
178
+ - Catching `Exception` broadly — catch specific exception types
179
+
180
+ ---
181
+
182
+ ## Related Skills
183
+
184
+ - `coroutine` — async/concurrency patterns
185
+ - `extension-functions-design` — detailed extension function guidelines
186
+ - `immutability` — immutability policy across layers
187
+ - `serialization` — Kotlin serialization setup and usage