
Android Clean Architecture
Lay out Android or Kotlin Multiplatform modules with Clean Architecture—domain UseCases, repository boundaries, and Room/SQLDelight/Ktor data layers—for agent-guided refactors.
Overview
android-clean-architecture is an agent skill for the Build phase that defines Android and KMP module structure, dependency rules, and UseCase/Repository data-layer patterns with Room, SQLDelight, and Ktor.
Install
npx skills add https://github.com/affaan-m/everything-claude-code --skill android-clean-architectureWhat is this skill?
- Recommended seven-area module layout: app, core, domain, data, presentation, design-system, optional feature/*
- Explicit dependency rules: domain stays pure Kotlin; data implements repository interfaces
- UseCase and Repository patterns with dependency inversion
- Data layer guidance for Room, SQLDelight, and Ktor
- DI setup notes for Koin or Hilt when wiring layers
- 7 named module areas in the recommended layout (app, core, domain, data, presentation, design-system, feature/*)
Adoption & trust: 5.1k installs on skills.sh; 210k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Android or KMP project mixes UI, API calls, and database code so features are hard to test and agents generate coupled layers.
Who is it for?
Indie mobile devs starting a structured KMP/Android app or splitting a tangled single-module codebase before scaling features.
Skip if: Tiny throwaway prototypes, server-only backends, or teams already standardized on a different architecture doc without Android/KMP scope.
When should I use this skill?
Structuring Android or KMP project modules; implementing UseCases, Repositories, or DataSources; designing data flow between domain, data, and presentation; setting up Koin or Hilt with Room, SQLDelight, or Ktor.
What do I get? / Deliverables
After applying the skill, modules follow Clean Architecture dependency rules with domain interfaces implemented in data and presentation consuming UseCases only.
- Module dependency graph aligned with documented rules
- Domain interfaces and data-layer repository implementations
- Presentation ViewModels wired through UseCases
Recommended Skills
Journey fit
Module boundaries and layer rules are applied while constructing the mobile codebase, before ship-ready feature work accumulates in the wrong packages. Presentation, domain, and data separation is primarily a mobile client architecture concern on the frontend build shelf, with data layer patterns tied to on-device storage and APIs.
How it compares
Opinionated module blueprint and dependency matrix—not a UI component library or a single REST integration skill.
Common Questions / FAQ
Who is android-clean-architecture for?
Solo and small-team Android/KMP builders using Claude Code or Cursor who want agents to respect layer boundaries and DI-friendly structure.
When should I use android-clean-architecture?
During Build when creating module trees, defining UseCases and Repositories, wiring Koin or Hilt, or integrating Room, SQLDelight, or Ktor in a layered way.
Is android-clean-architecture safe to install?
Treat it as architecture guidance only; review the Security Audits panel on this page and validate any agent-suggested Gradle or dependency changes in your repo.
SKILL.md
READMESKILL.md - Android Clean Architecture
# Android Clean Architecture Clean Architecture patterns for Android and KMP projects. Covers module boundaries, dependency inversion, UseCase/Repository patterns, and data layer design with Room, SQLDelight, and Ktor. ## When to Activate - Structuring Android or KMP project modules - Implementing UseCases, Repositories, or DataSources - Designing data flow between layers (domain, data, presentation) - Setting up dependency injection with Koin or Hilt - Working with Room, SQLDelight, or Ktor in a layered architecture ## Module Structure ### Recommended Layout ``` project/ ├── app/ # Android entry point, DI wiring, Application class ├── core/ # Shared utilities, base classes, error types ├── domain/ # UseCases, domain models, repository interfaces (pure Kotlin) ├── data/ # Repository implementations, DataSources, DB, network ├── presentation/ # Screens, ViewModels, UI models, navigation ├── design-system/ # Reusable Compose components, theme, typography └── feature/ # Feature modules (optional, for larger projects) ├── auth/ ├── settings/ └── profile/ ``` ### Dependency Rules ``` app → presentation, domain, data, core presentation → domain, design-system, core data → domain, core domain → core (or no dependencies) core → (nothing) ``` **Critical**: `domain` must NEVER depend on `data`, `presentation`, or any framework. It contains pure Kotlin only. ## Domain Layer ### UseCase Pattern Each UseCase represents one business operation. Use `operator fun invoke` for clean call sites: ```kotlin class GetItemsByCategoryUseCase( private val repository: ItemRepository ) { suspend operator fun invoke(category: String): Result<List<Item>> { return repository.getItemsByCategory(category) } } // Flow-based UseCase for reactive streams class ObserveUserProgressUseCase( private val repository: UserRepository ) { operator fun invoke(userId: String): Flow<UserProgress> { return repository.observeProgress(userId) } } ``` ### Domain Models Domain models are plain Kotlin data classes — no framework annotations: ```kotlin data class Item( val id: String, val title: String, val description: String, val tags: List<String>, val status: Status, val category: String ) enum class Status { DRAFT, ACTIVE, ARCHIVED } ``` ### Repository Interfaces Defined in domain, implemented in data: ```kotlin interface ItemRepository { suspend fun getItemsByCategory(category: String): Result<List<Item>> suspend fun saveItem(item: Item): Result<Unit> fun observeItems(): Flow<List<Item>> } ``` ## Data Layer ### Repository Implementation Coordinates between local and remote data sources: ```kotlin class ItemRepositoryImpl( private val localDataSource: ItemLocalDataSource, private val remoteDataSource: ItemRemoteDataSource ) : ItemRepository { override suspend fun getItemsByCategory(category: String): Result<List<Item>> { return runCatching { val remote = remoteDataSource.fetchItems(category) localDataSource.insertItems(remote.map { it.toEntity() }) localDataSource.getItemsByCategory(category).map { it.toDomain() } } } override suspend fun saveItem(item: Item): Result<Unit> { return runCatching { localDataSource.insertItems(listOf(item.toEntity())) } } override fun observeItems(): Flow<List<Item>> { return localDataSource.observeAll().map { entities -> entities.map { it.toDomain() } } } } ``` ### Mapper Pattern Keep mappers as extension functions near the data models: ```kotlin // In data layer fun ItemEntity