templates/.claude/skills/kotlin-best-practices/SKILL.md
Idiomatic Kotlin patterns from JetBrains conventions
npx skillsauth add baekenough/oh-my-customcode kotlin-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply idiomatic Kotlin patterns and best practices from official JetBrains documentation.
Concise yet readable
Null safety by design
Interoperability with Java
Functional when appropriate
packages:
style: lowercase, no underscores
example: org.example.project
classes_objects:
style: UpperCamelCase
example: DeclarationProcessor
functions_variables:
style: lowerCamelCase
example: processDeclarations, declarationCount
constants:
style: SCREAMING_SNAKE_CASE
example: const val MAX_COUNT = 8
backing_properties:
style: underscore prefix
example: private val _elementList
acronyms:
two_letters: both uppercase (IOStream)
three_plus: capitalize first only (XmlFormatter)
file_naming:
single_class: name after the class (MyClass.kt)
multiple_classes: descriptive UpperCamelCase (ProcessDeclarations.kt)
platform_specific: add suffix (Platform.jvm.kt)
class_layout:
1: Property declarations and initializer blocks
2: Secondary constructors
3: Method declarations
4: Companion object
directory_structure:
- Follow package structure with common root omitted
- Example: org.example.kotlin.network → network/
indentation:
- 4 spaces (no tabs)
- Opening brace at end of line
- Closing brace on separate line
horizontal_whitespace:
around_binary_operators: "a + b"
no_around_range: "0..i"
no_around_unary: "a++"
after_control_keywords: "if (condition)"
no_before_parentheses: "method()"
never_around_dot: "foo.bar()"
colons:
type_supertype: "class Foo : Bar"
declaration_type: "val x: Int"
always_space_after: true
trailing_commas:
recommended: true
reason: cleaner diffs, easier reordering
expression_bodies:
prefer: "fun foo() = 1"
over: |
fun foo(): Int {
return 1
}
default_parameters:
prefer: "fun foo(a: String = \"a\")"
over: overloaded functions
single_line_signatures:
if_fits: "fun foo(a: Int): String = ..."
otherwise: |
fun longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType,
): ReturnType { }
unit_return:
avoid: "fun foo(): Unit { }"
prefer: "fun foo() { }"
principles:
- Prefer non-null types by default
- Use ? only when nullability is meaningful
- Leverage safe calls (?.) and elvis (?:)
patterns: |
// Safe call
val length = text?.length
// Elvis operator
val name = user?.name ?: "Anonymous"
// Let for null checks
user?.let {
println(it.name)
}
// Not-null assertion (use sparingly)
val name = user!!.name
immutability:
prefer: "val over var"
collections: "listOf() over arrayListOf()"
conditionals:
binary: use if
multiple: use when
patterns: |
// if expression
return if (x) foo() else bar()
// when expression
return when(x) {
0 -> "zero"
else -> "nonzero"
}
functional:
prefer: "list.filter { it > 10 }.map { it * 2 }"
over: manual loops (except forEach)
ranges:
prefer: "for (i in 0..<n)"
avoid: "for (i in 0..n - 1)"
type_aliases:
use_for: |
typealias MouseClickHandler = (Any, MouseEvent) -> Unit
typealias PersonIndex = Map<String, Person>
formatting:
- Spaces around curly braces: "list.filter { it > 10 }"
- Single lambda outside parentheses
- it for single parameter
patterns: |
// Outside parentheses
list.filter { it > 10 }
// Multiple parameters
list.fold(0) { acc, item -> acc + item }
// Destructuring
map.forEach { (key, value) -> println("$key = $value") }
principles:
- Use suspend functions for async operations
- Structured concurrency with scopes
- Proper exception handling
patterns: |
// Suspend function
suspend fun fetchData(): Data {
return withContext(Dispatchers.IO) {
api.getData()
}
}
// Coroutine scope
lifecycleScope.launch {
val data = fetchData()
updateUI(data)
}
// Exception handling
try {
val result = async { fetchData() }.await()
} catch (e: Exception) {
handleError(e)
}
format: |
/**
* Returns the absolute value of the given [number].
*/
fun abs(number: Int): Int { ... }
best_practices:
- Incorporate parameters into description
- Use brackets for parameter references
- Use @param/@return only for lengthy descriptions
When writing or reviewing Kotlin code:
development
Generate and maintain a persistent codebase wiki — LLM-built interlinked markdown knowledge base (Karpathy LLM Wiki pattern)
development
Use the project wiki as RAG knowledge source — search wiki pages to answer codebase questions before exploring raw files
tools
Analyze task trajectories to propose reusable SKILL.md candidates from successful patterns
data-ai
hada.io RSS feed monitoring for AI agent/harness articles with automated /scout analysis