kmp-clean-architecture

Defines and enforces a 6-layer clean architecture contract for Kotlin Multiplatform feature modules.

2|Updated Jun 6, 2026
One-click install
npx skills add https://github.com/ronjunevaldoz/kmp-agent-skills --skill kmp-clean-architecture-ronjunevaldoz
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: kmp-clean-architecture
Source: https://github.com/ronjunevaldoz/kmp-agent-skills/tree/main/skills/kmp-clean-architecture
Command: npx skills add https://github.com/ronjunevaldoz/kmp-agent-skills --skill kmp-clean-architecture-ronjunevaldoz

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Kotlin Multiplatform projects grow into tangled module graphs where UI code reaches into repositories, DTOs leak into domain logic, and nothing mechanically stops layer violations. This Skill defines a strict 6-layer contract (:model / :api / :domain / :data / :presenter / :ui) and shows how to enforce it with Gradle dependency declarations, internal visibility, and Detekt rules so violations fail the build instead of slipping through review. ## Core Features & Use Cases - Layer dependency contract: Unidirectional flow :model → :api → :domain → :presenter → :ui, with :data as a sibling of :presenter, plus rules for what belongs in each layer and when a thin feature can skip layers. - Mechanical enforcement: Gradle api()/implementation() boundary rules to prevent ABI/type leakage, internal visibility tables per layer, Detekt architecture fitness functions, and audit-script checks for wrong-direction dependencies and dependency cycles. - Concrete patterns: Use case pattern, DTO mapper pattern, typed domain errors and typed domain IDs with @JvmInline value classes, cross-feature navigation via AppNavigator, and composition-over-inheritance guidance for commonMain. - Use Case: When reviewing a pull request that adds Compose imports to a :presenter module or lets :ui depend on :data directly, use this Skill to identify the violated layer rule, place the code correctly, and add the Gradle or Detekt check that prevents recurrence. ## Quick Start Ask the agent to review your KMP feature module structure against the 6-layer clean architecture contract and fix any layer dependency violations it finds.

Frequently Asked Questions about kmp-clean-architecture

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I structure a Kotlin Multiplatform feature module with clean architecture?▼

Split each feature into up to six layers: :model (pure types), :api (repository interfaces), :domain (use cases), :data (repository implementations), :presenter (ViewModels, no Compose), and :ui (Compose screens). Start thin and only add layers when they carry real logic.

When should I use api() vs implementation() in Gradle Kotlin Multiplatform modules?▼

Default to implementation(). Use api() only when your module's own public declarations expose the dependency's types, such as :api exposing :model types returned from repository interfaces. A wrong choice compiles locally but breaks consumers with missing-classpath errors.

Should a ViewModel call a repository directly or always go through a use case?▼

Always route through a use case in this contract, even for trivial pass-throughs. The bright-line rule that a ViewModel only depends on :domain is mechanically checkable by audit scripts, while a judgment-call exception is not.

How do I prevent Compose dependencies from leaking into the presenter layer?▼

Keep :presenter free of Compose in its build.gradle.kts so ViewModels stay testable on plain JVM, and add a Detekt NoComposeInPresenter rule forbidding androidx.compose imports. The audit script also greps presenter build files for compose dependencies.

How do two KMP feature modules navigate between each other without depending on each other?▼

Declare an AppNavigator interface in :core:api with methods like navigateToProfile(userId). The :app module implements it using a NavControllerHolder populated by AppNavHost after rememberNavController(), and feature ViewModels inject AppNavigator via Koin.

When should I not add all six layers to a KMP feature?▼

Skip layers that carry no weight: static screens need no ViewModel, one-line pass-throughs need no separate :data module, and single local data sources can inline in :domain. The 6-layer structure is a maximum for complex features, not a default template.