Agent skill

Kotlin Patterns

by affaan-m in affaan-m/ECC

Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL.

MITAuto-check passedMobile

Install Kotlin Patterns

skills CLI
$ npx skills add affaan-m/ECC --skill kotlin-patterns -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install affaan-m/ECC kotlin-patterns --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .claude/skills && cp -r skills-src/docs/es/skills/kotlin-patterns .claude/skills/kotlin-patterns && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
kotlin-patterns
GitHub stars
276k
Token cost
~4.8k tokens
SKILL.md length
412 words
Files
1
Skills in repo
673
Repo updated
First seen
Licence
MIT

At a glance

Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL.

  • Works in 4 steps: Null Safety → Inmutabilidad por Defecto → Cuerpos de Expresión y Funciones de Una… → …
  • Tasks that involve Android development
  • SKILL.md covers Cuándo Usar, Cómo Funciona, Ejemplos and Principios Fundamentales, plus 8 more sections
  • Reaches kotlinlang.org

What it does

Kotlin Patterns is an agent skill from affaan-m/ECC. Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL.

Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering Android development. It works with Kotlin. The repository describes itself as: The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond. The licence is MIT.

When your agent uses it

  • Tasks that involve Android development

Example prompts

  • “Use the kotlin-patterns skill to patrone idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas…”
  • “/kotlin-patterns”

Workflow steps

4 steps, taken from the step headings in SKILL.md.

  1. Null Safety
  2. Inmutabilidad por Defecto
  3. Cuerpos de Expresión y Funciones de Una Sola Expresión
  4. Data Classes para Objetos de Valor

What it can do on your machine

Read from SKILL.md and the folder at commit ef648e0. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are kotlin).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • kotlinlang.org

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Kotlin Patterns loads about 4.8k tokens when it runs. Until then it costs about 49 tokens; SKILL.md has 412 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~49
When it runs · the whole SKILL.md, loaded when a task matches
~4.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from affaan-m/ECC at commit ef648e0, republished under its MIT licence (© affaan-m). 412 words, ~4,846 tokens.

Download SKILL.mdSave it as .claude/skills/kotlin-patterns/SKILL.md (or your agent's skills folder).
name
kotlin-patterns
description
Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL.
origin
ECC

Patrones de Desarrollo Kotlin

Patrones idiomáticos de Kotlin y buenas prácticas para construir aplicaciones robustas, eficientes y mantenibles.

Cuándo Usar

  • Escribir nuevo código Kotlin
  • Revisar código Kotlin
  • Refactorizar código Kotlin existente
  • Diseñar módulos o librerías Kotlin
  • Configurar builds con Gradle Kotlin DSL

Cómo Funciona

Este skill aplica convenciones idiomáticas de Kotlin en siete áreas clave: null safety usando el sistema de tipos y operadores de llamada segura, inmutabilidad mediante val y copy() en data classes, clases selladas e interfaces para jerarquías de tipos exhaustivas, concurrencia estructurada con coroutines y Flow, funciones de extensión para agregar comportamiento sin herencia, builders de DSL type-safe usando @DslMarker y receptores lambda, y Gradle Kotlin DSL para configuración de build.

Ejemplos

Null safety con el operador Elvis:

kotlin
fun getUserEmail(userId: String): String {
    val user = userRepository.findById(userId)
    return user?.email ?: "unknown@example.com"
}

Sealed class para resultados exhaustivos:

kotlin
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Failure(val error: AppError) : Result<Nothing>()
    data object Loading : Result<Nothing>()
}

Concurrencia estructurada con async/await:

kotlin
suspend fun fetchUserWithPosts(userId: String): UserProfile =
    coroutineScope {
        val user = async { userService.getUser(userId) }
        val posts = async { postService.getUserPosts(userId) }
        UserProfile(user = user.await(), posts = posts.await())
    }

Principios Fundamentales

1. Null Safety

El sistema de tipos de Kotlin distingue tipos nullable de no-nullable. Aprovecharlo al máximo.

