Claude
Skills
Sign in
Back

kmp-feature-slice

Included with Lifetime
$97 forever

Procedural KMP feature generation workflow — step-by-step creation of feature slices with typed errors, compose-arch compliance, and build verification. Use when scaffolding a new feature module in a KMP/Compose Multiplatform project.

General

What this skill does


# KMP Feature Slice Generator

Procedural workflow for generating complete KMP feature slices. Enforces strict creation order, typed error handling, and compose-arch compliance.

**Prerequisites**: Read `compose-arch` skill first — it is the SINGLE SOURCE OF TRUTH for architecture rules.

## Companion skills (versions live there — do not duplicate)

- Architecture rules + Component/View/Screen split — `compose-arch`.
- DI annotations (`@BindingContainer`, `@Provides`, `@AssistedInject`) — `metro-di-mobile` (Metro 1.0.0).
- Navigation primitives (`Value<T>`, `ChildStack`) — `decompose`.
- HTTP — `ktor-client` (3.4.3).

When generating a slice, **always read these companion skills first** for current versions and idioms; never inline a version here.

## Project conventions (project-level glue, NOT framework)

This skill references three helpers that are **project conventions**, not Decompose/Metro/Kotlin APIs. Define them once in your `:core:*` modules (or substitute equivalents) before following the steps. If your project already has equivalents under different names, mentally remap.

| Helper | Lives in | Minimal definition / stand-in |
|--------|----------|-------------------------------|
| `componentScope()` | `:core:component` (typical) | Extension on `ComponentContext` returning a `CoroutineScope` tied to component lifecycle. **Stand-in**: Decompose Essenty's `coroutineScope()` from `essenty-coroutines-extensions` — same semantics. |
| `runCatchingApp { ... }` | `:core:result` (typical) | Project-level `runCatching` variant that maps `Throwable` to `AppResult.Failure` (typed-error mapping inside). **Stand-in**: plain `kotlin.runCatching { ... }` returning `kotlin.Result<T>`. |
| `AppResult<T>` | `:core:result` (typical) | Project sealed result type — usually `sealed interface AppResult<out T> { data class Success<T>(val value: T); data class Failure(val error: AppError) }`. **Stand-in**: `kotlin.Result<T>`. |

If these don't exist yet in the project, create them once in `:core:component` / `:core:result` (or whatever module convention the host project uses) **before** generating feature slices. Do NOT inline them per-feature.

Below, treat any reference to `componentScope()` / `runCatchingApp` / `AppResult` as a call into these conventions — substitute the stand-ins listed above if the project hasn't adopted them.

## Phase 1: Input Collection (LOW FREEDOM)

Collect these inputs before generating any code:

| Input | Required | Example |
|-------|----------|---------|
| **Feature name** | Yes | `OrderHistory` |
| **Data sources** | Yes | `remote-only`, `local+remote`, `local-only` |
| **Target platforms** | Yes | `android,ios,desktop`, `android,ios,desktop,wasm`, `all` |
| **Error types** | Yes | `network,validation`, `network,auth,conflict` |
| **Has list/detail?** | Yes | `list-only`, `detail-only`, `list+detail` |
| **Navigation** | Yes | `stack` (full screen), `slot` (dialog/modal), `none` |
| **Needs pagination?** | No | `true/false` (default: false) |
| **Parent module path** | Yes | `feature/order-history` |

### Error Type Catalog

Select from these typed error categories (see `references/error-patterns.md` for sealed class templates):

| Error Type | When to Use |
|------------|-------------|
| `network` | API calls, timeouts, connectivity |
| `validation` | User input, form data |
| `auth` | Token expired, unauthorized |
| `conflict` | Concurrent modification, duplicate |
| `not-found` | Missing resource |
| `storage` | Database, file system errors |
| `permission` | OS-level permissions (camera, location) |

## Phase 2: File Manifest (ZERO FREEDOM)

Based on inputs, generate the exact file list. Every feature slice follows this structure:

### Mandatory Files (always created)

