Expert skill for native Android development with Kotlin and Jetpack Compose
Creates native Android apps using Kotlin and Jetpack Compose with modern architecture patterns.
npx claudepluginhub a5c-ai/babysitterThis skill inherits all available tools. When active, it can use any tool Claude has access to.
README.mdThis skill provides expert capabilities for native Android development using Kotlin and Jetpack Compose. It enables generation of Compose UI components, implementation of modern Android architecture patterns, and comprehensive Gradle build operations.
bash - Execute Gradle commands, adb, and Android SDK toolsread - Analyze Kotlin source files and Gradle configurationswrite - Generate and modify Kotlin code and Compose composablesedit - Update existing Kotlin code and configurationsglob - Search for Kotlin files and Android resourcesgrep - Search for patterns in Android codebaseComposable Functions
State Management
Navigation
ViewModel Patterns
UI State Management
Coroutine Patterns
Flow Patterns
Build Configuration
KSP/KAPT
This skill integrates with the following processes:
jetpack-compose-ui.js - Compose UI developmentandroid-room-database.js - Room persistencefirebase-cloud-messaging.js - FCM integrationandroid-playstore-publishing.js - Play Store submissionapp/
├── src/
│ ├── main/
│ │ ├── kotlin/com/example/myapp/
│ │ │ ├── MyApplication.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── di/
│ │ │ │ └── AppModule.kt
│ │ │ ├── data/
│ │ │ │ ├── repository/
│ │ │ │ ├── local/
│ │ │ │ └── remote/
│ │ │ ├── domain/
│ │ │ │ ├── model/
│ │ │ │ ├── repository/
│ │ │ │ └── usecase/
│ │ │ └── ui/
│ │ │ ├── theme/
│ │ │ ├── navigation/
│ │ │ └── feature/
│ │ ├── res/
│ │ └── AndroidManifest.xml
│ ├── test/
│ └── androidTest/
├── build.gradle.kts
└── proguard-rules.pro
# gradle/libs.versions.toml
[versions]
kotlin = "1.9.21"
compose-bom = "2024.01.00"
hilt = "2.50"
room = "2.6.1"
lifecycle = "2.7.0"
[libraries]
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
compose-ui = { group = "androidx.compose.ui", name = "ui" }
compose-material3 = { group = "androidx.compose.material3", name = "material3" }
compose-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-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" }
[plugins]
android-application = { id = "com.android.application", version = "8.2.0" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
ksp = { id = "com.google.devtools.ksp", version = "1.9.21-1.0.16" }
// ui/feature/home/HomeScreen.kt
package com.example.myapp.ui.feature.home
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
viewModel: HomeViewModel = hiltViewModel(),
onItemClick: (String) -> Unit
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Scaffold(
topBar = {
TopAppBar(
title = { Text("Home") }
)
}
) { paddingValues ->
when (val state = uiState) {
is HomeUiState.Loading -> {
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
is HomeUiState.Success -> {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(state.items, key = { it.id }) { item ->
ItemCard(
item = item,
onClick = { onItemClick(item.id) }
)
}
}
}
is HomeUiState.Error -> {
ErrorContent(
message = state.message,
onRetry = viewModel::retry,
modifier = Modifier.padding(paddingValues)
)
}
}
}
}
@Composable
private fun ItemCard(
item: Item,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Card(
onClick = onClick,
modifier = modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = item.title,
style = MaterialTheme.typography.titleMedium
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = item.description,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
// ui/feature/home/HomeViewModel.kt
package com.example.myapp.ui.feature.home
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val getItemsUseCase: GetItemsUseCase
) : ViewModel() {
private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
init {
loadItems()
}
private fun loadItems() {
viewModelScope.launch {
_uiState.value = HomeUiState.Loading
getItemsUseCase()
.catch { e ->
_uiState.value = HomeUiState.Error(e.message ?: "Unknown error")
}
.collect { items ->
_uiState.value = HomeUiState.Success(items)
}
}
}
fun retry() {
loadItems()
}
}
sealed interface HomeUiState {
data object Loading : HomeUiState
data class Success(val items: List<Item>) : HomeUiState
data class Error(val message: String) : HomeUiState
}
// ui/navigation/NavGraph.kt
package com.example.myapp.ui.navigation
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.example.myapp.ui.feature.home.HomeScreen
import com.example.myapp.ui.feature.detail.DetailScreen
sealed class Screen(val route: String) {
data object Home : Screen("home")
data object Detail : Screen("detail/{itemId}") {
fun createRoute(itemId: String) = "detail/$itemId"
}
}
@Composable
fun NavGraph(
navController: NavHostController,
startDestination: String = Screen.Home.route
) {
NavHost(
navController = navController,
startDestination = startDestination
) {
composable(Screen.Home.route) {
HomeScreen(
onItemClick = { itemId ->
navController.navigate(Screen.Detail.createRoute(itemId))
}
)
}
composable(
route = Screen.Detail.route,
arguments = listOf(
navArgument("itemId") { type = NavType.StringType }
)
) { backStackEntry ->
val itemId = backStackEntry.arguments?.getString("itemId") ?: return@composable
DetailScreen(
itemId = itemId,
onBackClick = { navController.popBackStack() }
)
}
}
}
// di/AppModule.kt
package com.example.myapp.di
import android.content.Context
import androidx.room.Room
import com.example.myapp.data.local.AppDatabase
import com.example.myapp.data.remote.ApiService
import com.example.myapp.data.repository.ItemRepositoryImpl
import com.example.myapp.domain.repository.ItemRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindItemRepository(impl: ItemRepositoryImpl): ItemRepository
}
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"app_database"
).build()
}
@Provides
fun provideItemDao(database: AppDatabase) = database.itemDao()
}
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
# Clean build
./gradlew clean
# Build debug APK
./gradlew assembleDebug
# Build release AAB
./gradlew bundleRelease
# Run unit tests
./gradlew testDebugUnitTest
# Run instrumented tests
./gradlew connectedDebugAndroidTest
# Run lint
./gradlew lintDebug
# Install on device
./gradlew installDebug
Gradle sync failures
./gradlew --refresh-dependencies
KSP/KAPT issues
./gradlew clean && ./gradlew kspDebugKotlin
Emulator issues
adb kill-server && adb start-server
Compose preview issues
# Invalidate caches: File > Invalidate Caches / Restart
android-room - Room database integrationfirebase-mobile - Firebase servicesmobile-testing - Comprehensive testinggoogle-play-console - Play Store publishingActivates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.