kotlin
// Bien: Usar tipos no-nullable por defecto
fun getUser(id: String): User {
    return userRepository.findById(id)
        ?: throw UserNotFoundException("User $id not found")
}

// Bien: Llamadas seguras y operador Elvis
fun getUserEmail(userId: String): String {
    val user = userRepository.findById(userId)
    return user?.email ?: "unknown@example.com"
}

// Mal: Desempaquetar forzadamente tipos nullable
fun getUserEmail(userId: String): String {
    val user = userRepository.findById(userId)
    return user!!.email // Lanza NPE si es null
}
2. Inmutabilidad por Defecto

Preferir val sobre var, colecciones inmutables sobre mutables.

kotlin
// Bien: Datos inmutables
data class User(
    val id: String,
    val name: String,
    val email: String,
)

// Bien: Transformar con copy()
fun updateEmail(user: User, newEmail: String): User =
    user.copy(email = newEmail)

// Bien: Colecciones inmutables
val users: List<User> = listOf(user1, user2)
val filtered = users.filter { it.email.isNotBlank() }

// Mal: Estado mutable
var currentUser: User? = null // Evitar estado global mutable
val mutableUsers = mutableListOf<User>() // Evitar a menos que sea realmente necesario
3. Cuerpos de Expresión y Funciones de Una Sola Expresión

Usar cuerpos de expresión para funciones concisas y legibles.

kotlin
// Bien: Cuerpo de expresión
fun isAdult(age: Int): Boolean = age >= 18

fun formatFullName(first: String, last: String): String =
    "$first $last".trim()

fun User.displayName(): String =
    name.ifBlank { email.substringBefore('@') }

// Bien: When como expresión
fun statusMessage(code: Int): String = when (code) {
    200 -> "OK"
    404 -> "Not Found"
    500 -> "Internal Server Error"
    else -> "Unknown status: $code"
}

// Mal: Cuerpo de bloque innecesario
fun isAdult(age: Int): Boolean {
    return age >= 18
}
4. Data Classes para Objetos de Valor

Usar data classes para tipos que principalmente contienen datos.

kotlin
// Bien: Data class con copy, equals, hashCode, toString
data class CreateUserRequest(
    val name: String,
    val email: String,
    val role: Role = Role.USER,
)

// Bien: Value class para type safety (cero overhead en tiempo de ejecución)
@JvmInline
value class UserId(val value: String) {
    init {
        require(value.isNotBlank()) { "UserId cannot be blank" }
    }
}

@JvmInline
value class Email(val value: String) {
    init {
        require('@' in value) { "Invalid email: $value" }
    }
}

fun getUser(id: UserId): User = userRepository.findById(id)

Clases Selladas e Interfaces

Modelar Jerarquías Restringidas
kotlin
// Bien: Sealed class para when exhaustivo
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Failure(val error: AppError) : Result<Nothing>()
    data object Loading : Result<Nothing>()
}

fun <T> Result<T>.getOrNull(): T? = when (this) {
    is Result.Success -> data
    is Result.Failure -> null
    is Result.Loading -> null
}

fun <T> Result<T>.getOrThrow(): T = when (this) {
    is Result.Success -> data
    is Result.Failure -> throw error.toException()
    is Result.Loading -> throw IllegalStateException("Still loading")
}
Sealed Interfaces para Respuestas de API
kotlin
sealed interface ApiError {
    val message: String

    data class NotFound(override val message: String) : ApiError
    data class Unauthorized(override val message: String) : ApiError
    data class Validation(
        override val message: String,
        val field: String,
    ) : ApiError
    data class Internal(
        override val message: String,
        val cause: Throwable? = null,
    ) : ApiError
}

fun ApiError.toStatusCode(): Int = when (this) {
    is ApiError.NotFound -> 404
    is ApiError.Unauthorized -> 401
    is ApiError.Validation -> 422
    is ApiError.Internal -> 500
}

Funciones de Scope

Cuándo Usar Cada Una
kotlin
// let: Transformar resultado nullable o delimitado
val length: Int? = name?.let { it.trim().length }

