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
Stats
1,600
Stars
221
Forks
Active
Maintenance
Kotlin
Language
MIT
License
41m ago
Last commit
3y ago
Created

Repo: vitorpamplona/amethyst

Other skills on amethyst.