```
feature/<name>/
├── api/
│   └── src/commonMain/kotlin/
│       ├── <Name>Component.kt          # Step 1: Interface
│       ├── <Name>Models.kt             # Step 2: Domain models + error types
│       └── <Name>Repository.kt         # Step 3: Repository interface (if data sources != none)
│
└── impl/
    └── src/commonMain/kotlin/
        ├── component/
        │   └── Default<Name>Component.kt   # Step 7: Component implementation
        ├── domain/
        │   ├── usecase/
        │   │   └── Get<Name>UseCase.kt     # Step 5: Primary use case
        │   └── repository/
        │       └── <Name>RepositoryImpl.kt # Step 6: Repository implementation
        ├── data/
        │   └── datasource/
        │       └── <Name>RemoteDataSource.kt  # Step 4: Remote data source
        ├── view/
        │   ├── <Name>ViewState.kt          # Step 8: View state
        │   ├── <Name>ViewEvent.kt          # Step 9: View events
        │   └── <Name>View.kt              # Step 10: View (pure UI)
        ├── screen/
        │   └── <Name>Screen.kt            # Step 11: Screen (thin adapter)
        └── di/
            └── <Name>Module.kt            # Step 12: DI module
```

### Conditional Files

| Condition | Additional Files | Insert at step |
|-----------|-----------------|---------------|
| `data-sources: local+remote` | `<Name>LocalDataSource.kt` | Step 4b — same step as RemoteDataSource |
| `local storage uses DataStore` (e.g. Settings-style features) | `commonMain` declares `expect` factory + interface; platform sourceSets supply actuals — typically `androidMain/.../<Name>Settings.android.kt` and `iosMain/.../<Name>Settings.ios.kt` (and `desktopMain` / `wasmJsMain` if targeted). Do NOT put DataStore construction in `commonMain`. | Step 4b — same step as LocalDataSource |
| `has: list+detail` | **Container** Component (`<Name>Component.kt`) owning `ChildStack<Config, Child>` + **two child Components**: `<Name>ListComponent.kt` and `<Name>DetailComponent.kt` (each with its own `viewState`/`Event`/`View`/`Screen`). Impl side mirrors with `Default<Name>Component`, `Default<Name>ListComponent`, `Default<Name>DetailComponent`. | Container interface at Step 1; child interfaces also at Step 1; container impl at Step 7 (drives `ChildStack`, exposes child factories); child impls at Step 7 (each owns its own state/use cases). View/State/Event/Screen for each child at Steps 8-11. |
| `pagination: true` | `<Name>Pager.kt` in `impl/domain/` | Step 5b — between Repository (Step 5) and Component (Step 7) |
| `navigation: stack` | Navigation config (`Config` sealed class + `ChildStack`) in `<Name>Component.kt` and `Default<Name>Component.kt` | Steps 1 + 7 |
| `navigation: slot` | Slot config in `<Name>Component.kt` and `Default<Name>Component.kt` | Steps 1 + 7 |

> **Component owning navigation alongside state.** A Component can expose BOTH `val viewState: Value<T>` AND `val childStack: Value<ChildStack<Config, Child>>`. They are independent fields.
>
> **List+detail uses the container pattern, not one Component with two states.** The container Component holds *only* the `ChildStack` and child factories — no `viewState` of its own. Each child Component (List, Detail) owns its own `viewState`, events, and use cases. This keeps each child testable in isolation and matches Decompose's `Children { }` rendering. A real example:
>
> ```kotlin
> // Container — navigation only, no viewState
> interface OrderHistoryComponent {
>     val childStack: Value<ChildStack<*, Child>>
>     sealed class Child {
>         data class List(val component: OrderHistoryListComponent) : Child()
>         data class Detail(val component: OrderHistoryDetailComponent) : Child()
>     }
> }
>
> // Each child is a full Component with its own viewState
> interface OrderHistoryListComponent {
>     val viewState: Value<OrderHistoryListViewState>
>     fun obtainEvent(event: OrderHistoryListEvent)
> }
> ```
>
> Avoid the anti-pattern of a single Component carrying `viewState: Value<ListState>` + `detailViewState: Value<DetailState>` + manual show/hide flags — that scales poorly and breaks the one-Component-one-screen mental model.

### Gradle Files

```
feature/<name>/
├── api/
│   └── build.gradle.kts        
Files: 5
Size: 38.2 KB
Complexity: 47/100
Category: General

Related in General