// apply: Configurar un objeto (retorna el objeto)
val user = User().apply {
    name = "Alice"
    email = "alice@example.com"
}

// also: Efectos secundarios (retorna el objeto)
val user = createUser(request).also { logger.info("Created user: ${it.id}") }

// run: Ejecutar un bloque con receptor (retorna resultado)
val result = connection.run {
    prepareStatement(sql)
    executeQuery()
}

// with: Forma no-extensión de run
val csv = with(StringBuilder()) {
    appendLine("name,email")
    users.forEach { appendLine("${it.name},${it.email}") }
    toString()
}
Anti-Patrones
kotlin
// Mal: Anidar funciones de scope
user?.let { u ->
    u.address?.let { addr ->
        addr.city?.let { city ->
            println(city) // Difícil de leer
        }
    }
}

// Bien: Encadenar llamadas seguras en su lugar
val city = user?.address?.city
city?.let { println(it) }

Funciones de Extensión

Agregar Funcionalidad Sin Herencia
kotlin
// Bien: Extensiones específicas del dominio
fun String.toSlug(): String =
    lowercase()
        .replace(Regex("[^a-z0-9\\s-]"), "")
        .replace(Regex("\\s+"), "-")
        .trim('-')

fun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =
    atZone(zone).toLocalDate()

// Bien: Extensiones de colecciones
fun <T> List<T>.second(): T = this[1]

fun <T> List<T>.secondOrNull(): T? = getOrNull(1)

// Bien: Extensiones delimitadas (sin contaminar el namespace global)
class UserService {
    private fun User.isActive(): Boolean =
        status == Status.ACTIVE && lastLogin.isAfter(Instant.now().minus(30, ChronoUnit.DAYS))

    fun getActiveUsers(): List<User> = userRepository.findAll().filter { it.isActive() }
}

Coroutines

Concurrencia Estructurada
kotlin
// Bien: Concurrencia estructurada con coroutineScope
suspend fun fetchUserWithPosts(userId: String): UserProfile =
    coroutineScope {
        val userDeferred = async { userService.getUser(userId) }
        val postsDeferred = async { postService.getUserPosts(userId) }

        UserProfile(
            user = userDeferred.await(),
            posts = postsDeferred.await(),
        )
    }

// Bien: supervisorScope cuando los hijos pueden fallar independientemente
suspend fun fetchDashboard(userId: String): Dashboard =
    supervisorScope {
        val user = async { userService.getUser(userId) }
        val notifications = async { notificationService.getRecent(userId) }
        val recommendations = async { recommendationService.getFor(userId) }

        Dashboard(
            user = user.await(),
            notifications = try {
                notifications.await()
            } catch (e: CancellationException) {
                throw e
            } catch (e: Exception) {
                emptyList()
            },
            recommendations = try {
                recommendations.await()
            } catch (e: CancellationException) {
                throw e
            } catch (e: Exception) {
                emptyList()
            },
        )
    }
Flow para Streams Reactivos
kotlin
// Bien: Flow frío con manejo de errores adecuado
fun observeUsers(): Flow<List<User>> = flow {
    while (currentCoroutineContext().isActive) {
        val users = userRepository.findAll()
        emit(users)
        delay(5.seconds)
    }
}.catch { e ->
    logger.error("Error observing users", e)
    emit(emptyList())
}

// Bien: Operadores de Flow
fun searchUsers(query: Flow<String>): Flow<List<User>> =
    query
        .debounce(300.milliseconds)
        .distinctUntilChanged()
        .filter { it.length >= 2 }
        .mapLatest { q -> userRepository.search(q) }
        .catch { emit(emptyList()) }
Cancelación y Limpieza
kotlin
// Bien: Respetar la cancelación
suspend fun processItems(items: List<Item>) {
    items.forEach { item ->
        ensureActive() // Verificar cancelación antes del trabajo costoso
        processItem(item)
    }
}

