Skip to content
Development
Skill

/kotlin-expert

Advanced Kotlin patterns for AmethystMultiplatform. Flow state management (StateFlow/SharedFlow), sealed hierarchies (classes vs interfaces), immutability (@Immutable, data classes), DSL builders (type-safe fluent APIs), inline functions (reified generics, performance). Use when

From plugin
amethyst
1.6k30 skills3 commands
Install
$ npx -y skills add vitorpamplona/amethyst --skill kotlin-expert --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/kotlin-expert

Context preview

The summary Claude sees to decide when to auto-load this skill.

Advanced Kotlin patterns for AmethystMultiplatform. Flow state management (StateFlow/SharedFlow), sealed hierarchies (classes vs interfaces), immutability (@Immutable, data classes), DSL builders (type-safe fluent APIs), inline functions (reified generics, performance). Use when

SKILL.md

kotlin-expert.SKILL.md
name: kotlin-expert
description: Advanced Kotlin patterns for AmethystMultiplatform. Flow state management (StateFlow/SharedFlow), sealed hierarchies (classes vs interfaces), immutability (@Immutable, data classes), DSL builders (type-safe fluent APIs), inline functions (reified generics, performance). Use when working with: (1) State management patterns (StateFlow/SharedFlow/MutableStateFlow), (2) Sealed classes or sealed interfaces, (3) @Immutable annotations for Compose, (4) DSL builders with lambda receivers, (5) inline/reified functions, (6) Kotlin performance optimization. Complements kotlin-coroutines agent (async patterns) - this skill focuses on Amethyst-specific Kotlin idioms.

Kotlin Expert

Advanced Kotlin patterns for AmethystMultiplatform. Covers Flow state management, sealed hierarchies, immutability, DSL builders, and inline functions with real codebase examples.

Mental Model

**Kotlin in Amethyst:**

State Management (Hot Flows)
    ├── StateFlow<T>           # Single value, always has value, replays to new subscribers
    ├── SharedFlow<T>          # Event stream, configurable replay, multiple subscribers
    └── MutableStateFlow<T>    # Private mutable, public via .asStateFlow()

Type Safety (Sealed Hierarchies)
    ├── sealed class           # State variants with data (AccountState.LoggedIn/LoggedOut)
    └── sealed interface       # Generic result types (SignerResult<T>)

Compose Performance (@Immutable)
    ├── @Immutable             # 173+ event classes - prevents recomposition
    └── data class             # Structural equality, copy(), immutable by convention

DSL Patterns
    ├── Builder classes        # Fluent APIs (TagArrayBuilder)
    ├── Lambda receivers       # inline fun tagArray { ... }
    └── Method chaining        # return this

Performance
    ├── inline fun             # Eliminate lambda overhead
    ├── reified type params    # Runtime type info (OptimizedJsonMapper)
    └── value class            # Zero-cost wrappers (NOT USED yet in Amethyst)

**Delegation:**

  • **kotlin-coroutines agent**: Deep async (structured concurrency, channels, operators)
  • **kotlin-multiplatform skill**: expect/actual, source sets
  • **This skill**: Amethyst Kotlin idioms, state patterns, type safety

---

1. Flow State Management

StateFlow: State that Changes

**Mental model:** StateFlow is a "hot" observable state holder. Always has a value, new collectors immediately get current state.

**Amethyst pattern:**

// AccountManager.kt:48-50
class AccountManager {
    private val _accountState = MutableStateFlow<AccountState>(AccountState.LoggedOut)
    val accountState: StateFlow<AccountState> = _accountState.asStateFlow()

    fun login(key: String) {
        _accountState.value = AccountState.LoggedIn(...)
    }
}

**Key principles:** 1. **Private mutable, public immutable**: `_accountState` (MutableStateFlow) private, `accountState` (StateFlow) public 2. **Always has value**: Initial value required (`LoggedOut`) 3. **Single value**: Replays ONE most recent value to new subscribers 4. **Hot**: Stays in memory, all collectors share same instance

**See:** AccountManager.kt:48-50, RelayConnectionManager.kt:49-52

SharedFlow: Event Streams

**Mental model:** SharedFlow is a "hot" broadcast stream for events. Configurable replay buffer, doesn't require initial value.

**Amethyst pattern:**

// RelayConnectionManager.kt:52-53
val connectedRelays: StateFlow<Set<NormalizedRelayUrl>> = client.connectedRelaysFlow()
val availableRelays: StateFlow<Set<NormalizedRelayUrl>> = client.availableRelaysFlow()

**When to use StateFlow vs SharedFlow:**

| Scenario | Use StateFlow | Use SharedFlow | |----------|---------------|----------------| | **UI state** | ✅ Current screen data, login status | ❌ | | **One-time events** | ❌ | ✅ Navigation, snackbars, toasts | | **Always has value** | ✅ | ❌ Optional | | **Replay count** | 1 (latest only) | Configurable (0, 1, n) | | **Backpressure** | Conflates (drops old) | Configurable buffer |

**Best practice:**

// State: Use StateFlow
private val _uiState = MutableStateFlow(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()

// Events: Use SharedFlow
private val _navigationEvents = MutableSharedFlow<NavEvent>(replay = 0)
val navigationEvents: SharedFlow<NavEvent> = _navigationEvents.asSharedFlow()

Flow Anti-Patterns

❌ **Exposing mutable state:**

val accountState: MutableStateFlow<AccountState>  // BAD: Can be mutated externally

✅ **Expose immutable:**

val accountState: StateFlow<AccountState> = _accountState.asStateFlow()  // GOOD

---

❌ **SharedFlow for state:**

val loginState = MutableSharedFlow<LoginState>()  // BAD: State might get lost

✅ **StateFlow for state:**

val loginState = MutableStateFlow(LoginState.LoggedOut)  // GOOD: Always has value

**See:** `references/flow-patterns.md` for comprehensive examples.

---

2. Sealed Hierarchies

Sealed Classes: State Variants

**Mental model:** Sealed classes represent a closed set of variants that share common data/behavior.

**Amethyst pattern:**

// AccountManager.kt:36-46
sealed class AccountState {
    data object LoggedOut : AccountState()

    data class LoggedIn(
        val signer: NostrSigner,
        val pubKeyHex: String,
        val npub: String,
        val nsec: String?,
        val isReadOnly: Boolean
    ) : AccountState()
}

// Usage
when (state) {
    is AccountState.LoggedOut -> showLogin()
    is AccountState.LoggedIn -> showFeed(state.pubKeyHex)
}  // Exhaustive - compiler enforces all cases

**Key principles:** 1. **Closed hierarchy**: All subclasses known at compile-time 2. **Exhaustive when**: Compiler ensures all cases handled 3. **Shared data**: Sealed class can hold common properties 4. **Single inheritance**: Subclass can't extend another class

**When to use:**

  • Modeling UI states (Loading, S
Read more
Ships withamethyst

Nostr client for Android

Get the whole plugin

Other skills on amethyst.