Skip to content

UI Layer Agent

Ali Sadeghi edited this page May 18, 2026 · 4 revisions

UI Layer Agent

Implements the UI/presentation layer for KMP features. Invoked by creating-kmp-feature skill in Phase 3.

Model: sonnet · Color: purple · Allowed tools: Read, Write, Edit, Glob, Grep, ./gradlew

Generates

  • {Feature}UiState.kt — sealed interface, 4 states
  • {Feature}UiModel.kt — presentation model
  • {Feature}ViewModel.kt — uses setState { copy() }
  • presentation/ui/{Feature}Screen.kt — Screen + ScreenRoot + state routing
  • presentation/ui/components/ — self-contained UI units
  • presentation/navigation/@Serializable Route + NavGraphBuilder.{featurename}(…) extension

Workflow

  1. Follow the UI implementation workflow from _shared/patterns.md.
  2. Load architecture and design-system references on demand.
  3. Implement UiState (4-state sealed interface).
  4. Implement UiModel(s).
  5. Implement ViewModel with setState { copy() }.
  6. Implement Screen + ScreenRoot (both required).
  7. Handle all 4 UI states (Uninitialized / Loading / Success / Failed).
  8. Implement Navigation with callbacks (no navController in screens).
  9. Validate: ./gradlew :feature:{featurename}:assembleAndroidMain.

ScreenRoot Pattern (Required)

// Screen — ViewModel wrapper (NOT tested)
@Composable
fun FeatureScreen(viewModel: FeatureViewModel, onBackClick: () -> Unit) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    FeatureScreenRoot(
        uiState = uiState,
        onBackClick = onBackClick,
        onRetry = viewModel::retry,
    )
}

// ScreenRoot — ViewModel-independent (TESTABLE)
@Composable
fun FeatureScreenRoot(
    uiState: FeatureUiModel,
    onBackClick: () -> Unit,
    onRetry: () -> Unit,
) {
    // All UI here, X-components only
}

Navigation Pattern

Routes contain only data. The NavGraphBuilder extension wires the callbacks:

@Serializable
data object DashboardRoute

fun NavGraphBuilder.dashboard(
    onActionClick: (String) -> Unit,
    onBackToDashboard: () -> Unit,
) {
    composable<DashboardRoute> {
        DashboardScreen(
            viewModel = koinViewModel(),
            onActionClick = onActionClick,
            onBackToDashboard = onBackToDashboard,
        )
    }
}

BaseAppNavHost.kt then simply calls dashboard(...) — never composable<Route> { … } directly. This is what makes integration point #4 a one-liner.

UI File Organization Rule

{Feature}Screen.kt is the orchestrator and stays lean.

Keep in {Feature}Screen.kt Move to components/{Name}.kt
Screen and ScreenRoot Composable that's a "thing" on its own
State routing (when (uiState)) Owns its own structure / identity
Top-level layout scaffold Has private sub-composables
LoadingContent, ErrorContent

Guiding question: "Does this composable have meaning on its own, or only as part of the screen?" — meaning on its own → components/.

Design System Source

Uses X-components from :core:designsystem. The component-mapping reference (using-design-system/references/component-mappings.md) is loaded on demand. No Material3 components in feature files.

Design-Aware Mode

When invoked from a design-aware orchestrator the agent reads the blueprint's Component Tree from .claude/docs/{featurename}/designs/{featurename}_blueprint.md and:

  1. Applies the X-Component Constraint Check for every component the blueprint uses.
  2. Uses MaterialTheme.colorScheme.{role} exclusively — never raw Color() hex.
  3. Walks the blueprint's Post-Implementation Checklist before declaring done.

See Design-Pipeline.

Output Report

## UI Layer Complete: {featurename}

### Files Created
- presentation/{Feature}UiState.kt
- presentation/{Feature}UiModel.kt
- presentation/{Feature}ViewModel.kt
- presentation/ui/{Feature}Screen.kt
- presentation/ui/components/*.kt
- presentation/navigation/{Feature}Navigation.kt

### ScreenRoot Pattern
✅ {Feature}Screen     — ViewModel wrapper
✅ {Feature}ScreenRoot — ViewModel-independent

### Rules Followed
✅ setState {} used
✅ All 4 UI states handled
✅ X-components only
✅ ImmutableList for collections
✅ Callback parameters
✅ Build successful

Back to Feature-Development-Agents | Agents

Clone this wiki locally