// Bien: Limpieza con try/finally
suspend fun acquireAndProcess() {
    val resource = acquireResource()
    try {
        resource.process()
    } finally {
        withContext(NonCancellable) {
            resource.release() // Siempre liberar, incluso al cancelar
        }
    }
}

Delegación

Delegación de Propiedades
kotlin
// Inicialización diferida
val expensiveData: List<User> by lazy {
    userRepository.findAll()
}

// Propiedad observable
var name: String by Delegates.observable("initial") { _, old, new ->
    logger.info("Name changed from '$old' to '$new'")
}

// Propiedades respaldadas por Map
class Config(private val map: Map<String, Any?>) {
    val host: String by map
    val port: Int by map
    val debug: Boolean by map
}

val config = Config(mapOf("host" to "localhost", "port" to 8080, "debug" to true))
Delegación de Interfaces
kotlin
// Bien: Delegar implementación de interfaz
class LoggingUserRepository(
    private val delegate: UserRepository,
    private val logger: Logger,
) : UserRepository by delegate {
    // Solo sobreescribir lo que necesitas agregar logging
    override suspend fun findById(id: String): User? {
        logger.info("Finding user by id: $id")
        return delegate.findById(id).also {
            logger.info("Found user: ${it?.name ?: "null"}")
        }
    }
}

Builders de DSL

Builders Type-Safe
kotlin
// Bien: DSL con @DslMarker
@DslMarker
annotation class HtmlDsl

@HtmlDsl
class HTML {
    private val children = mutableListOf<Element>()

    fun head(init: Head.() -> Unit) {
        children += Head().apply(init)
    }

    fun body(init: Body.() -> Unit) {
        children += Body().apply(init)
    }

    override fun toString(): String = children.joinToString("\n")
}

fun html(init: HTML.() -> Unit): HTML = HTML().apply(init)

// Uso
val page = html {
    head { title("My Page") }
    body {
        h1("Welcome")
        p("Hello, World!")
    }
}
Show full SKILL.md (165 more words)Show less
DSL de Configuración
kotlin
data class ServerConfig(
    val host: String = "0.0.0.0",
    val port: Int = 8080,
    val ssl: SslConfig? = null,
    val database: DatabaseConfig? = null,
)

data class SslConfig(val certPath: String, val keyPath: String)
data class DatabaseConfig(val url: String, val maxPoolSize: Int = 10)

class ServerConfigBuilder {
    var host: String = "0.0.0.0"
    var port: Int = 8080
    private var ssl: SslConfig? = null
    private var database: DatabaseConfig? = null

    fun ssl(certPath: String, keyPath: String) {
        ssl = SslConfig(certPath, keyPath)
    }

    fun database(url: String, maxPoolSize: Int = 10) {
        database = DatabaseConfig(url, maxPoolSize)
    }

    fun build(): ServerConfig = ServerConfig(host, port, ssl, database)
}

fun serverConfig(init: ServerConfigBuilder.() -> Unit): ServerConfig =
    ServerConfigBuilder().apply(init).build()

// Uso
val config = serverConfig {
    host = "0.0.0.0"
    port = 443
    ssl("/certs/cert.pem", "/certs/key.pem")
    database("jdbc:postgresql://localhost:5432/mydb", maxPoolSize = 20)
}

Secuencias para Evaluación Diferida

kotlin
// Bien: Usar secuencias para colecciones grandes con múltiples operaciones
val result = users.asSequence()
    .filter { it.isActive }
    .map { it.email }
    .filter { it.endsWith("@company.com") }
    .take(10)
    .toList()

// Bien: Generar secuencias infinitas
val fibonacci: Sequence<Long> = sequence {
    var a = 0L
    var b = 1L
    while (true) {
        yield(a)
        val next = a + b
        a = b
        b = next
    }
}

val first20 = fibonacci.take(20).toList()

Gradle Kotlin DSL

