Loading...
Loading...
Use when writing, changing or reviewing code that touches the house contract for Jetpack Compose and Compose Multiplatform apps: module graph, MVI/BaseViewModel, error tiers, state ownership, naming, Koin DI, Navigation 3 and coroutines. The compose skill is the entry point. Do NOT use for Gradle-only work (compose-project), new screens (compose-feature), composable-only work (compose-ui), repositories or persistence (compose-data), or expect/actual splits (compose-platform).
npx skill4agent add meet-miyani/compose-skill compose-architecturecomposetemplates/coreBaseViewModellaunchGuardedAppErrorgradle/libs.versions.tomlcompose-feature/references/review-mode.mdcompose-feature| Task | Use instead |
|---|---|
| Add, change or review a screen, destination or slice | the |
| Write or review composables, lists, motion, accessibility, tokens, resources | the |
| Write or review repositories, Ktor, Room, DataStore, Paging, offline-first | the |
| New project or module, convention plugins, version catalog, CI, hooks, adoption | the |
| the |
| Navigation 3 API mechanics (scenes, decorators, deep-link recipes, transitions) | the android/skills |
Iron law: never mix two patterns in one feature. New work follows this contract. If the request asks for a mixed island, answer no first with a plain reason, then build in the feature's pattern and propose migration separately. Precedent is evidence, not permission.
existing-projects.md:feature:*:data:*:core:*:core:*:data:*:data:<domain>UiEffectBaseViewModel<Action, State, Effect>onActionContract.ktUiStateUiActionUiEffectpresentation/<destination>/model/UiEffecteffecterrorsEffectlaunchGuarded(onError = …)runGuardedtry/catchResultCancellationExceptiononErrorlaunchGuardedJobUiStateAppErrorAppErrorcatch| Situation | Tier | Wiring |
|---|---|---|
| First load, nothing to show yet | inline | |
| Refresh fails over visible content | popup | Keep content; |
| User-initiated action fails | popup, or inline at a recoverable field | |
| Background poll, user did not trigger | silent, named as a poll | |
| Session expired (401) | none | Session sign-out path; suppressed at the host |
rememberSaveableUiStateLaunchedEffectSavedStateHandleUiStatedata/domain/presentation/navigation/di/suspend fun getX(…)fun getXStream(…): Flow<…>observeXgetXFlowgetXPagerSavedStateHandlenavigation.mddi/@KoinViewModel@InjectedParamParams@Serializable sealed interface <Feature>NavKey : NavKeyNavDisplaygradle/libs.versions.toml@param@returnifforwhiledowhenwhenifelsecode-craft.mdcompose| Thought | Reality |
|---|---|
| "I'll just add one kit MVI screen inside this MVVM/Hilt feature to save time." | No. Rule 1: build in the feature's pattern, propose migration separately. |
| "The file next to mine does it the old way, so I will too." | Precedent is evidence, not permission (rule 1). |
| "First-load failure goes to the popup host; the host handles errors." | No. Rule 8: first load with no content is inline with Retry. |
"A | No. Rule 6: every async call site uses |
"I'll wrap the call in a | No. Rule 6 forbids |
| "Stale list with no message is fine for this refresh." | No. Rule 8: silent is only for named polls. |
"I'll mirror the title into | No. Rule 9 forbids mirrors; rule 10 puts drafts in |
| "I'll import the other feature's ViewModel; it is only one screen." | No. Rules 1–3: shared state to |
| "I'll comment every line so it's clear." | No. Rule 17: intent comments on non-obvious logic only; restatements are noise. Delete them. |
| "I'll rebuild it the kit way." | No. Stance item 9: extend the existing slice; rebuild only when asked. |
| "The name is obvious; no KDoc needed on this public repository." | No. Rule 17: cross-module APIs carry short KDoc even when the name is clear. |
| "It's one line; braces are noise." | No. Rule 17: multi-line bodies are braced and single-line |
scripts/composekit/run-checks.shscripts/run-checks.sh <project-root>*Contract.kt*UiState*UiAction*UiEffectlaunchGuardedonErrortry/catchResultCancellationExceptionvarFlowStreaminternal:appNavDisplayContract.ktSavedStateHandleON_START