Modern kotlin
Agent Skills for Kotlin Development
npx -y skills add Heapy/kortex --skill modern-kotlinAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when writing, reviewing, or modernizing Kotlin code with recent language versions (2.0–2.4.x, including 2.4.10 and 2.4.20-Beta1), including context parameters, collection literals, guard conditions in when, multi-dollar interpolation, non-local break/continue, explicit backing fields, nested type aliases, name-based destructuring, data objects, Enum.entries, rangeUntil, unused-return-value checker, K2 smart casts, contracts, experimental -X compiler flags, and stdlib APIs such as Uuid, Base64, HexFormat, kotlin.time Instant/Clock, and atomics.
SKILL.md
13.5 KB, as published. Nobody here has run it
Modern Kotlin
Use this skill to write idiomatic Kotlin with the features added in the last four years (mid-2022 → 2026, Kotlin 1.7 → 2.4.20-Beta1) and to know exactly which compiler flag or opt-in each preview feature needs.
State as of July 2026:
- Latest stable: 2.4.10 (July 14, 2026). EAP: 2.4.20-Beta1 (2.4.20 final planned September 2026).
- Default language version is 2.4. K1 is gone: 2.4.0 dropped
-language-version 1.9; K2 has been the only compiler since 2.0.0 (May 2024). - Context receivers (
-Xcontext-receivers) were removed in 2.3.20 — always migrate to context parameters.
Detailed per-version notes with full stdlib/tooling changes live in references/ (linked at the bottom). Older
pre-2022 features (sealed interfaces, value classes, fun interface, Duration API, …) are in
references/kotlin-1.4-1.6.md.
Release timeline
| Version | Date | Language headliners |
|---|---|---|
| 1.7.0 / 1.7.20 | Jun / Sep 2022 | K2 Alpha; builder inference, T & Any, opt-in stable; ..< and data object previews |
| 1.8.0 / 1.8.20 | Dec 2022 / Apr 2023 | old JVM backend removed; Enum.entries preview, Base64/AutoCloseable experimental |
| 1.9.0 / 1.9.20 | Jul / Nov 2023 | entries, data object, ..<, time API stable; K2 Beta; KMP stable |
| 2.0.0 / 2.0.20 | May / Aug 2024 | K2 stable, smart-cast upgrades; copy() visibility migration; Uuid |
| 2.1.0 / 2.1.20 | Nov 2024 / Mar 2025 | previews: guard conditions, non-local break/continue, $$ interpolation; atomics, Instant |
| 2.2.0 / 2.2.20 | Jun / Sep 2025 | guards + $$ + non-local break/continue stable; context parameters preview; contracts previews |
| 2.3.0 / 2.3.20 | Dec 2025 / Mar 2026 | return-value checker, explicit backing fields; name-based destructuring; context receivers removed |
| 2.4.0 | Jun 3, 2026 | context parameters stable, collection literals, @IntroducedAt; K1 dropped |
| 2.4.10 | Jul 14, 2026 | bug fixes only — current stable |
| 2.4.20-Beta1 | Jun 24, 2026 | explicit context arguments stable; when via invokedynamic default (JVM 21+) |
Stable language features (no flags needed on 2.4.x)
Context parameters — stable 2.4.0
Declare dependencies implicitly available from the calling context; parameters are named and referenced explicitly.
Replaces context receivers. Preview since 2.2.0 (-Xcontext-parameters needed on 2.2–2.3 only).
interface UserService {
fun log(message: String)
}
context(users: UserService)
fun outputMessage(message: String) = users.log("Log: $message")
context(users: UserService)
val firstUser: String get() = users.findUserById(1)
Still experimental around it: explicit context arguments at call sites (-Xexplicit-context-arguments, stable in
2.4.20-Beta1) and callable references to context functions.
Docs
Explicit backing fields — stable 2.4.0
Public read-only type, private mutable storage — without the _x naming convention. Experimental in 2.3.0 behind
-Xexplicit-backing-fields.
val city: StateFlow<String>
field = MutableStateFlow("")
fun updateCity(newCity: String) {
city.value = newCity // resolves to the MutableStateFlow field in private scope
}
Guard conditions in when — stable 2.2.0
Extra if after a branch condition (preview in 2.1.0 behind -Xwhen-guards):
when (animal) {
is Animal.Dog -> animal.feedDog()
is Animal.Cat if !animal.mouseHunter -> animal.feedCat()
else -> println("Unknown animal")
}
Multi-dollar string interpolation — stable 2.2.0
$$"..." — only $$ interpolates; single $ is a literal. Perfect for JSON schema, Gradle version catalogs, regex.
Preview in 2.1.0 behind -Xmulti-dollar-interpolation.
val jsonSchema = $$"""
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "$${title}" }
"""
Non-local break and continue — stable 2.2.0
From lambdas passed to inline functions (preview in 2.1.0 behind -Xnon-local-break-continue):
for (element in elements) {
val v = element.nullableMethod() ?: run {
log.warning("skipping null"); continue
}
}
Data-flow-based when exhaustiveness — stable 2.3.0
Earlier checks and early returns count toward exhaustiveness — no redundant else (experimental in 2.2.20 behind
-Xdata-flow-based-exhaustiveness):
fun getPermissionLevel(role: UserRole): Int {
if (role == UserRole.ADMIN) return 99
return when (role) {
UserRole.MEMBER -> 10
UserRole.GUEST -> 1
} // no else needed
}
return in expression bodies — default 2.3.0
Allowed when the return type is explicit:
fun getDisplayNameOrDefault(userId: String?): String =
getDisplayName(userId ?: return "default")
Nested type aliases — stable 2.3.0
typealias inside classes/objects/functions (Beta in 2.2.0 behind -Xnested-type-aliases); cannot capture outer
type parameters.
Annotation targeting — stable 2.4.0
@all:meta-target applies an annotation to every applicable target of a property (@all:Email val email: String).- New defaulting rules: an unqualified annotation propagates to
param+property(orfield), not just the first applicable target. Both previewed in 2.2.0 (-Xannotation-target-all,-Xannotation-default-target).
2.1.0 stable resolution/checks
@SubclassOptInRequired— require opt-in to implement/extend an API.- Sealed-upper-bound exhaustiveness:
fun <T : Result> render(result: T) = when (result) { ... }withoutelse. - Generic-lambda overload resolution fixed (
store("") { 1 }picks the lambda overload).
K2 smart casts — 2.0.0
All default: boolean variables capturing type checks (val isCat = animal is Cat; if (isCat) animal.purr()),
is A || is B casts to the common supertype, implicit callsInPlace for inline functions, function-type val
properties, smart casts propagating into catch/finally, and correct types after ++/--.
2022–2023 era (1.7–1.9), all stable since 1.9.0 or earlier
data object— singleton with cleantoString()/equals()/hashCode()for sealed hierarchies.Enum.entries— allocation-freeEnumEntries<E>list replacingvalues();enumEntries<T>()for reified generics (stable 2.0.0)...<(rangeUntil) —in 0.0..<0.25open-ended ranges, replacinguntil.- Definitely non-nullable
T & Any(1.7.0); builder inference without flags (1.7.0); opt-in requirements stable (1.7.0); secondary constructors with bodies in value classes (1.9.0);data class+ Java records interop.
Experimental and preview features (flag required on 2.4.10)
Full flag index with platform flags: references/experimental-flags.md.
Collection literals — -Xcollection-literals (2.4.0)
val shapes: MutableList<String> = ["triangle", "square", "circle"]
val fruit = ["apple", "banana"] // List<String> by default
class Row(vararg val elements: Double) {
companion object { operator fun of(vararg elements: Double) = Row(*elements) }
}
Type comes from the expected type; custom types opt in with operator fun of. Cannot construct Java collection
types. KEEP-0416.
Explicit context arguments — -Xexplicit-context-arguments (2.4.0; stable in 2.4.20-Beta1)
sendNotification(emailSender = defaultEmailSender) — pass a context argument by name, e.g. to disambiguate
context-parameter overloads. KEEP-0448.
Name-based destructuring — -Xname-based-destructuring=<mode> (2.3.20)
Modes: only-syntax (new syntax only), name-mismatch (warn on positional-name mismatch), complete
(parenthesized form becomes name-based). Square brackets are the new explicit positional form. Syntax-only planned
stable in 2.5.
(val mail = email, val name = username) = user // by name
val [username, email] = user // by position
Unused return value checker — -Xreturn-value-checker=check|full (2.3.0)
Warns when a non-Unit result is silently discarded. @MustUseReturnValues scopes enforcement,
@IgnorableReturnValue exempts a function; suppress one call with val _ = compute(). In 2.4.0 the returnsResultOf contract
(-Xallow-returns-result-of) propagates the check through higher-order functions.
Context-sensitive resolution — -Xcontext-sensitive-resolution (2.2.0, improved 2.3.0)
Omit the type name where it is inferable (enum entries, sealed subtypes): when (problem) { CONNECTION -> ... }.
Contract extensions (2.2.20) — all with @OptIn(ExperimentalContracts::class)
-Xallow-contracts-on-more-functions— contracts in property accessors and specific operators; generics in contract type assertions.-Xallow-condition-implies-returns-contracts—(encoded != null) implies (returnsNotNull()).-Xallow-holdsin-contract—condition holdsIn blockfor smart casts inside DSL lambdas.
Reified types in catch — -Xallow-reified-type-in-catch (2.2.20)
inline fun <reified E : Throwable> handle(block: () -> Unit) { try { block() } catch (e: E) { ... } }
Other experimental
- Compile-time constants —
-Xintrinsic-const-evaluation(2.4.0): const evaluation for unsigned ops, string functions, enum.name. @IntroducedAt("1.1")—@OptIn(ExperimentalVersionOverloading::class)(2.4.0): hidden overloads for binary compatibility when adding optional parameters.whenvia invokedynamic —-Xwhen-expressions=indy(2.2.20); default for JVM target 21+ since 2.4.20-Beta1.- Data class
copy()visibility —@ConsistentCopyVisibility/@ExposedCopyVisibility/-Xconsistent-data-class-copy-visibility(2.0.20): alignscopy()visibility with a non-public primary constructor. - Warning management —
-Xwarning-level=NAME:(error|warning|disabled)(2.2.0),-Xsuppress-warning=NAME(2.1.0),-Wextraextra checks (2.1.0).
Compiler and toolchain changes that affect code
- 2.2.0: interface methods compile to JVM default methods by default; stable
-jvm-default(enable|no-compatibility|disable) replaces-Xjvm-default. GradlekotlinOptions {}is an error — usecompilerOptions {}. REPL deprecated (-Xreplto re-enable). - 2.1.0: JSpecify nullability violations are errors by default (
-Xnullability-annotations=strict). - 2.3.0: Java 25 bytecode;
-language-version 1.8dropped. 2.4.0: Java 26; K1 fully removed. - 2.3.20: Kotlin/JVM builds run through the Build Tools API by default; JetBrains
@Unmodifiablecollections become read-only in Kotlin (warning → error in 2.5). - kapt runs on K2 by default since 2.2.20 (opt-out deprecated).
- Machine-readable list of all compiler options:
org.jetbrains.kotlin:kotlin-compiler-arguments-description.
Modern stdlib quick map
| API | Since (experimental) | Stable |
|---|---|---|
kotlin.uuid.Uuid | 2.0.20 | 2.4.0 (V4/V7 generators still experimental) |
kotlin.time.Instant / Clock | 2.1.20 | 2.3.0 |
Base64 (kotlin.io.encoding) | 1.8.20 | 2.2.0 |
HexFormat (toHexString()) | 1.9.0 | 2.2.0 |
Common atomics (kotlin.concurrent.atomics) + update() | 2.1.20 / 2.2.20 | experimental |
AutoCloseable + use (common) | 1.8.20 | 2.0.0 |
Time API (TimeSource.Monotonic, measureTime) | 1.3.50 | 1.9.0 |
Path.walk() / visitFileTree() | 1.7.20 | 2.1.0 |
Path.copyToRecursively() / deleteRecursively() | 1.8.0 | experimental |
isSorted() family, UInt.toBigInteger() | — | 2.4.0 |
Map fallback (getOrPutIfMissing) | 2.4.0 | experimental |
StackTraceRecoverable | 2.4.20-Beta1 | experimental |
Deprecated to error: toLowerCase()/toUpperCase() → lowercase()/uppercase(); appendln() → appendLine()
(2.1.0).
References
Detailed per-version descriptions, including pre-2022 history:
- references/kotlin-2.4.md — 2.4.0, 2.4.10, 2.4.20-Beta1 in depth.
- references/kotlin-2.3.md — 2.3.0, 2.3.20.
- references/kotlin-2.2.md — 2.2.0, 2.2.20 (context parameters preview, contracts).
- references/kotlin-2.0-2.1.md — K2 rollout, smart casts, 2.1 previews.
- references/kotlin-1.7-1.9.md — 2022–2023: data objects, entries, rangeUntil.
- references/kotlin-1.4-1.6.md — 2020–2021 history: sealed interfaces, value
classes,
fun interface, Duration. - references/experimental-flags.md — every
-Xflag and opt-in with status.
Canonical upstream: What's new index · Releases · EAP · Compiler options · Components stability