Configuración de build.gradle.kts
kotlin
// Verificar las últimas versiones: https://kotlinlang.org/docs/releases.html
plugins {
    kotlin("jvm") version "2.3.10"
    kotlin("plugin.serialization") version "2.3.10"
    id("io.ktor.plugin") version "3.4.0"
    id("org.jetbrains.kotlinx.kover") version "0.9.7"
    id("io.gitlab.arturbosch.detekt") version "1.23.8"
}

group = "com.example"
version = "1.0.0"

kotlin {
    jvmToolchain(21)
}

dependencies {
    // Ktor
    implementation("io.ktor:ktor-server-core:3.4.0")
    implementation("io.ktor:ktor-server-netty:3.4.0")
    implementation("io.ktor:ktor-server-content-negotiation:3.4.0")
    implementation("io.ktor:ktor-serialization-kotlinx-json:3.4.0")

    // Exposed
    implementation("org.jetbrains.exposed:exposed-core:1.0.0")
    implementation("org.jetbrains.exposed:exposed-dao:1.0.0")
    implementation("org.jetbrains.exposed:exposed-jdbc:1.0.0")
    implementation("org.jetbrains.exposed:exposed-kotlin-datetime:1.0.0")

    // Koin
    implementation("io.insert-koin:koin-ktor:4.2.0")

    // Coroutines
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")

    // Pruebas
    testImplementation("io.kotest:kotest-runner-junit5:6.1.4")
    testImplementation("io.kotest:kotest-assertions-core:6.1.4")
    testImplementation("io.kotest:kotest-property:6.1.4")
    testImplementation("io.mockk:mockk:1.14.9")
    testImplementation("io.ktor:ktor-server-test-host:3.4.0")
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
}

tasks.withType<Test> {
    useJUnitPlatform()
}

detekt {
    config.setFrom(files("config/detekt/detekt.yml"))
    buildUponDefaultConfig = true
}

Patrones de Manejo de Errores

Tipo Result para Operaciones de Dominio
kotlin
// Bien: Usar Result de Kotlin o una sealed class personalizada
suspend fun createUser(request: CreateUserRequest): Result<User> = runCatching {
    require(request.name.isNotBlank()) { "Name cannot be blank" }
    require('@' in request.email) { "Invalid email format" }

    val user = User(
        id = UserId(UUID.randomUUID().toString()),
        name = request.name,
        email = Email(request.email),
    )
    userRepository.save(user)
    user
}

// Bien: Encadenar resultados
val displayName = createUser(request)
    .map { it.name }
    .getOrElse { "Unknown" }
require, check, error
kotlin
// Bien: Precondiciones con mensajes claros
fun withdraw(account: Account, amount: Money): Account {
    require(amount.value > 0) { "Amount must be positive: $amount" }
    check(account.balance >= amount) { "Insufficient balance: ${account.balance} < $amount" }

    return account.copy(balance = account.balance - amount)
}

Operaciones de Colecciones

Procesamiento Idiomático de Colecciones
kotlin
// Bien: Operaciones encadenadas
val activeAdminEmails: List<String> = users
    .filter { it.role == Role.ADMIN && it.isActive }
    .sortedBy { it.name }
    .map { it.email }

// Bien: Agrupación y agregación
val usersByRole: Map<Role, List<User>> = users.groupBy { it.role }

val oldestByRole: Map<Role, User?> = users.groupBy { it.role }
    .mapValues { (_, users) -> users.minByOrNull { it.createdAt } }

// Bien: Associate para creación de maps
val usersById: Map<UserId, User> = users.associateBy { it.id }

// Bien: Partition para dividir
val (active, inactive) = users.partition { it.isActive }

Referencia Rápida: Modismos de Kotlin

ModismoDescripción
val sobre varPreferir variables inmutables
data classPara objetos de valor con equals/hashCode/copy
sealed class/interfacePara jerarquías de tipos restringidas
value classPara wrappers type-safe con cero overhead
when expresiónPattern matching exhaustivo
Llamada segura ?.Acceso a miembros null-safe
Elvis ?:Valor por defecto para nullables
let/apply/also/run/withFunciones de scope para código limpio
Funciones de extensiónAgregar comportamiento sin herencia
copy()Actualizaciones inmutables en data classes
require/checkAserciones de precondiciones
Coroutine async/awaitEjecución concurrente estructurada
FlowStreams reactivos fríos
sequenceEvaluación diferida
Delegación byReutilizar implementación sin herencia

