Agent skill

Kotlin Android

by ericrisco in ericrisco/rsc-harness

A skill your agent uses when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe…

MITAuto-check passedMobile

Install Kotlin Android

skills CLI
$ npx skills add ericrisco/rsc-harness --skill kotlin-android -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ericrisco/rsc-harness kotlin-android --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/kotlin-android .claude/skills/kotlin-android && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
kotlin-android
GitHub stars
156
Token cost
~2.9k tokens
SKILL.md length
1,003 words
Files
6 (incl. scripts, references)
Skills in repo
229
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe…

  • Fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow
  • SKILL.md covers Versions floor (2026), The architecture in one screen, State & recomposition and ViewModel + UI state, plus 8 more sections
  • Runs Shell scripts from its folder
  • Type-safe Navigation

What it does

Kotlin Android is an agent skill from ericrisco/rsc-harness. Use when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, and the Gradle/AGP surface. NOT shared Android and iOS UI from one Kotlin codebase (that is compose-multiplatform).

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/architecture.md`).

It sits in Mobile, covering Android development. It works with Android, Kotlin, Jetpack Compose and Gradle. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.

When your agent uses it

  • Fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow
  • Type-safe Navigation
  • The Gradle/AGP surface

Example prompts

  • “/kotlin-android”

Requirements

  • A Bash shell

What it can do on your machine

Read from SKILL.md and the folder at commit 92fde8f. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 1 file in scripts/ (Shell), which the agent can run.

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Kotlin Android loads about 2.9k tokens when it runs, and up to ~6k if it reads all its reference files. Until then it costs about 81 tokens; SKILL.md has 1,003 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~81
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from ericrisco/rsc-harness at commit 92fde8f, republished under its MIT licence (© ericrisco). 1,003 words, ~2,935 tokens.

Download SKILL.mdSave it as .claude/skills/kotlin-android/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
kotlin-android
description
Use when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, and the Gradle/AGP surface. NOT shared Android and iOS UI from one Kotlin codebase (that is `compose-multiplatform`).
tags
kotlin, android, jetpack-compose, hilt, room, coroutines, mvvm, clean-architecture
recommends
compose-multiplatform, spring-boot, java, testing-web, github-actions
origin
risco

Native Android with Kotlin & Compose

You build production native Android: Kotlin + Jetpack Compose + the UDF layered architecture (UI → domain → data). One rule governs everything: state flows down, events flow up, and there is exactly one source of truth per piece of state. Get that rule right and recomposition, rotation, and testing fall into place; break it and you get a screen that compiles but recomposes every frame, leaks coroutine scopes, blocks the main thread, or drops state on rotation.

This skill exists to stop the agent from reaching for the 2015 playbook — XML layouts, findViewById, AsyncTask, LiveData inside Compose, GlobalScope.launch, MutableState exposed straight out of a ViewModel. Emit a buildable, idiomatic module, not a toy.

Versions floor (2026)

These are floors verified against current docs (2026-06). Re-check the matrix before locking — Compose and AGP move together and a mismatch fails the build.

PieceFloorWhy it matters
Kotlin (KGP)2.2.xK2 compiler is default & Stable; KGP must align with AGP.
AGP9.2+ when using ComposeCompose's compileSdk 37 requires AGP ≥ 9.2.0.
compileSdk37Current Compose target.
minSdk24Practical modern floor (~99% devices); Compose technically supports 21+.
JDK (build)17Required by current AGP/Compose toolchain.
Compose BOM2026.05.01 → Compose 1.11.2Pin artifacts via the BOM, never per-artifact versions.
Navigation2.8+Type-safe @Serializable routes land here.
Hilt + Room + RetrofitcurrentDI / persistence / network. Wire Room & Hilt with KSP, not kapt.
Serializationkotlinx.serializationRetrofit converter + Navigation route types.

The architecture in one screen

Three layers. Higher layers depend on lower; never the reverse.

text
UI layer      Composable (stateless) ── reads ──> UiState
                     │ events up                  ▲ state down
              ViewModel exposes StateFlow<UiState> │
                     │ calls
domain layer  (optional) UseCase — only when logic spans repos or is reused
                     │ calls
data layer    Repository (interface in domain, impl here)
                  ├── Room DAO  → Flow   (single source of truth)
                  └── Retrofit  → suspend (refreshes the source of truth)
  • UI is dumb: render UiState, send events. No business logic in a @Composable.
  • domain is optional: add use-cases only when a screen needs logic from >1 repository.
  • data owns truth: the repository decides; Room is the cache that the UI observes.

Offline-first means Room is the source of truth. The network writes into Room; the UI observes Room's Flow. WorkManager does background sync. The UI never reads the network directly.

State & recomposition

Each rule has a one-line reason.

  • Hoist state. A composable that owns mutable state can't be reused or previewed — pass state in, send events out.
  • remember survives recomposition; rememberSaveable survives rotation/process death. Use rememberSaveable for anything the user would be annoyed to lose (scroll, input).
  • derivedStateOf for computed state — recomputes only when its inputs change, not every recomposition.
  • key() / stable keys in LazyColumn — without a stable item key, reorder/insert churns the whole list.
  • Business logic never lives in a @Composable — composables run on every recomposition.
kotlin
// Bad — logic + I/O in the composable; runs on every recomposition.
@Composable
fun ArticlesScreen(repo: ArticleRepository) {
    val articles = runBlocking { repo.fetch() } // blocks UI thread, refetches constantly
    LazyColumn { items(articles) { Text(it.title) } }
}

// Good — stateless UI driven by hoisted state; logic in the ViewModel.
@Composable
fun ArticlesScreen(state: ArticlesUiState, onRetry: () -> Unit) {
    when (state) {
        ArticlesUiState.Loading -> CircularProgressIndicator()
        is ArticlesUiState.Error -> ErrorView(state.message, onRetry)
        is ArticlesUiState.Success ->
            LazyColumn { items(state.articles, key = { it.id }) { Text(it.title) } }
    }
}

ViewModel + UI state

Model the screen as a sealed UiState so impossible states (loading and error) can't exist. Expose it as StateFlow, never a mutable type.

kotlin
sealed interface ArticlesUiState {
    data object Loading : ArticlesUiState
    data class Success(val articles: List<Article>) : ArticlesUiState
    data class Error(val message: String) : ArticlesUiState
}

@HiltViewModel
class ArticlesViewModel @Inject constructor(
    repository: ArticleRepository,
) : ViewModel() {
    val uiState: StateFlow<ArticlesUiState> =
        repository.observeArticles()
            .map<List<Article>, ArticlesUiState> { ArticlesUiState.Success(it) }
            .catch { emit(ArticlesUiState.Error(it.message ?: "Unknown error")) }
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = ArticlesUiState.Loading,
            )
}

Collect it lifecycle-aware so collection pauses below STARTED and you don't burn work off-screen:

kotlin
@Composable
fun ArticlesRoute(viewModel: ArticlesViewModel = hiltViewModel()) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    ArticlesScreen(state = state, onRetry = viewModel::refresh)
}

WhileSubscribed(5_000) keeps the flow alive 5s past the last collector so a rotation doesn't restart the upstream pipeline.

Data layer

The repository interface lives in domain; its implementation lives in data. Retrofit uses suspend functions and a @Serializable DTO; Room DAOs return Flow. Errors surface as a sealed result, not raw exceptions thrown into the UI.

kotlin
interface ArticleRepository {
    fun observeArticles(): Flow<List<Article>>   // from Room — the source of truth
    suspend fun refresh()                         // network -> Room
}

The full wired example — DTO, entity, DAO, Retrofit service, repository impl, mappers, offline-first refresh — is in references/architecture.md. Read it before scaffolding a feature end-to-end.

DI with Hilt

@HiltAndroidApp on the Application, @Module @InstallIn(SingletonComponent::class) for bindings, @HiltViewModel + hiltViewModel() for screens. Prefer constructor injection; reach for @Provides/@Binds only for interfaces and third-party types you don't own.

Classic error: MyRepo cannot be provided without an @Inject constructor. Fix one of: either add @Inject constructor(...) to the concrete class, or @Binds the interface to its implementation inside an installed module. See references/gradle-setup.md for the KSP wiring that makes Hilt generate.

Show full SKILL.md (403 more words)Show less

Coroutines & Flow rules

  • Never GlobalScope.launch — it outlives every screen and leaks. Use viewModelScope (UI logic) or a repository-scoped scope.
  • Structured concurrency: a cancelled parent cancels children — keep work inside a real scope so navigation-away cancels it.
  • Inject dispatchers (@IoDispatcher CoroutineDispatcher) instead of hardcoding Dispatchers.IO — otherwise the work isn't testable.
  • flowOn to switch a flow's upstream context, not withContext inside a flow { } builder (which is a context-preservation violation).
  • Cold Flow for streams, StateFlow for current-value state — don't collect a cold flow when the UI needs the latest value.

Navigation (type-safe)

Since Navigation 2.8, routes are @Serializable types — the compiler checks your args.

kotlin
@Serializable data object ArticleList
@Serializable data class ArticleDetail(val id: String)

NavHost(navController, startDestination = ArticleList) {
    composable<ArticleList> {
        ArticlesRoute(onOpen = { navController.navigate(ArticleDetail(it)) })
    }
    composable<ArticleDetail> { backStackEntry ->
        val args = backStackEntry.toRoute<ArticleDetail>()
        ArticleDetailRoute(id = args.id)
    }
}

No string routes, no manual arguments = listOf(navArgument(...)), no fragile key parsing.

Build & verify

bash
./gradlew :app:assembleDebug lintDebug testDebugUnitTest

assembleDebug proves it builds, lintDebug catches Android lint, testDebugUnitTest runs JVM unit tests. For a fast, SDK-free static gate over the Kotlin/Gradle you just wrote, run scripts/verify.sh — it greps for banned patterns and missing modern ones without touching the Android SDK, so it works in CI or a bare checkout.

Anti-patterns

Anti-patternWhy it bitesDo instead
XML layouts + findViewByIdStale; no compile-time view safety; doesn't composeJetpack Compose @Composable
LiveData collected in a ComposableLifecycle mismatch, extra dependency, not Compose-nativeStateFlow + collectAsStateWithLifecycle()
GlobalScope.launchLeaks; outlives the screen; uncancellableviewModelScope / scoped coroutine
runBlocking / network call on the main threadANR, frozen UIsuspend on an injected dispatcher
Business logic in a @ComposableRuns every recomposition; untestableMove to ViewModel / use-case
MutableStateFlow/mutableStateOf exposed publiclyUI can mutate state; breaks single source of truthprivate mutable backing + public asStateFlow()/StateFlow
God-Activity holding all stateUntestable, rotation-fragileOne ViewModel per screen, hoisted state
kapt for Room/HiltSlow, legacy; K2-incompatible edge casesKSP
collectAsState() in ComposeKeeps collecting off-screen, wastes workcollectAsStateWithLifecycle()
Reading the network directly in the repository's read pathNo offline; UI flickers on every fetchRoom as source of truth; network refreshes it

When this is the wrong skill

  • Shared UI across Android + iOS + desktop from one Kotlin codebase — the moment commonMain, expect/actual, or an iOS target appears, use ../compose-multiplatform/SKILL.md.
  • Server-side Kotlin / JVM web backend the app talks to → ../spring-boot/SKILL.md.
  • Pure Kotlin/JVM language questions, no Android → ../java/SKILL.md is the nearest JVM-language sibling (there is no standalone kotlin language skill).
  • iOS/SwiftUI → swift-ios. Dart cross-platform → ../flutter/SKILL.md. React Native → react-native.
  • CI for assembleDebug/tests → github-actions.

References

  • references/architecture.md — end-to-end wired feature (UiState + ViewModel + Repository + Room + Retrofit + Hilt), complete file contents.
  • references/gradle-setup.md — libs.versions.toml, root + module build.gradle.kts, the Compose Kotlin plugin, Hilt/KSP wiring, and common Gradle/build error fixes.

© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files (scripts, references) in skills/kotlin-android of ericrisco/rsc-harness.

  • SKILL.md
  • evals/README.md
  • evals/cases.yaml
  • references/architecture.md
  • references/gradle-setup.md
  • scripts/verify.sh

Open the folder on GitHubat commit 92fde8f

Compare with similar skills

Kotlin Android next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Kotlin Android compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Kotlin Android this skillericrisco/rsc-harness156—~2.9kAutomated safety check: PassMIT
Composewebview Developmentparkwoocheol/compose-webview103—~1.3kAutomated safety check: PassMIT
Android Developmentdpconde/claude-android-skill336—~1.7kAutomated safety check: PassMIT
Claude Android NinjaDrjacky/claude-android-ninja124—~5.2kAutomated safety check: PassApache-2.0
Expo Brownfield Integrationmweinbach/agent-coworker1562 repos~900Automated safety check: NotesCustom licence
Jetpack Composedarriousliu/PiPixiv262—~1.5kAutomated safety check: PassApache-2.0

Similar skills

  • Composewebview Development

    parkwoocheol/compose-webview

    Builds, tests, and formats ComposeWebView multiplatform library.

    103 GitHub stars~1.3k tokensUpdated 1 mo ago
    MobileAuto-check passed
  • Android Development

    dpconde/claude-android-skill

    Create production-quality Android applications following Google's official architecture guidance and NowInAndroid best practices.

    336 GitHub stars~1.7k tokensUpdated 10 mo ago
    MobileAuto-check passed
  • Claude Android Ninja

    Drjacky/claude-android-ninja

    Build and migrate Android apps with Kotlin, Jetpack Compose, MVVM, Hilt, Room 3 (KSP, SQLiteDriver, Flow/suspend DAOs), Navigation3, and multi-module Gradle.

    124 GitHub stars~5.2k tokensUpdated 8 days ago
    MobileAuto-check passed
  • Expo Brownfield Integration

    mweinbach/agent-coworker

    Helps add Expo and React Native to an existing native iOS or Android app, and choose between a prebuilt AAR or XCFramework and a fully integrated build.

    156 GitHub starsUsed in 2 repos~900 tokens
    MobileAuto-check: notes
  • Jetpack Compose

    darriousliu/PiPixiv

    Jetpack Compose expert skill for Android UI development. An agent skill from darriousliu/PiPixiv.

    262 GitHub stars~1.5k tokensUpdated yesterday
    MobileAuto-check passed
  • Ksafe

    ioannisa/KSafe

    Required before any reply that touches KSafe (by ksafe(...), ksafe.get/put, :ksafe-compose, :ksafe-biometrics), even a 'can KSafe do X?' question or a one-line change that looks like plain Kotlin.

    332 GitHub stars~17k tokensUpdated 4 days ago
    MobileAuto-check passed

More from ericrisco/rsc-harness

All 229 skills in this repo
  • Ab Testing

    ericrisco/rsc-harness

    A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…

    156 GitHub stars~2.4k tokensUpdated today
    Auto-check passed
  • Accessibility

    ericrisco/rsc-harness

    A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…

    156 GitHub stars~3.4k tokensUpdated today
    Auto-check passed
  • Ads

    ericrisco/rsc-harness

    A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…

    156 GitHub stars~2.2k tokensUpdated today
    Auto-check passed
  • Agent Eval

    ericrisco/rsc-harness

    A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…

    156 GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • AI Media

    ericrisco/rsc-harness

    A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…

    156 GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Analytics

    ericrisco/rsc-harness

    A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.

    156 GitHub stars~2.8k tokensUpdated today
    Auto-check passed

Categories

Questions about Kotlin Android

What does Kotlin Android do?

A skill your agent uses when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe…. Kotlin Android is an agent skill from ericrisco/rsc-harness. Use when building or fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow, Hilt, Room, Retrofit, coroutines, type-safe Navigation, and the Gradle/AGP surface.

When should I use Kotlin Android?

Kotlin Android fits situations like: fixing a native Android app in Kotlin and Jetpack Compose on the UDF layered architecture — ViewModel/StateFlow; type-safe Navigation; the Gradle/AGP surface.

How do I install Kotlin Android in Claude Code?

Run `npx skills add ericrisco/rsc-harness --skill kotlin-android -a claude-code`. Or copy the skill folder (skills/kotlin-android in ericrisco/rsc-harness) into .claude/skills/kotlin-android in your project. Claude Code loads it when a task matches its description.

How do I install Kotlin Android in Codex?

Run `npx skills add ericrisco/rsc-harness --skill kotlin-android -a codex`. Or copy the skill folder (skills/kotlin-android in ericrisco/rsc-harness) into .agents/skills/kotlin-android in your project. Codex loads it when a task matches its description.

Can I use Kotlin Android in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill kotlin-android -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/kotlin-android, .gemini/skills/kotlin-android, .github/skills/kotlin-android and .opencode/skills/kotlin-android in your project.

What does Kotlin Android need to run?

Going by SKILL.md and its folder, Kotlin Android needs a shell for the scripts in its folder. Our summary lists: A Bash shell.

Does Kotlin Android access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Kotlin Android safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Kotlin Android use?

Kotlin Android is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Kotlin Android use?

About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 3k tokens, read only when the agent opens those files.

What are the alternatives to Kotlin Android?

Skills that share tags, products or a category with Kotlin Android: Composewebview Development (parkwoocheol/compose-webview, 103 stars), Android Development (dpconde/claude-android-skill, 336 stars), Claude Android Ninja (Drjacky/claude-android-ninja, 124 stars) and Expo Brownfield Integration (mweinbach/agent-coworker, 156 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Kotlin Android?

ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 156 GitHub stars. The repository holds 229 skills in this directory. The repository was last updated on October 6, 2026.

Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.