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,192 @@
1
+ ---
2
+ name: synchronization-policy
3
+ description: >
4
+ Thread safety and synchronization policy for Android with coroutines.
5
+ Load this skill when defining how shared state is accessed across threads,
6
+ deciding between confinement vs locking, ensuring data consistency,
7
+ or auditing code for race conditions.
8
+ ---
9
+
10
+ # Synchronization Policy
11
+
12
+ ## Overview
13
+
14
+ Synchronization policy defines the rules for safely accessing shared mutable state across coroutines and threads. The safest approach is **confinement** — restricting access to a single thread or coroutine — rather than locking. When shared access is unavoidable, use coroutine-friendly primitives like `Mutex` and `StateFlow.update`.
15
+
16
+ ---
17
+
18
+ ## Core Principles
19
+
20
+ - Prefer **confinement** over locking — restrict state to one dispatcher or coroutine
21
+ - Prefer **immutable data** — no synchronization needed if data can't change
22
+ - Use `StateFlow.update` for UI state — it's atomic and coroutine-safe
23
+ - Use `Mutex` only when state must be shared across multiple coroutines
24
+ - Never access the same mutable state from both `Dispatchers.IO` and `Dispatchers.Main` without synchronization
25
+
26
+ ---
27
+
28
+ ## Strategy 1 — Confinement (Preferred)
29
+
30
+ ```kotlin
31
+ // ✅ Confine mutable state to a single dispatcher
32
+ class DataCache @Inject constructor() {
33
+ // All access happens on a single-threaded dispatcher
34
+ private val cacheDispatcher = Dispatchers.IO.limitedParallelism(1)
35
+ private val cache = mutableMapOf<String, Data>()
36
+
37
+ suspend fun get(key: String): Data? = withContext(cacheDispatcher) {
38
+ cache[key]
39
+ }
40
+
41
+ suspend fun put(key: String, data: Data) = withContext(cacheDispatcher) {
42
+ cache[key] = data
43
+ }
44
+
45
+ suspend fun clear() = withContext(cacheDispatcher) {
46
+ cache.clear()
47
+ }
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Strategy 2 — Immutable State + Atomic Updates
54
+
55
+ ```kotlin
56
+ // ✅ Immutable data class + atomic StateFlow update
57
+ class CartManager @Inject constructor() {
58
+ private val _cart = MutableStateFlow(Cart())
59
+ val cart: StateFlow<Cart> = _cart.asStateFlow()
60
+
61
+ fun addItem(item: CartItem) {
62
+ _cart.update { current ->
63
+ current.copy(items = current.items + item) // new list — immutable
64
+ }
65
+ }
66
+
67
+ fun removeItem(itemId: String) {
68
+ _cart.update { current ->
69
+ current.copy(items = current.items.filter { it.id != itemId })
70
+ }
71
+ }
72
+ }
73
+
74
+ data class Cart(
75
+ val items: List<CartItem> = emptyList() // immutable list
76
+ )
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Strategy 3 — Mutex for Shared Mutable State
82
+
83
+ ```kotlin
84
+ // ✅ Use Mutex when multiple coroutines must share mutable state
85
+ class ConnectionPool @Inject constructor() {
86
+ private val mutex = Mutex()
87
+ private val connections = mutableListOf<Connection>()
88
+
89
+ suspend fun acquire(): Connection = mutex.withLock {
90
+ connections.removeFirstOrNull() ?: createNewConnection()
91
+ }
92
+
93
+ suspend fun release(connection: Connection) = mutex.withLock {
94
+ connections.add(connection)
95
+ }
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Choosing the Right Strategy
102
+
103
+ ```
104
+ Is the state only read after initialization?
105
+ → Use val + immutable data class — no sync needed
106
+
107
+ Is the state only accessed from one coroutine/dispatcher?
108
+ → Use confinement (limitedParallelism(1)) — no sync needed
109
+
110
+ Is the state a simple counter or flag?
111
+ → Use AtomicInteger / AtomicBoolean — no coroutine sync needed
112
+
113
+ Is the state UI state in a ViewModel?
114
+ → Use MutableStateFlow.update — built-in atomic update
115
+
116
+ Is the state accessed by multiple coroutines concurrently?
117
+ → Use Mutex.withLock
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Thread Confinement with limitedParallelism
123
+
124
+ ```kotlin
125
+ // ✅ Single-threaded context for all operations on shared resource
126
+ private val singleThreadContext = Dispatchers.IO.limitedParallelism(1)
127
+
128
+ // All database writes serialized through single thread
129
+ suspend fun writeData(data: List<Item>) = withContext(singleThreadContext) {
130
+ dao.deleteAll()
131
+ dao.insertAll(data)
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Common Race Conditions to Avoid
138
+
139
+ ```kotlin
140
+ // ❌ Check-then-act race condition
141
+ if (cache[key] == null) { // thread A checks
142
+ cache[key] = expensiveCompute() // thread B also checks — both compute
143
+ }
144
+
145
+ // ✅ Fix with Mutex
146
+ mutex.withLock {
147
+ if (cache[key] == null) {
148
+ cache[key] = expensiveCompute()
149
+ }
150
+ }
151
+
152
+ // ❌ Non-atomic read-modify-write
153
+ _state.value = _state.value.copy(count = _state.value.count + 1) // race
154
+
155
+ // ✅ Fix with update
156
+ _state.update { it.copy(count = it.count + 1) } // atomic
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Annotations for Documentation
162
+
163
+ ```kotlin
164
+ // ✅ Document thread-safety expectations
165
+ @ThreadSafe
166
+ class SafeCache { /* ... */ }
167
+
168
+ @MainThread
169
+ fun updateUi(data: List<Item>) { /* ... */ }
170
+
171
+ @WorkerThread
172
+ suspend fun loadFromDisk(): List<Item> { /* ... */ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Anti-Patterns
178
+
179
+ - Accessing a `MutableList` from multiple coroutines without synchronization — race condition
180
+ - Using `synchronized {}` in coroutine code — blocks the thread
181
+ - Mutable `var` property in a class accessed from multiple dispatchers without protection
182
+ - Reading `StateFlow.value` and writing separately — use `update {}` instead
183
+ - Assuming coroutines on the same dispatcher are sequential — they may interleave at suspension points
184
+
185
+ ---
186
+
187
+ ## Related Skills
188
+
189
+ - `mutex-strategy` — Mutex and Semaphore implementation details
190
+ - `coroutine` — dispatcher selection and coroutine fundamentals
191
+ - `structured-concurrency` — coroutine lifetime and cancellation
192
+ - `stateflow` — atomic state updates with StateFlow
@@ -0,0 +1,224 @@
1
+ ---
2
+ name: annotation-processing
3
+ description: >
4
+ Annotation processing setup and usage for Android development.
5
+ Load this skill when working with KSP or KAPT, creating custom annotations,
6
+ configuring code generation tools (Hilt, Room, Moshi, etc.), or
7
+ understanding how annotation processors fit into the build pipeline.
8
+ ---
9
+
10
+ # Annotation Processing
11
+
12
+ ## Overview
13
+
14
+ Annotation processing generates code at compile time based on annotations in the source code. In Android, this powers libraries like Room, Hilt, Moshi, and Glide. KSP (Kotlin Symbol Processing) is the modern replacement for KAPT and should be preferred in all new projects.
15
+
16
+ ---
17
+
18
+ ## Core Principles
19
+
20
+ - **Always prefer KSP over KAPT** — KSP is faster, Kotlin-first, and KMP-compatible
21
+ - Use KAPT only when a library hasn't migrated to KSP yet
22
+ - Never mix KSP and KAPT for the same library
23
+ - Annotation processors run at **compile time** — errors are caught early
24
+ - Generated code lives in `build/generated/` — never edit it manually
25
+
26
+ ---
27
+
28
+ ## KSP vs KAPT
29
+
30
+ | | KSP | KAPT |
31
+ | -------------- | -------------------- | ----------------------- |
32
+ | Speed | Fast (Kotlin-native) | Slow (stubs generation) |
33
+ | KMP Support | ✅ Yes | ❌ No |
34
+ | Incremental | ✅ Yes | Partial |
35
+ | Kotlin-first | ✅ Yes | ❌ Java-based |
36
+ | Recommendation | **Use this** | Only if no KSP support |
37
+
38
+ ---
39
+
40
+ ## Setup
41
+
42
+ ### KSP
43
+
44
+ ```toml
45
+ # libs.versions.toml
46
+ [versions]
47
+ ksp = "2.0.0-1.0.21"
48
+
49
+ [plugins]
50
+ ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
51
+ ```
52
+
53
+ ```kotlin
54
+ // build.gradle.kts
55
+ plugins {
56
+ alias(libs.plugins.ksp)
57
+ }
58
+
59
+ dependencies {
60
+ // KSP-based libraries
61
+ ksp(libs.hilt.compiler)
62
+ ksp(libs.room.compiler)
63
+ }
64
+ ```
65
+
66
+ ### KAPT (legacy — only when KSP unavailable)
67
+
68
+ ```kotlin
69
+ plugins {
70
+ kotlin("kapt")
71
+ }
72
+
73
+ dependencies {
74
+ kapt(libs.some.legacy.compiler)
75
+ }
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Common Libraries and Their Processor
81
+
82
+ | Library | Processor Type | Dependency |
83
+ | ----------- | -------------- | -------------------------------- |
84
+ | Hilt | KSP | `ksp(libs.hilt.compiler)` |
85
+ | Room | KSP | `ksp(libs.room.compiler)` |
86
+ | Moshi | KSP | `ksp(libs.moshi.kotlin.codegen)` |
87
+ | Glide | KAPT | `kapt(libs.glide.compiler)` |
88
+ | DataBinding | Built-in | No extra setup |
89
+
90
+ ---
91
+
92
+ ## Custom Annotations
93
+
94
+ ```kotlin
95
+ // ✅ Define annotation
96
+ @Target(AnnotationTarget.CLASS)
97
+ @Retention(AnnotationRetention.SOURCE)
98
+ annotation class AutoFactory
99
+
100
+ // ✅ Define annotation with parameters
101
+ @Target(AnnotationTarget.FUNCTION)
102
+ @Retention(AnnotationRetention.RUNTIME)
103
+ annotation class RequiresPermission(val value: String)
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Custom KSP Processor
109
+
110
+ ```kotlin
111
+ // ✅ Implement SymbolProcessor
112
+ class AutoFactoryProcessor(
113
+ private val codeGenerator: CodeGenerator,
114
+ private val logger: KSPLogger
115
+ ) : SymbolProcessor {
116
+
117
+ override fun process(resolver: Resolver): List<KSAnnotated> {
118
+ val symbols = resolver
119
+ .getSymbolsWithAnnotation(AutoFactory::class.qualifiedName!!)
120
+ .filterIsInstance<KSClassDeclaration>()
121
+
122
+ symbols.forEach { classDecl ->
123
+ generateFactory(classDecl)
124
+ }
125
+
126
+ return emptyList()
127
+ }
128
+
129
+ private fun generateFactory(classDecl: KSClassDeclaration) {
130
+ val packageName = classDecl.packageName.asString()
131
+ val className = classDecl.simpleName.asString()
132
+
133
+ codeGenerator.createNewFile(
134
+ dependencies = Dependencies(false, classDecl.containingFile!!),
135
+ packageName = packageName,
136
+ fileName = "${className}Factory"
137
+ ).use { stream ->
138
+ stream.write(generateFactoryCode(packageName, className).toByteArray())
139
+ }
140
+ }
141
+ }
142
+
143
+ // ✅ Register processor
144
+ class AutoFactoryProcessorProvider : SymbolProcessorProvider {
145
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
146
+ AutoFactoryProcessor(environment.codeGenerator, environment.logger)
147
+ }
148
+ ```
149
+
150
+ ```
151
+ # Register in resources/META-INF/services/
152
+ # com.google.devtools.ksp.processing.SymbolProcessorProvider
153
+ com.example.processor.AutoFactoryProcessorProvider
154
+ ```
155
+
156
+ ---
157
+
158
+ ## KSP in Multi-Module Projects
159
+
160
+ ```kotlin
161
+ // ✅ Apply KSP only in modules that use it
162
+ // feature/build.gradle.kts
163
+ plugins {
164
+ alias(libs.plugins.ksp)
165
+ }
166
+
167
+ // ✅ Room — schema export location per module
168
+ ksp {
169
+ arg("room.schemaLocation", "$projectDir/schemas")
170
+ arg("room.incremental", "true")
171
+ }
172
+
173
+ // ✅ Hilt — no extra config needed per module
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Incremental Processing
179
+
180
+ ```kotlin
181
+ // ✅ Enable incremental annotation processing for Room
182
+ ksp {
183
+ arg("room.incremental", "true")
184
+ }
185
+
186
+ // ✅ KSP is incremental by default — no extra config needed
187
+ // ❌ KAPT incremental is unreliable — another reason to prefer KSP
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Debugging Annotation Processors
193
+
194
+ ```bash
195
+ # View generated code
196
+ # build/generated/ksp/<variant>/kotlin/
197
+
198
+ # Enable KSP verbose logging
199
+ ksp {
200
+ arg("verbose", "true")
201
+ }
202
+
203
+ # Clean and rebuild when processor changes
204
+ ./gradlew clean assembleDebug
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Anti-Patterns
210
+
211
+ - Using KAPT when KSP is available for the same library
212
+ - Mixing KAPT and KSP for the same library in the same module
213
+ - Editing generated files in `build/generated/` — they are overwritten on rebuild
214
+ - Applying KSP plugin to modules that don't need it — adds unnecessary compile overhead
215
+ - Using `@Retention(RUNTIME)` when `SOURCE` is sufficient — bloats the binary
216
+
217
+ ---
218
+
219
+ ## Related Skills
220
+
221
+ - `hilt` — Hilt DI with KSP setup
222
+ - `room` — Room database with KSP compiler
223
+ - `gradle` — build configuration and plugin setup
224
+ - `kmp` — KSP in multiplatform modules
@@ -0,0 +1,186 @@
1
+ ---
2
+ name: dsl
3
+ description: >
4
+ Kotlin DSL design and implementation patterns for Android development.
5
+ Load this skill when designing builder APIs, configuration blocks,
6
+ type-safe builders, or any fluent API that leverages Kotlin's DSL capabilities.
7
+ ---
8
+
9
+ # Kotlin DSL
10
+
11
+ ## Overview
12
+
13
+ Kotlin DSLs (Domain-Specific Languages) allow expressing configuration, building objects, and defining structure in a readable, type-safe way using lambdas with receivers. Common in Gradle scripts, Compose, Ktor, and custom builders.
14
+
15
+ ---
16
+
17
+ ## Core Principles
18
+
19
+ - DSLs should **read like natural language** in their domain
20
+ - DSLs should be **type-safe** — wrong usage must fail at compile time
21
+ - Use `@DslMarker` to prevent implicit receiver leakage
22
+ - Keep DSL scope **focused** — one responsibility per receiver class
23
+
24
+ ---
25
+
26
+ ## Basic DSL Pattern
27
+
28
+ ```kotlin
29
+ // ✅ Lambda with receiver
30
+ class DialogBuilder {
31
+ var title: String = ""
32
+ var message: String = ""
33
+ private val buttons = mutableListOf<Button>()
34
+
35
+ fun button(label: String, action: () -> Unit) {
36
+ buttons.add(Button(label, action))
37
+ }
38
+
39
+ fun build(): Dialog = Dialog(title, message, buttons)
40
+ }
41
+
42
+ fun dialog(block: DialogBuilder.() -> Unit): Dialog {
43
+ return DialogBuilder().apply(block).build()
44
+ }
45
+
46
+ // Usage
47
+ val dialog = dialog {
48
+ title = "Confirm"
49
+ message = "Are you sure?"
50
+ button("Yes") { confirm() }
51
+ button("No") { dismiss() }
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## @DslMarker — Preventing Receiver Leakage
58
+
59
+ ```kotlin
60
+ // ✅ Always annotate DSL scopes with @DslMarker
61
+ @DslMarker
62
+ annotation class DialogDsl
63
+
64
+ @DialogDsl
65
+ class DialogBuilder { ... }
66
+
67
+ @DialogDsl
68
+ class ButtonBuilder { ... }
69
+
70
+ // Without @DslMarker, inner blocks can access outer receivers
71
+ // causing confusing and hard-to-debug behavior
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Type-Safe Builder Pattern
77
+
78
+ ```kotlin
79
+ // ✅ Use for building structured/hierarchical data
80
+ @DslMarker
81
+ annotation class RouteDsl
82
+
83
+ @RouteDsl
84
+ class RouteBuilder {
85
+ private val routes = mutableListOf<Route>()
86
+
87
+ fun route(path: String, block: RouteConfig.() -> Unit) {
88
+ routes.add(RouteConfig(path).apply(block).build())
89
+ }
90
+
91
+ fun build(): List<Route> = routes
92
+ }
93
+
94
+ @RouteDsl
95
+ class RouteConfig(val path: String) {
96
+ var requiresAuth: Boolean = false
97
+ var deepLink: String? = null
98
+
99
+ fun build(): Route = Route(path, requiresAuth, deepLink)
100
+ }
101
+
102
+ fun routes(block: RouteBuilder.() -> Unit): List<Route> =
103
+ RouteBuilder().apply(block).build()
104
+
105
+ // Usage
106
+ val appRoutes = routes {
107
+ route("/home") {
108
+ requiresAuth = true
109
+ }
110
+ route("/login") {
111
+ deepLink = "app://login"
112
+ }
113
+ }
114
+ ```
115
+
116
+ ---
117
+
118
+ ## DSL for Configuration
119
+
120
+ ```kotlin
121
+ // ✅ Common pattern for library/module configuration
122
+ class NetworkConfig {
123
+ var baseUrl: String = ""
124
+ var timeoutMs: Long = 30_000
125
+ var retryCount: Int = 3
126
+ var enableLogging: Boolean = false
127
+ }
128
+
129
+ fun configureNetwork(block: NetworkConfig.() -> Unit): NetworkConfig =
130
+ NetworkConfig().apply(block)
131
+
132
+ // Usage
133
+ val config = configureNetwork {
134
+ baseUrl = "https://api.example.com"
135
+ timeoutMs = 60_000
136
+ enableLogging = BuildConfig.DEBUG
137
+ }
138
+ ```
139
+
140
+ ---
141
+
142
+ ## DSL in Gradle (Convention Plugins)
143
+
144
+ ```kotlin
145
+ // ✅ Expose DSL-style API in convention plugins
146
+ fun Project.androidLibrary(block: LibraryExtension.() -> Unit) {
147
+ extensions.configure(LibraryExtension::class.java, block)
148
+ }
149
+
150
+ // Usage in module build.gradle.kts
151
+ androidLibrary {
152
+ compileSdk = 35
153
+ defaultConfig {
154
+ minSdk = 24
155
+ }
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## When to Use DSL
162
+
163
+ | Use DSL | Don't Use DSL |
164
+ | -------------------------------------------------- | ----------------------------------- |
165
+ | Building complex objects with many optional fields | Simple data classes with few fields |
166
+ | Hierarchical/nested configuration | One-level flat configuration |
167
+ | Domain has natural language structure | Technical/algorithmic code |
168
+ | Builder would have 5+ parameters | Builder has 1-2 parameters |
169
+
170
+ ---
171
+
172
+ ## Anti-Patterns
173
+
174
+ - DSL without `@DslMarker` — allows accidental outer receiver access
175
+ - Mutable state escaping the DSL scope — DSL output should be immutable
176
+ - DSL that requires calling methods in a specific order — use phases/staged builders instead
177
+ - Too many nested levels — more than 3 levels deep becomes unreadable
178
+ - Side effects inside DSL blocks — DSL should declare, not execute
179
+
180
+ ---
181
+
182
+ ## Related Skills
183
+
184
+ - `kotlin` — Kotlin language fundamentals
185
+ - `extension-functions-design` — extension functions used in DSL design
186
+ - `gradle` — Gradle Kotlin DSL conventions