Anti-Patrones a Evitar

kotlin
// Mal: Desempaquetar forzadamente tipos nullable
val name = user!!.name

// Mal: Fuga de tipos de plataforma desde Java
fun getLength(s: String) = s.length // Seguro
fun getLength(s: String?) = s?.length ?: 0 // Manejar nulls de Java

// Mal: Data classes mutables
data class MutableUser(var name: String, var email: String)

// Mal: Usar excepciones para control de flujo
try {
    val user = findUser(id)
} catch (e: NotFoundException) {
    // No usar excepciones para casos esperados
}

// Bien: Usar retorno nullable o Result
val user: User? = findUserOrNull(id)

// Mal: Ignorar el scope de coroutine
GlobalScope.launch { /* Evitar GlobalScope */ }

// Bien: Usar concurrencia estructurada
coroutineScope {
    launch { /* Correctamente delimitado */ }
}

// Mal: Funciones de scope profundamente anidadas
user?.let { u ->
    u.address?.let { a ->
        a.city?.let { c -> process(c) }
    }
}

// Bien: Cadena null-safe directa
user?.address?.city?.let { process(it) }

Recuerda: El código Kotlin debe ser conciso pero legible. Aprovecha el sistema de tipos para seguridad, prefiere la inmutabilidad y usa coroutines para concurrencia. Ante la duda, deja que el compilador te ayude.

© affaan-m, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in docs/es/skills/kotlin-patterns of affaan-m/ECC.

Open the folder on GitHubat commit ef648e0

Compare with similar skills

Kotlin Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Kotlin Patterns compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Kotlin Patterns this skillaffaan-m/ECC276k—~4.8kAutomated safety check: PassMIT
Compose Multiplatform Patternsmonta-app/ocpp-emulator1805 repos~2kAutomated safety check: PassApache-2.0
Kotlin Patternsgetknit/knit1325 repos~4.7kAutomated safety check: PassGPL-3.0
Summoncodeyousef/summon167—~1.1kAutomated safety check: PassApache-2.0
Add JSON Schemayontrack/yontrack102—~883Automated safety check: PassMIT
Add Ktnip Parameter Strategyvendelieu/telegram-bot249—~613Automated safety check: PassApache-2.0

Similar skills

  • Compose Multiplatform Patterns

    monta-app/ocpp-emulator

    Compose Multiplatform and Jetpack Compose patterns for KMP projects — state management, navigation, theming, performance, and platform-specific UI.

    180 GitHub starsUsed in 5 repos~2k tokens
    MobileAuto-check passed
  • Kotlin Patterns

    getknit/knit

    Idiomatic Kotlin patterns, best practices, and conventions for building robust, efficient, and maintainable Kotlin applications with coroutines, null safety, and DSL builders.

    132 GitHub starsUsed in 5 repos~4.7k tokens
    MobileAuto-check passed
  • Summon

    codeyousef/summon

    A skill your agent uses when developing applications with the Summon Kotlin Multiplatform UI framework.

    167 GitHub stars~1.1k tokensUpdated yesterday
    MobileAuto-check passed
  • Add JSON Schema

    yontrack/yontrack

    Add a new downloadable JSON schema to the Resources page — Kotlin provider class only, auto-discovered by Spring.

    102 GitHub stars~883 tokensUpdated today
    MobileAuto-check passed
  • Add Ktnip Parameter Strategy

    vendelieu/telegram-bot

    Adds a new parameter resolution strategy to the ktnip KSP processor.

    249 GitHub stars~613 tokensUpdated 5 days ago
    MobileAuto-check passed
  • CometChat Android v5 Headless SDK

    cometchat/cometchat-skills

    Builds chat on Android with your own UI against the headless CometChat Chat SDK v5, covering install, Jetifier conflicts, credentials and init-before-login ordering.

    131 GitHub stars~4k tokensUpdated 4 days ago
    MobileAuto-check passed

