$npx -y skills add mmiani/kotlin-kmp-claude-agent-skills --skill kotlin-ui-compose-multiplatformUse when designing, implementing, or reviewing shared UI in Compose Multiplatform projects, including state-driven architecture, composable decomposition, layout/modifier discipline, adaptive behavior, and previewable shared UI in common source sets.
| 1 | # Compose Multiplatform UI |
| 2 | |
| 3 | Use this skill when designing, implementing, or reviewing shared UI in a Compose Multiplatform project. |
| 4 | |
| 5 | This skill is intentionally strict. Its purpose is to keep shared UI declarative, state-driven, decomposed, adaptive, previewable, and cleanly separated from business logic and platform entry concerns. |
| 6 | |
| 7 | ## Primary goals |
| 8 | |
| 9 | The UI design should optimize for: |
| 10 | |
| 11 | - state-driven rendering |
| 12 | - clear composable decomposition |
| 13 | - business logic outside composables |
| 14 | - layout structure that remains understandable |
| 15 | - modifier usage that is intentional and explainable |
| 16 | - adaptive behavior across different window sizes |
| 17 | - previewability in common code |
| 18 | - clean separation between shared UI and platform-specific startup or OS integration |
| 19 | |
| 20 | Do not treat Compose UI as just “screens and widgets”. |
| 21 | Treat it as part of app architecture. |
| 22 | |
| 23 | ## Official defaults to prefer |
| 24 | |
| 25 | Unless the project has a strong reason not to, prefer: |
| 26 | |
| 27 | - UI driven from immutable state |
| 28 | - state hoisting when multiple composables need to coordinate state |
| 29 | - side effects handled deliberately rather than embedded in rendering paths |
| 30 | - composables focused on rendering and interaction, not business rules |
| 31 | - shared UI in `commonMain` when valid across targets |
| 32 | - platform-specific UI bootstrapping and OS integration in platform source sets |
| 33 | - adaptive layouts driven by structured window-size reasoning |
| 34 | - previewable shared UI with `@Preview` where useful |
| 35 | |
| 36 | --- |
| 37 | |
| 38 | ## KMP project-structure expectations |
| 39 | |
| 40 | Compose Multiplatform projects typically place shared Compose code in a shared source set such as `composeApp/src/commonMain/kotlin`, with platform-specific code in source sets such as `androidMain` and `iosMain`. |
| 41 | |
| 42 | Review expectations: |
| 43 | - shared composables, shared UI state models, and reusable UI components belong in shared source sets when they are valid across targets |
| 44 | - platform entry points, startup wiring, and OS-specific integrations stay in platform-specific source sets |
| 45 | - UI architecture does not assume Android-only behavior as the default model for shared code |
| 46 | |
| 47 | Flag as a concern when: |
| 48 | - shared UI is duplicated across targets without a real platform difference |
| 49 | - platform-specific assumptions leak into shared composables |
| 50 | - common UI code depends on platform-only APIs |
| 51 | |
| 52 | ## Review dimensions |
| 53 | |
| 54 | ### 1. State-driven UI |
| 55 | |
| 56 | Compose guidance treats state management as foundational. |
| 57 | |
| 58 | Check whether: |
| 59 | - UI renders from explicit immutable state |
| 60 | - rendering is driven by state instead of imperative mutation |
| 61 | - state ownership is clear |
| 62 | - composables are not reaching into dependencies ad hoc |
| 63 | |
| 64 | Flag as a concern when: |
| 65 | - composables fetch or mutate state from many unrelated places |
| 66 | - UI is driven by scattered booleans rather than a coherent model |
| 67 | - rendering depends on hidden mutable state |
| 68 | |
| 69 | ### 2. State hoisting |
| 70 | |
| 71 | Compose explicitly documents state hoisting as a core design tool. |
| 72 | |
| 73 | Check whether: |
| 74 | - state is hoisted when multiple composables need to coordinate it |
| 75 | - local state remains local when it is truly local |
| 76 | - app- or screen-level state is not trapped in leaf composables |
| 77 | - callbacks and state ownership are easy to trace |
| 78 | |
| 79 | Flag as a concern when: |
| 80 | - sibling composables coordinate through hidden shared state |
| 81 | - screen-critical state lives in leaf components |
| 82 | - hoisting is skipped and duplication appears across the tree |
| 83 | |
| 84 | ### 3. State lifespans and saveability |
| 85 | |
| 86 | Compose docs distinguish state lifespans and saving UI state. |
| 87 | |
| 88 | Check whether: |
| 89 | - ephemeral UI state is distinguished from longer-lived screen state |
| 90 | - saveable UI state is used intentionally where needed |
| 91 | - business-critical state is not confused with short-lived widget state |
| 92 | |
| 93 | **KMP platform note:** `rememberSaveable` with `Bundle`-based serialization is Android-specific. On iOS, desktop, and web KMP targets, the state-restoration mechanism differs or may not exist in the same form. If a project expects state restoration across process recreation on non-Android targets, verify that the chosen state-persistence mechanism is platform-appropriate rather than assuming `rememberSaveable` behavior is universal. |
| 94 | |
| 95 | Flag as a concern when: |
| 96 | - important UI state is lost unnecessarily on any target |
| 97 | - trivial widget state is elevated too far |
| 98 | - long-lived state is modeled as disposable local widget state |
| 99 | - `rememberSaveable` with Android-specific serializers is used in shared code without a non-Android fallback |
| 100 | |
| 101 | ### 4. Side-effect discipline |
| 102 | |
| 103 | Compose explicitly treats side effects as a distinct design concern. |
| 104 | |
| 105 | Check whether: |
| 106 | - side effects are isolated and deliberate |
| 107 | - recomposition does not accidentally retrigger important actions |
| 108 | - navigation, analytics, toasts, and |