Android Kotlin Architecture
Communityhaidrrrry
Enforces Clean Architecture, MVVM/MVI, and unidirectional data flow for Android apps. Covers UiState, UiEvent, UiEffect, UseCase boundaries, module structure, and atomic ViewModel state via _state.update. Use when structuring features, refactoring ViewModels, splitting modules, or asking "MVVM vs MVI", "where does state live", "UseCase when".
Overview
- Repository
- haidrrrry/compose-kotlin-agent-skills
- Publisher
- haidrrrry
- Stars
- 65
- Forks
- 8
- Bundled files
- 0
- License
- MIT
- Updated
- Jul 8, 2026
Installation
tmp=$(mktemp -d)
git clone --depth 1 https://github.com/haidrrrry/compose-kotlin-agent-skills.git "$tmp"
mkdir -p ~/.claude/skills
cp -R "$tmp/skills/android-kotlin-architecture" ~/.claude/skills/android-kotlin-architecture
rm -rf "$tmp"tmp=$(mktemp -d)
git clone --depth 1 https://github.com/haidrrrry/compose-kotlin-agent-skills.git "$tmp"
mkdir -p ~/.codex/skills
cp -R "$tmp/skills/android-kotlin-architecture" ~/.codex/skills/android-kotlin-architecture
rm -rf "$tmp"Install the Android Kotlin Architecture agent skill from https://github.com/haidrrrry/compose-kotlin-agent-skills/tree/main/skills/android-kotlin-architecture into this project's skills folder.Instructions
Android Kotlin — Architecture Module
Parent kit: ../../SKILL.md · Index: ../../AGENTS.md
Read First
| File | When |
|---|---|
../../references/01-architecture.md |
Full MVVM/MVI patterns, container/content composables |
../../references/04-coroutines-flow.md |
StateFlow, Channel effects, stateIn |
../../references/05-hilt-di.md |
@HiltViewModel, repository wiring |
../../references/06-room-db.md |
Repository + Room offline-first |
MVI Contract (Mandatory)
@Immutable
data class FeatureUiState(
val items: List<ItemUi> = emptyList(),
val isLoading: Boolean = false,
val error: UiError? = null
)
sealed interface FeatureUiEvent {
data class SearchChanged(val query: String) : FeatureUiEvent
data object Refresh : FeatureUiEvent
data class ItemClicked(val id: String) : FeatureUiEvent
}
sealed interface FeatureUiEffect {
data class ShowMessage(@StringRes val messageRes: Int) : FeatureUiEffect
data class NavigateToDetail(val id: String) : FeatureUiEffect
}
class FeatureViewModel @Inject constructor(
private val repository: FeatureRepository
) : ViewModel() {
private val _state = MutableStateFlow(FeatureUiState())
val state: StateFlow<FeatureUiState> = _state.asStateFlow()
private val _effects = Channel<FeatureUiEffect>(Channel.BUFFERED)
val effects: Flow<FeatureUiEffect> = _effects.receiveAsFlow()
fun onEvent(event: FeatureUiEvent) {
when (event) {
is FeatureUiEvent.SearchChanged -> onSearchChanged(event.query)
FeatureUiEvent.Refresh -> refresh()
is FeatureUiEvent.ItemClicked -> emitNavigate(event.id)
}
}
private fun onSearchChanged(query: String) {
_state.update { it.copy(searchQuery = query) } // ONLY mutation style allowed
}
private fun refresh() {
viewModelScope.launch {
_state.update { it.copy(isLoading = true, error = null) }
repository.sync()
.onSuccess { _state.update { it.copy(isLoading = false) } }
.onFailure { e ->
_state.update { it.copy(isLoading = false, error = e.toUiError()) }
}
}
}
private fun emitNavigate(id: String) {
viewModelScope.launch { _effects.send(FeatureUiEffect.NavigateToDetail(id)) }
}
}Module Layout (Large Apps)
app/
feature-<name>/
presentation/ # Composables + ViewModel
domain/ # Models, repository interfaces, UseCases
data/ # Room, Ktor, mappers
core/
core-ui/ # Design system
core-domain/
core-testing/
Feature modules must not depend on other feature modules — only core-* and domain contracts.
UseCase Rule
| Use UseCase | Skip UseCase |
|---|---|
| Logic shared by 2+ ViewModels | Single-line repo delegate |
| Multi-repo orchestration | One ViewModel, one repo |
| Needs isolated unit tests | CRUD with no extra rules |
Anti-Patterns (Architecture)
| Banned | Fix |
|---|---|
_state.value = newState |
_state.update { it.copy(...) } |
| God ViewModel (>200 lines) | Split screen or extract UseCases |
| ViewModel in composable params | Pass onEvent lambdas |
Domain model with @Entity |
Entity in data/, map in repository |
Collecting Flow in init without stateIn |
stateIn(WhileSubscribed(5_000)) |
FAQ
What does Android Kotlin Architecture do?
Enforces Clean Architecture, MVVM/MVI, and unidirectional data flow for Android apps. Covers UiState, UiEvent, UiEffect, UseCase boundaries, module structure, and atomic ViewModel state via _state.update. Use when structuring features, refactoring ViewModels, splitting modules, or asking "MVVM vs MVI", "where does state live", "UseCase when".
Who made Android Kotlin Architecture?
haidrrrry (a community member) publishes it in the haidrrrry/compose-kotlin-agent-skills repository on GitHub.
Is Android Kotlin Architecture free?
Yes. Android Kotlin Architecture is open source, published by haidrrrry under the MIT license.
What comes with Android Kotlin Architecture?
Just its instructions. Everything the agent needs is in one SKILL.md file.
Which agents can use Android Kotlin Architecture?
Any coding agent that reads SKILL.md files, including Claude Code, Codex, Cursor, GitHub Copilot and Gemini CLI. The agent loads the skill when a task matches its description.
What are agent skills?
An agent skill is a folder with a SKILL.md file: instructions that teach a coding agent how to do one kind of task, and optionally files it can read while it works. The agent keeps only the skill's name and description in mind and reads the rest when a task calls for it.
How are agent skills different from MCP servers?
An MCP server gives an agent new tools to call, code that runs somewhere and returns results. A skill gives it knowledge: how to approach a task with the tools it already has. Many agents use both.
How can my agent test my Android app?
Robomori lets coding agents create, start and control Android emulators and devices from one command, so they can install your app, take screenshots and check dark mode, font sizes and languages.