Install
$ agentstack add skill-mouchegmouradian-claude-code-skills-android-app-builder ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Android Development
Build Android applications following Google's official architecture guidance, as demonstrated in the NowInAndroid reference app.
Quick Reference
| Task | Reference File | |------|----------------| | Complexity tier selection | [complexity-tiers.md](references/complexity-tiers.md) | | Project structure & modules | [modularization.md](references/modularization.md) | | Architecture layers (UI, Domain, Data) | [architecture.md](references/architecture.md) | | Jetpack Compose patterns | [compose-patterns.md](references/compose-patterns.md) | | Coroutines & Flow patterns | [coroutines.md](references/coroutines.md) | | Gradle & build configuration | [gradle-setup.md](references/gradle-setup.md) | | Testing approach | [testing.md](references/testing.md) |
Step 0: Detect Complexity Tier
Before writing any code, classify the project into one of three tiers. This determines every architectural decision that follows.
Detection Heuristics
Apply these signals in order. The first confident match wins.
Tier 1 — Simple (default for ambiguous small projects):
- Described as: demo, prototype, personal app, learning project, side project, sample, or proof-of-concept
- 1–3 distinct user-facing features
- Features are independent — no described need to share data across screens
- No described need for background processing or scheduled work
- No mention of teams, multi-developer workflow, or production deployment
- Examples: tip calculator, flashcard app, habit tracker, weather viewer, unit converter
Tier 2 — Standard:
- 3–6 distinct user-facing features
- Some features share a repository or data model (e.g., "profile data shown on both home and settings")
- Described as a "real app" or "production" but built by a small team (1–3 developers)
- Needs Hilt for testability or future scaling, but no current need for module isolation
- Examples: personal finance tracker, recipe app with favorites/search/detail, fitness app with history and goals
Tier 3 — Production (current default behavior, unchanged):
- 6+ distinct user-facing features, or
- Multiple teams working in parallel, or
- Described as needing module isolation, independent delivery, or feature flags per team, or
- Complex background sync (WorkManager with multiple syncable repositories), or
- Existing large codebase being extended
Fallback: Ask When Uncertain
If the description is ambiguous, ask exactly one clarifying question before proceeding:
> "To choose the right architecture, how many distinct features does this app need, and is this a personal/prototype app or something for a team or production release?"
Use the answer to re-apply the heuristics above.
After Classification
State the selected tier and its rationale in one sentence before generating any code. Example:
> "This is a Tier 1 (Simple) project — a personal prototype with 2 features and no shared data layer."
Then follow only the blueprint for that tier. Do not mix patterns across tiers.
Workflow Decision Tree
After detecting the tier (see Step 0 above):
Tier 1 — Creating a new project? → Single app/ module only — no feature or core submodules → No Hilt — use companion object ViewModel factory (see [Simple Tier Patterns](#simple-tier-patterns-tier-1-only) below) → No Room — use DataStore or in-memory state → See [complexity-tiers.md](references/complexity-tiers.md) for the full Tier 1 blueprint
Tier 2 — Creating a new project? → Single module with feature packages: ui/featurename/, data/, di/ → Hilt for DI (KSP setup required) → Room if persistence is needed → No build-logic/, no module split → See [complexity-tiers.md](references/complexity-tiers.md) for the full Tier 2 blueprint
Tier 3 — Creating a new project? → Read [modularization.md](references/modularization.md) for project structure → Use templates in assets/templates/
Adding a new feature? (all tiers) → Tier 1/2: Add a new package under app/src/main/.../ui/featurename/ → Tier 3: Create feature:myfeature:api + feature:myfeature:impl modules
Building UI screens? (all tiers) → Read [compose-patterns.md](references/compose-patterns.md) → Always create Route + Screen composables (Route/Screen split applies at every tier) → Always use sealed UiState (Loading/Success/Error)
Setting up data layer? → Tier 1: In-memory or DataStore; concrete class, no interface required for simple cases → Tier 2/3: Interface + implementation; read data layer section in [architecture.md](references/architecture.md)
Working with coroutines/Flow? (all tiers) → Read [coroutines.md](references/coroutines.md) → Follow dispatcher and structured concurrency patterns
Core Principles
- MVVM + UDF (all tiers): ViewModels expose
StateFlow, screens react to state changes; events flow down, data flows up - Sealed UiState (all tiers): Always model Loading/Success/Error states with a sealed interface
- Route/Screen split (all tiers): Route composable handles ViewModel wiring; Screen composable receives plain data only
- No mocking libraries (all tiers): Use test doubles that implement the same interfaces
- Reactive streams (all tiers): Use Kotlin Flow for all data exposure
- Offline-first (Tier 3 default, optional Tier 2): Local database is source of truth when network sync is required
- Modular by feature (Tier 3 only): Each feature is a separate Gradle module with clear api/impl boundaries
- Testable by design (all tiers): DI enables this via Hilt (Tier 2/3) or constructor injection via factory (Tier 1)
Simple Tier Patterns (Tier 1 Only)
Use these patterns only when the project is classified as Tier 1. Do not add Hilt or multi-module structure to Tier 1 projects.
Project Structure (Tier 1)
app/
└── src/main/kotlin/com/example/app/
├── MainActivity.kt
├── AppNavigation.kt # NavHost + all routes in one file
├── data/
│ └── MyRepository.kt # Concrete class, no interface required
└── ui/
└── featurename/
├── FeatureNameRoute.kt
├── FeatureNameScreen.kt
├── FeatureNameViewModel.kt
└── FeatureNameUiState.kt
ViewModel Factory Pattern (Tier 1 — No Hilt)
class FeatureNameViewModel(
private val repository: MyRepository,
) : ViewModel() {
val uiState: StateFlow = repository
.getData()
.map { data -> FeatureNameUiState.Success(data) }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = FeatureNameUiState.Loading,
)
fun onAction(action: FeatureNameAction) {
when (action) {
is FeatureNameAction.ItemClicked -> handleItemClick(action.id)
}
}
companion object {
fun factory(repository: MyRepository): ViewModelProvider.Factory =
viewModelFactory {
initializer { FeatureNameViewModel(repository) }
}
}
}
Route Pattern (Tier 1 — No hiltViewModel())
@Composable
internal fun FeatureNameRoute(
onNavigateToDetail: (String) -> Unit,
repository: MyRepository,
viewModel: FeatureNameViewModel = viewModel(
factory = FeatureNameViewModel.factory(repository)
),
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
FeatureNameScreen(
uiState = uiState,
onAction = viewModel::onAction,
onNavigateToDetail = onNavigateToDetail,
)
}
Repository Pattern (Tier 1 — Concrete Class, DataStore)
class MyRepository(
private val dataStore: DataStore,
) {
val items: Flow> = dataStore.data
.map { prefs -> prefs[MY_ITEMS_KEY]?.let { deserialize(it) } ?: emptyList() }
suspend fun addItem(item: MyItem) {
dataStore.edit { prefs ->
val current = prefs[MY_ITEMS_KEY]?.let { deserialize(it) } ?: emptyList()
prefs[MY_ITEMS_KEY] = serialize(current + item)
}
}
companion object {
val MY_ITEMS_KEY = stringPreferencesKey("my_items")
}
}
MainActivity Wiring (Tier 1 — No Application Subclass Needed)
class MainActivity : ComponentActivity() {
private val repository by lazy {
MyRepository(applicationContext.dataStore)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
AppNavigation(repository = repository)
}
}
}
}
val Context.dataStore: DataStore by preferencesDataStore(name = "app_data")
Navigation (Tier 1 — String Routes, All in One File)
@Composable
fun AppNavigation(repository: MyRepository) {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "feature_name") {
composable("feature_name") {
FeatureNameRoute(
onNavigateToDetail = { id -> navController.navigate("detail/$id") },
repository = repository,
)
}
composable("detail/{id}") { backStackEntry ->
val id = backStackEntry.arguments?.getString("id") ?: return@composable
DetailRoute(id = id, repository = repository)
}
}
}
> Tier 1 uses string routes for simplicity. Tier 2/3 use type-safe @Serializable routes.
build.gradle.kts (Tier 1 — No KSP, No Hilt)
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.plugin.compose")
}
android {
namespace = "com.example.app"
compileSdk = 36
defaultConfig { minSdk = 26; targetSdk = 36 }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures { compose = true }
}
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.datastore.preferences)
debugImplementation(libs.androidx.compose.ui.tooling)
}
No build-logic/, no ksp, no Hilt compiler. This is intentional.
Standard Tier Patterns (Tier 2 Only)
Use these patterns when the project is classified as Tier 2. Single module with Hilt; no build-logic/ convention plugins or multi-module structure.
Project Structure (Tier 2)
app/
└── src/main/kotlin/com/example/app/
├── MainActivity.kt # @AndroidEntryPoint
├── AppNavigation.kt
├── di/
│ └── AppModule.kt # @Module @InstallIn(SingletonComponent)
├── model/
│ └── MyModel.kt
├── data/
│ ├── MyRepository.kt # Interface
│ └── MyRepositoryImpl.kt # @Inject constructor
└── ui/
└── featurename/
├── FeatureNameRoute.kt # uses hiltViewModel()
├── FeatureNameScreen.kt
├── FeatureNameViewModel.kt # @HiltViewModel @Inject constructor
└── FeatureNameUiState.kt
build.gradle.kts (Tier 2 — Hilt + KSP, No Convention Plugins)
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.plugin.compose")
id("com.google.devtools.ksp")
id("dagger.hilt.android.plugin")
}
android {
namespace = "com.example.app"
compileSdk = 36
defaultConfig { minSdk = 26; targetSdk = 36 }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures { compose = true }
}
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.hilt.android)
ksp(libs.hilt.android.compiler)
implementation(libs.androidx.hilt.navigation.compose)
// Add Room only if persistence is needed:
// implementation(libs.room.runtime)
// implementation(libs.room.ktx)
// ksp(libs.room.compiler)
debugImplementation(libs.androidx.compose.ui.tooling)
}
No build-logic/, no multi-module. Repositories are interfaces bound in a single AppModule.kt. Use hiltViewModel() in Route composables and @HiltViewModel @Inject constructor on ViewModels — the same ViewModel/Repository/UiState code patterns as Tier 3, just in a flat module.
> Tier 2 and Tier 3 only. The sections below use Hilt and multi-layer architecture. For Tier 1, use the Simple Tier Patterns above.
Architecture Layers
┌─────────────────────────────────────────┐
│ UI Layer │
│ (Compose Screens + ViewModels) │
├─────────────────────────────────────────┤
│ Domain Layer │
│ (Use Cases - optional, for reuse) │
├─────────────────────────────────────────┤
│ Data Layer │
│ (Repositories + DataSources) │
└─────────────────────────────────────────┘
> Tier 3 only. This multi-module layout does not apply to Tier 1 or Tier 2 projects.
Module Types
app/ # App module - navigation, scaffolding
feature/
├── featurename/
│ ├── api/ # Navigation keys (public)
│ └── impl/ # Screen, ViewModel, DI (internal)
core/
├── data/ # Repositories
├── database/ # Room DAOs, entities
├── network/ # Retrofit, API models
├── model/ # Domain models (pure Kotlin)
├── common/ # Shared utilities
├── ui/ # Reusable Compose components
├── designsystem/ # Theme, icons, base components
├── datastore/ # Preferences storage
└── testing/ # Test utilities
> Tier 3 only. In Tier 1/2, add a new package under app/src/main/.../ui/.
Creating a New Feature
- Create
feature:myfeature:apimodule with navigation key - Create
feature:myfeature:implmodule with:
MyFeatureScreen.kt- Composable UIMyFeatureViewModel.kt- State holderMyFeatureUiState.kt- Sealed interface for statesMyFeatureNavigation.kt- Navigation setupMyFeatureModule.kt- Hilt DI module
Standard File Patterns
ViewModel Pattern
> Tier 2 and Tier 3 — requires Hilt. For Tier 1, use the companion object factory pattern above.
@HiltViewModel
class MyFeatureViewModel @Inject constructor(
private val myRepository: MyRepository,
) : ViewModel() {
val uiState: StateFlow = myRepository
.getData()
.map { data -> MyFeatureUiState.Success(data) }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = MyFeatureUiState.Loading,
)
fun onAction(action: MyFeatureAction) {
when (action) {
is MyFeatureAction.ItemClicked -> handleItemClick(action.id)
is MyFeatureAction.RefreshRequested -> refresh()
}
}
private fun refresh() {
viewModelScope.launch {
myRepository.sync()
}
}
}
UiState Pattern
sealed interface MyFeatureUiState {
data object Loading : MyFeatureUiState
data class Success(val items: List) : MyFeatureUiState
data class Error(val message: String) : MyFeatureUiState
}
> When to use individual StateFlows instead: The sealed `Ui
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mouchegmouradian
- Source: mouchegmouradian/claude-code-skills
- License: MIT
- Homepage: https://mouchegmouradian.github.io/claude-code-skills/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.