AGENTS.kotlin.md — Kotlin (any target)
Additive to ../AGENTS.md. Applies to every .kt / .kts file: Android, KMP,
Spring Boot, CLIs and libraries. Target rules are in AGENTS.android.md,
AGENTS.kmp.md and AGENTS.spring.md.
Build and check
./gradlew ktlintFormat # fix formatting first
./gradlew ktlintCheck detekt # must pass
./gradlew test # JVM modules; Android variants: see AGENTS.android.md
Never commit with ktlintCheck failing “because CI will format it”. CI does not
format. CI fails.
Kotlin rules
- No
!!. If you believe a value cannot be null, encode that in the type or userequireNotNull(x) { "why this cannot be null" }with a real message. detekt enforces this; the pre-commit hook accepts// allow-bangon a line it must let through. - No
runBlockingoutside tests andmain(). Suspend functions all the way up. The one inmain()gets a// allow-blockingcomment so CI stays quiet. - No
GlobalScope. Use the injected scope (on Android,viewModelScope). - Dispatchers are injected, never hardcoded: take a
CoroutineDispatcherparameter (or aDispatcherProvider) so tests can substitute. - Never swallow
CancellationException. Acatch (e: Exception)orrunCatchingaround a suspend call must rethrow it. - Prefer
sealed interfacefor state,data classfor payloads,value classfor identifiers. AStringuserId is a bug waiting to be swapped with aStringsessionId. - Public API of a module needs KDoc on the entry points only. Do not KDoc private functions to satisfy a linter.
- No new
objectsingletons holding mutable state. Use DI.
Gradle rules
- Dependencies are declared in
gradle/libs.versions.tomlonly. No inlineimplementation("group:artifact:1.2.3")in a module build file. - No new Gradle plugin without Platform review. Plugins are Kitchen.
- Module build files stay boring: plugins block, the target’s block (
android,kotlin,springBoot), dependencies. Custom logic goes in a convention plugin underbuild-logic/.
Testing
- Unit tests for logic, Turbine for flows,
runTestfor coroutines (neverThread.sleepor real delays). - A bug fix lands with a test that fails before the fix. No exceptions, and this is the one rule an agent may not “simplify”.
- Do not delete or
@Ignorea failing test to make CI green. Quarantining is a human decision, recorded in the PR.
Anti-patterns seen in this repo
- Wildcard imports (
import foo.*) — ktlint catches these; do not suppress it. @Suppresswithout a trailing comment explaining why and when it can go.