Agent skill

Compose Multiplatform

by ericrisco in ericrisco/rsc-harness

A skill your agent uses when building one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform…

MITAuto-check passedMobile

Install Compose Multiplatform

skills CLI
$ npx skills add ericrisco/rsc-harness --skill compose-multiplatform -a claude-code

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

GitHub CLI
$ gh skill install ericrisco/rsc-harness compose-multiplatform --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/compose-multiplatform .claude/skills/compose-multiplatform && 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
compose-multiplatform
GitHub stars
156
Token cost
~2.7k tokens
SKILL.md length
1,008 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 one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform…

  • Building one shared Compose UI in Kotlin across Android
  • SKILL.md covers Versions floor (2026), Where does this code go?, Project structure (the 2026… and expect / actual — the core…, plus 5 more sections
  • Runs Shell scripts from its folder
  • Desktop — commonMain @Composables

What it does

Compose Multiplatform is an agent skill from ericrisco/rsc-harness. Use when building one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform ViewModel/navigation/Koin. NOT a single-platform native build (that is kotlin-android / swift-ios), and NOT Dart/Flutter cross-platform UI (that is flutter).

Its SKILL.md is about 2.7k 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/ios-interop.md`).

It sits in Mobile, covering Android development, Cross-platform mobile apps and iOS development. It works with Jetpack Compose, Android, iOS and Kotlin. 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

  • Building one shared Compose UI in Kotlin across Android
  • Desktop — commonMain @Composables
  • Source-set placement
  • Multiplatform ViewModel/navigation/Koin

Example prompts

  • “/compose-multiplatform”

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

Compose Multiplatform loads about 2.7k tokens when it runs, and up to ~4.5k if it reads all its reference files. Until then it costs about 89 tokens; SKILL.md has 1,008 words of instructions outside code blocks.

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

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,008 words, ~2,670 tokens.

Download SKILL.mdSave it as .claude/skills/compose-multiplatform/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
compose-multiplatform
description
Use when building one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform ViewModel/navigation/Koin. NOT a single-platform native build (that is kotlin-android / swift-ios), and NOT Dart/Flutter cross-platform UI (that is flutter).
tags
kotlin, kmp, compose-multiplatform, cross-platform, shared-ui, expect-actual, ios, android
recommends
kotlin-android, swift-ios, flutter, tauri
origin
risco

Compose Multiplatform

You write one Compose UI tree in commonMain and let each platform be a thin host. The whole discipline is one sentence: common by default, platform by exception. Every line you put in commonMain ships to Android, iOS, and desktop unchanged; every line you put in a platform source set is a deliberate exception you should be able to justify.

Versions floor (2026)

Pin these or the K2 compiler bites you. Verify against current docs before locking a project — these are the floors, not opinions.

  • Compose Multiplatform 1.11.0, bundling Jetpack Compose 1.11.1.
  • Kotlin 2.1.0+ required (2.2.20 recommended for evolving iOS/Web targets). Since CMP 1.8.0 the K2 compiler is mandatory, so every dependency must compile against Kotlin 2.1.0+.
  • iOS is Stable (production-ready since CMP 1.8.0, May 2025): feature parity for popular cases, type-safe navigation with deep linking, accessibility (VoiceOver, Full Keyboard Access).
  • Web is Beta (CMP 1.9.0, Sept 2025), runs on WasmGC browsers. Do not promise Web parity — ship Android/iOS/desktop, pilot Web.
  • Platform minimums: Android API 21, iOS 14+, macOS 13 arm64, Windows 10+, Ubuntu 20.04+, desktop JDK 11+ (17+ for jpackage packaging).

Where does this code go?

This is the question you answer dozens of times a day. Default to the leftmost column that compiles.

Source setPut hereConcrete exampleNever here
commonMainShared @Composables, ViewModels, business logic, common interfaces, expect declarations@Composable fun GreetingScreen(), expect fun platformName(): Stringandroid.*, platform.UIKit, java.awt, androidx.activity
androidMainActivity, actual using Android Context/Buildclass MainActivity : ComponentActivityiOS/desktop-only APIs
iosMainComposeUIViewController factory, actual via cinterop/platform.*fun MainViewController() = ComposeUIViewController { App() }android.*
desktopMainapplication {} window, Swing interopapplication { Window(::exitApplication) { App() } }mobile-only APIs
wasmJsMain (Beta)Web entry pointComposeViewport(document.body!!) { App() }anything you can't ship as Beta

Why this matters: a platform import in commonMain breaks the build for every other target, and the error surfaces in the iOS link step, far from the offending line. Keep commonMain import-clean.

Project structure (the 2026 default)

The current default KMP layout (announced May 2026, aligned with AGP 9.0) is a dedicated shared KMP library module + per-platform app modules, not the old single composeApp:

text
my-app/
  shared/            # KMP library: commonMain holds the Compose UI tree
    src/
      commonMain/    # @Composables, ViewModels, expect declarations, DI
      androidMain/   # actual impls using android.*
      iosMain/       # actual impls + ComposeUIViewController
      desktopMain/   # actual impls + application {} window
      wasmJsMain/    # web entry (Beta)
  androidApp/        # thin Android host -> setContent { App() }
  iosApp/            # Xcode project -> embeds the shared framework
  desktopApp/        # ./gradlew :desktopApp:run
  webApp/            # WasmGC entry (Beta)

Split rule: if some screens are native and only some are shared Compose, split into sharedLogic (all platforms) + sharedUI (CMP platforms only). A server-inclusive project adds a root core module. Don't pre-split — start with one shared module and split when a platform genuinely needs native UI.

Source-set hierarchy — commonMain fans out, with intermediate sets where targets share code:

text
commonMain
├── androidMain
├── desktopMain (jvm)
├── wasmJsMain (Beta)
└── iosMain (intermediate)
    ├── iosArm64
    └── iosSimulatorArm64

Scaffold a new project with kmp.new or the Kotlin Multiplatform wizard (IntelliJ IDEA 2025.2.2+ / Android Studio Otter 2025.2.1+ with the KMP plugin). Add a shared module to an existing Android app via Android Studio's Shared Module Template.

Minimal version-catalog plugin wiring (full Gradle in references/project-setup.md):

kotlin
// gradle/libs.versions.toml
[versions]
kotlin = "2.2.20"
compose = "1.11.0"
agp = "9.0.0"

[plugins]
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose" }

expect / actual — the core mechanism

expect/actual is how you reach a platform API while keeping the call site common. Declare expect in commonMain; provide an actual in every target you compile.

kotlin
// commonMain
expect fun platformName(): String
kotlin
// androidMain
import android.os.Build
actual fun platformName(): String = "Android ${Build.VERSION.SDK_INT}"
kotlin
// iosMain
import platform.UIKit.UIDevice
actual fun platformName(): String =
    UIDevice.currentDevice.systemName + " " + UIDevice.currentDevice.systemVersion

Rules, each with the reason it exists:

  • Every expect needs an actual in every compiled target. An orphan expect is not a warning — it is a hard build failure (often only surfacing on the iOS target), so add the actual per target or remove the target.
  • Keep the common surface tiny. Each expect symbol multiplies into N actuals you maintain; expose the smallest function, not a fat class.
  • Prefer a common interface + DI over deep expect trees for anything you want to test or fake. expect class can't be mocked in common tests.
kotlin
// Bad: deep expect class — N actuals, untestable in commonTest
expect class Database {
    fun query(sql: String): List<Row>
    fun close()
}
kotlin
// Good: common interface, platform impls injected via Koin (fakeable in tests)
interface Database {
    fun query(sql: String): List<Row>
    fun close()
}
// androidMain/iosMain provide SqliteDatabase implementing Database, bound in a Koin module.
Show full SKILL.md (436 more words)Show less

Native interop

You bridge in both directions. Shared Compose embeds native views; native hosts embed shared Compose.

  • iOS — native view inside shared Compose: UIKitView / UIKitViewController with a factory lambda.
  • iOS — shared Compose inside SwiftUI: wrap ComposeUIViewController in a UIViewControllerRepresentable.
  • Android: AndroidView for native views; host the tree via setContent { App() } in an Activity.
  • Desktop: application { Window { App() } }; Swing interop via SwingPanel.

Embed a native view through an injected interface, not a raw expect — so the common screen stays platform-agnostic and testable:

kotlin
// commonMain
interface MapFactory { /* returns a platform map handle */ }

@Composable
fun MapScreen(mapFactory: MapFactory = koinInject()) {
    // iosMain provides the actual UIKitView wiring around mapFactory; see references/ios-interop.md
}

Full bridge patterns (ComposeUIViewController SwiftUI wrapper, native-view-factory-via-Koin, MapKit/camera, ViewModel lifecycle) live in references/ios-interop.md — read it before writing iOS interop.

State, ViewModel, navigation, DI

  • androidx.lifecycle.ViewModel works in commonMain. Obtain instances with koin-compose-viewmodel's koinViewModel { } so they survive recomposition. iOS has no built-in ViewModelStoreOwner — tie the VM lifecycle to SwiftUI manually (KMP-ObservableViewModel lets SwiftUI observe Kotlin VMs).
  • Koin is the common DI runtime. Define a shared initKoin() and call it from the Android Application and from iOS app init:
kotlin
// commonMain
fun initKoin(config: KoinAppDeclaration? = null) = startKoin {
    config?.invoke(this)
    modules(appModule, platformModule)
}
  • Navigation: androidx.navigation provides type-safe nav + deep links in commonMain.
  • Resources: compose.components.resources generates Res accessors — Res.string.app_name, Res.drawable.logo, fonts — shared across all platforms.

Running & packaging

  • Android: run the androidApp run config (hosts via setContent).
  • iOS: open iosApp in Xcode, or use the KMP iOS run config in the IDE.
  • Desktop: ./gradlew :desktopApp:run; package with ./gradlew :desktopApp:packageDistributionForCurrentOS (needs JDK 17+ for jpackage).
  • Web (Beta): ./gradlew :webApp:wasmJsBrowserDevelopmentRun.

Anti-patterns

Anti-patternWhy it bitesDo instead
android.* / platform.UIKit / java.awt import in commonMainBreaks the build for every other target, error surfaces far awayexpect/actual or inject via a common interface
expect with no actual for a targetHard build failure on that targetAdd an actual per compiled target or drop the target
Recreating a ViewModel each recomposition (remember { VM() } wrong)State loss on every recomposekoinViewModel { } / hoist state
Treating Compose Web as productionWeb is Beta (1.9), not StableShip Android/iOS/desktop; pilot Web only
Kotlin < 2.1.0 with CMP 1.8+K2 incompatibility — deps fail to linkBump to Kotlin 2.2.x
Deep expect class for testable logicCan't fake in commonTestCommon interface + Koin-injected platform impl
Pre-splitting into sharedLogic/sharedUI on day onePremature complexity, extra Gradle wiringStart with one shared module; split when a platform needs native UI

Verify

After scaffolding or editing, run scripts/verify.sh <project-dir> (read-only, no Gradle/Xcode needed). It statically checks the structural invariants:

  • a commonMain source set exists;
  • every expect in commonMain has a matching actual in some platform source set (catches orphans);
  • the Compose Multiplatform plugin (org.jetbrains.compose) and a Kotlin version are present, and Kotlin is >= 2.1.0 (K2 floor);
  • no forbidden platform imports leak into commonMain.

It exits 0 on a clean or empty target and non-zero only on hard failures.

© 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/compose-multiplatform of ericrisco/rsc-harness.

  • SKILL.md
  • evals/README.md
  • evals/cases.yaml
  • references/ios-interop.md
  • references/project-setup.md
  • scripts/verify.sh

Open the folder on GitHubat commit 92fde8f

Compare with similar skills

Compose Multiplatform 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.

Compose Multiplatform compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Compose Multiplatform this skillericrisco/rsc-harness156—~2.7kAutomated safety check: PassMIT
Ksafeioannisa/KSafe332—~17kAutomated safety check: PassApache-2.0
Developing Mobile Appstelagod/code-abyss244—~258Automated safety check: PassMIT
Senior Mobileborghei/Claude-Skills874—~1.9kAutomated safety check: PassMIT
Mobile Apps Createforcedotcom/sf-skills1.1k—~1.4kAutomated safety check: PassApache-2.0
Mobile App Developertheneoai/awesome-skills183—~2.1kAutomated safety check: PassMIT

Similar skills

  • 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
  • Developing Mobile Apps

    telagod/code-abyss

    Mobile development knowledge reference covering iOS (SwiftUI), Android (Jetpack Compose), React Native, and Flutter.

    244 GitHub stars~258 tokensUpdated 2 mo ago
    MobileAuto-check passed
  • Senior Mobile

    borghei/Claude-Skills

    A skill your agent uses when the user asks to "build a mobile app", "scaffold React Native project", "create SwiftUI views", "set up Jetpack Compose", "optimize mobile performance", "configure Expo…

    874 GitHub stars~1.9k tokensUpdated yesterday
    MobileAuto-check passed
  • Mobile Apps Create

    forcedotcom/sf-skills

    The entry point for building any Salesforce native mobile app on iOS or Android.

    1.1k GitHub stars~1.4k tokensUpdated 5 days ago
    MobileAuto-check passed
  • Mobile App Developer

    theneoai/awesome-skills

    Elite Mobile App Developer skill with expertise in native iOS (Swift), native Android (Kotlin), and cross-platform (React Native, Flutter).

    183 GitHub stars~2.1k tokensUpdated 4 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

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 yesterday
    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 yesterday
    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 yesterday
    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 yesterday
    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 yesterday
    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 yesterday
    Auto-check passed

Categories

Questions about Compose Multiplatform

What does Compose Multiplatform do?

A skill your agent uses when building one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform…. Compose Multiplatform is an agent skill from ericrisco/rsc-harness. Use when building one shared Compose UI in Kotlin across Android, iOS, and desktop — commonMain @Composables, expect/actual, source-set placement, native interop, multiplatform ViewModel/navigation/Koin.

When should I use Compose Multiplatform?

Compose Multiplatform fits situations like: building one shared Compose UI in Kotlin across Android; desktop — commonMain @Composables; source-set placement; multiplatform ViewModel/navigation/Koin.

How do I install Compose Multiplatform in Claude Code?

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

How do I install Compose Multiplatform in Codex?

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

Can I use Compose Multiplatform 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 compose-multiplatform -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/compose-multiplatform, .gemini/skills/compose-multiplatform, .github/skills/compose-multiplatform and .opencode/skills/compose-multiplatform in your project.

What does Compose Multiplatform need to run?

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

Does Compose Multiplatform 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 Compose Multiplatform 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 Compose Multiplatform use?

Compose Multiplatform 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 Compose Multiplatform use?

About 2.7k tokens (SKILL.md is roughly 11k 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 1.8k tokens, read only when the agent opens those files.

What are the alternatives to Compose Multiplatform?

Skills that share tags, products or a category with Compose Multiplatform: Ksafe (ioannisa/KSafe, 332 stars), Developing Mobile Apps (telagod/code-abyss, 244 stars), Senior Mobile (borghei/Claude-Skills, 874 stars) and Mobile Apps Create (forcedotcom/sf-skills, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Compose Multiplatform?

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.