More from affaan-m/ECC

All 673 skills in this repo
  • Skill Stocktake

    affaan-m/ECC

    Audits your installed Claude skills and commands for quality, with a quick mode for recently changed skills and a full mode that evaluates all of them through subagents.

    276k GitHub starsUsed in 5 repos~1.9k tokens
    Auto-check passed
  • Ingests, indexes, searches, edits and monitors video, audio and live streams through the VideoDB Python SDK, returning stream links, clips and timestamps.

    276k GitHub starsUsed in 3 repos~3.5k tokens
    Auto-check: notes
  • Rules Distillation

    affaan-m/ECC

    Scans installed skills for principles that recur across them and proposes rule-file changes: append, revise, add a section, create a file or leave as covered.

    276k GitHub starsUsed in 2 repos~2.3k tokens
    Auto-check passed
  • Builds DRAFT counterparty agreements from one markdown template and a small JSON spec per party, with clauses picked by the party's role.

    276k GitHub stars~2.9k tokensUpdated 4 days ago
    Auto-check passed
  • Measures whether agents actually follow a skill, rule or agent definition by generating scenarios at three strictness levels and scoring tool-call traces.

    276k GitHub starsUsed in 1 repo~623 tokens
    Auto-check passed
  • Instinct-based learning system that observes sessions via hooks, creates atomic instincts with confidence scoring, and evolves them into skills/commands/agents.

    276k GitHub stars~3.5k tokensUpdated 4 days ago
    Auto-check passed

Works with

Categories

Questions about Kotlin Patterns

What does Kotlin Patterns do?

Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL. Kotlin Patterns is an agent skill from affaan-m/ECC. Patrones idiomáticos de Kotlin, buenas prácticas y convenciones para construir aplicaciones Kotlin robustas, eficientes y mantenibles con coroutines, null safety y builders de DSL.

When should I use Kotlin Patterns?

Kotlin Patterns fits situations like: tasks that involve Android development.

How do I install Kotlin Patterns in Claude Code?

Run `npx skills add affaan-m/ECC --skill kotlin-patterns -a claude-code`. Or copy the skill folder (docs/es/skills/kotlin-patterns in affaan-m/ECC) into .claude/skills/kotlin-patterns in your project. Claude Code loads it when a task matches its description.

How do I install Kotlin Patterns in Codex?

Run `npx skills add affaan-m/ECC --skill kotlin-patterns -a codex`. Or copy the skill folder (docs/es/skills/kotlin-patterns in affaan-m/ECC) into .agents/skills/kotlin-patterns in your project. Codex loads it when a task matches its description.

Can I use Kotlin Patterns in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add affaan-m/ECC --skill kotlin-patterns -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/kotlin-patterns, .gemini/skills/kotlin-patterns, .github/skills/kotlin-patterns and .opencode/skills/kotlin-patterns in your project.

What does Kotlin Patterns need to run?

SKILL.md names no scripts, command-line tools or credentials: Kotlin Patterns is instructions for the agent only.

Does Kotlin Patterns access the network?

SKILL.md names 1 domain. In commands or code: kotlinlang.org; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Kotlin Patterns safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Kotlin Patterns use?

Kotlin Patterns is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Kotlin Patterns use?

About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Kotlin Patterns?

Skills that share tags, products or a category with Kotlin Patterns: Compose Multiplatform Patterns (monta-app/ocpp-emulator, 180 stars), Kotlin Patterns (getknit/knit, 132 stars), Summon (codeyousef/summon, 167 stars) and Add JSON Schema (yontrack/yontrack, 102 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Kotlin Patterns?

affaan-m (a GitHub user) maintains it in affaan-m/ECC, which has 275,546 GitHub stars. The repository holds 673 skills in this directory. The repository was last updated on October 5, 2026.

Source: affaan-m/ECC on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.