| name | kotlin-kmp-boundary-interop |
| description | Use this skill to statically review Kotlin Multiplatform source-set architecture, expect/actual design and pairing completeness, platform-API-leakage prevention, cross-target dependency compatibility, Swift/Objective-C interop (suspend-to-async, @Throws, @ObjCName), and Kotlin/Native runtime correctness (new memory manager, freezing deprecation). Reads source and build configuration only; it never compiles or runs a target. |
| allowed-tools | Read Grep Glob |
| metadata | {"author":"github: Raishin","version":"0.1.0","updated":"2026-07-21","category":"architecture","lifecycle":"experimental"} |
kotlin-kmp-boundary-interop
Purpose
This skill decides whether a Kotlin Multiplatform boundary design is correct. A design is safe only when every expect declaration has a matching actual per target, no platform API leaks into commonMain, every common dependency is compatible with every target it propagates to, Swift/Objective-C interop annotations are used correctly, and no code or guidance still assumes the legacy frozen-object model Kotlin/Native has moved past.
Trigger conditions
- A user provides KMP source-set configuration, expect/actual declarations, or Gradle multiplatform build files and asks whether the boundary is designed correctly.
- A user is diagnosing a platform-API leak into commonMain, an incomplete expect/actual pairing, or a Swift/Objective-C interop mismatch.
- A user asks whether their Kotlin/Native code still needs freezing or is compatible with the current memory manager.
When not to use
- The question is whether to adopt KMP at all rather than how to structure it — route to
kotlin-kmp-portfolio-decision-agent.
- The question is Gradle build wiring or configuration cache rather than source-set architecture — route to
kotlin-gradle-build-engineering-agent.
- The question is KMP test source-set setup — route to
kotlin-test-architecture-agent.
- The task requires compiling or running any target, or invoking an iOS toolchain — this skill is static-review only.
- The concern is Android-only architecture with no multiplatform boundary involved — route to
kotlin-android-architecture-agent.
Lean operating rules
- CRITICAL — any code, comment, or review guidance that calls
freeze(), references @FreezingIsDeprecated, or assumes objects must be frozen before being shared across threads is legacy: freezing is a hard error starting Kotlin 2.1.0 and the new memory manager, default since 1.7.20 and the only manager since the legacy one was removed in 1.9.20, does not require it — flag and correct any such assumption rather than let it stand.
- CRITICAL — a platform-specific API or type (e.g.
java.io.File, an Android SDK class, an iOS Foundation type) referenced from commonMain either fails to compile or is being smuggled in through an unsafe workaround; require it be moved behind an expect/actual boundary or relocated to the correct platform source set.
- CRITICAL — an
expect declaration with no actual for one of the project's declared targets is a compile-time defect, not a style issue; treat any incomplete expect/actual pairing across all configured targets as blocking.
- HIGH — a dependency added to a common source set that does not actually support every platform source set that depends on it, transitively via the hierarchy, will fail to resolve or behave inconsistently on the unsupported target; require dependency compatibility be checked against every target reachable from where it's declared.
- HIGH — an expect/actual split drawn far wider than the actual platform difference, such as duplicating shared logic inside every actual instead of keeping it in commonMain and expecting only the true platform-specific piece, defeats the purpose of sharing; require the boundary be minimal.
- HIGH — a
suspend function exposed to Swift without confirming how it's exported (as async or a completion handler, depending on the Kotlin/Native version and configuration) risks a Swift-side API mismatch; require the exported shape be verified against the project's actual cinterop configuration rather than assumed.
- MEDIUM — a Kotlin exception thrown across the Swift boundary without
@Throws(Exception::class) (or an equivalent declared exception type) is not visible to Swift as a catchable NSError and will crash instead of being handled; require @Throws on any function whose exceptions Swift callers are expected to catch.
- MEDIUM —
@ObjCName is experimental and requires explicit opt-in; using it without the opt-in annotation, or relying on it in a stable public API without acknowledging its experimental status, is a defect to flag.
- MEDIUM — a custom source-set graph that bypasses or conflicts with
applyDefaultHierarchyTemplate() with no stated reason risks intermediate source sets not resolving as expected; require a stated reason for any manual override of the default hierarchy.
- Label every finding with an evidence-basis label: confirmed (source provided), inference (partial source), assumption (source absent), or unknown — a claim about runtime behaviour, deployment topology, or a version not shown in the artifacts is assumption at best.
References
Load these only when needed:
Response minimum
- A verdict (pass / pass-with-conditions / block) and the evidence level behind each claim.
- Findings grouped by source-set/hierarchy, expect/actual design, platform-API-leakage/dependency-compatibility, interop, and Kotlin/Native runtime correctness.
- A severity-labelled finding list, each with an evidence-basis label, and safe next actions plus any target/version the user must confirm.