Kotlin android architecture
Expert guidance on a modern Kotlin-first Android application architecture using Clean Architecture, Gradle module separation, version catalogs, and Hilt DI. Use this when asked about project structure, module layout, or dependency injection.From its SKILL.md
npx -y skills add almasumdev/awesome-kotlin-android-agent-skills --skill kotlin-android-architectureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.7 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Kotlin Android Clean Architecture & Modularization
Instructions
When designing or refactoring a Kotlin Android application, follow Clean Architecture principles. Dependencies must flow inwards toward pure Kotlin domain code. Kotlin 2.0 (K2), JVM 17, Compose-first.
1. High-Level Layers
- Presentation Layer (
:app,:feature:*:ui)- Responsibility: Render Compose UI and expose ViewModels.
- Components:
@Composablescreens,HiltViewModelclasses exposingStateFlow<UiState>, and one-shot events viaSharedFlow<UiEvent>. - Dependencies: Domain interfaces only. No Retrofit, no Room here.
- Domain Layer (
:core:domain,:feature:*:domain) — pure Kotlin, no Android dependencies- Components: UseCases (
class GetArticlesUseCase @Inject constructor(...)), immutabledata classentities, repository interfaces. - Rule: Module-level
plugins { kotlin("jvm") }only. Nocom.android.library. This is enforceable.
- Components: UseCases (
- Data Layer (
:core:data,:feature:*:data)- Components: Repository implementations, Retrofit API services, Room
@Daos, DTOs with@Serializable, and mappers to domain models.
- Components: Repository implementations, Retrofit API services, Room
2. Module Graph
:app
└─ depends on feature modules + :core:designsystem + :core:ui
:feature:articles:ui → :feature:articles:domain, :core:designsystem
:feature:articles:data → :feature:articles:domain, :core:network, :core:database
:feature:articles:domain → (pure Kotlin)
:core:network → Retrofit, OkHttp, kotlinx.serialization
:core:database → Room
:core:designsystem → Compose, Material 3 tokens, typography, shapes
3. Version Catalog (gradle/libs.versions.toml)
[versions]
kotlin = "2.0.21"
agp = "8.7.2"
compose-bom = "2024.10.01"
hilt = "2.52"
room = "2.6.1"
retrofit = "2.11.0"
kotlinx-serialization = "1.7.3"
[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
ksp = { id = "com.google.devtools.ksp", version = "2.0.21-1.0.25" }
4. Dependency Injection with Hilt
@HiltAndroidApp
class MyApp : Application()
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides @Singleton
fun provideJson(): Json = Json { ignoreUnknownKeys = true; explicitNulls = false }
@Provides @Singleton
fun provideRetrofit(client: OkHttpClient, json: Json): Retrofit =
Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.client(client)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
}
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryBindings {
@Binds abstract fun bindArticleRepo(impl: ArticleRepositoryImpl): ArticleRepository
}
For Koin (alternative): declare modules with single { ... } / viewModel { ... } and call startKoin { modules(appModule) } in Application.onCreate.
5. Feature Module Template
// feature/articles/ui/build.gradle.kts
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
}
android { namespace = "com.example.feature.articles.ui"; compileSdk = 35 }
dependencies {
implementation(projects.feature.articles.domain)
implementation(projects.core.designsystem)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.material3)
implementation(libs.hilt.android); ksp(libs.hilt.compiler)
}
6. Rules the Agent Must Enforce
- Domain modules use
kotlin("jvm"), nevercom.android.library. - Feature modules do not depend on other feature modules directly — wire across features in
:apponly. - Every public repository returns domain models, never DTOs.
- Every ViewModel exposes a single immutable
UiStateviaStateFlow, plus aChannel<UiEvent>orSharedFlow<UiEvent>for navigation/toasts.
Checklist
- Domain modules have zero Android dependencies (
./gradlew :core:domain:dependencies | grep androidxreturns nothing). -
libs.versions.tomlis the single source of versions; no hard-coded"x.y.z"in build scripts. - Hilt graph compiles (
./gradlew :app:kspDebugKotlin). - Repositories return domain entities; DTOs live only in
:feature:*:data. - Feature-to-feature imports fail CI (enforced by a module-graph lint or
konsistrule).
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.