3.3 KiB
3.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build Commands
./gradlew assembleDebug # Build debug APK
./gradlew assembleRelease # Build release APK (minified with R8)
./gradlew installDebug # Build and install on connected device/emulator
./gradlew clean # Clean build artifacts
No test suite exists yet. JDK 17 and Android SDK 35 are required.
Architecture
Wisp is a minimal Android Nostr client using Kotlin + Jetpack Compose (Material 3). MVVM with five layers:
UI (ui/screen/, ui/component/) → ViewModel (viewmodel/) → Repository (repo/) → Protocol (nostr/) → Relay (relay/)
All source lives under app/src/main/kotlin/com/wisp/app/.
Key Design Decisions
- No database — all state in-memory (LRU caches) or SharedPreferences/EncryptedSharedPreferences. Events re-fetched from relays each session.
- Flow-based reactivity — SharedFlow for relay events, StateFlow for UI state. No RxJava or LiveData.
- NIP objects — each NIP implemented as a Kotlin
objectwith static helpers (e.g.,Nip17.createGiftWrap()). New NIPs go inNipXX.kt. - Outbox/inbox relay model —
OutboxRouterroutes queries to author write relays and delivers to recipient read relays based on NIP-65. - Relay pool —
RelayPoolmanages persistent connections (max 30) and ephemeral connections (max 50) with automatic cleanup and cooldowns. - Encrypted key storage — private keys in EncryptedSharedPreferences (AES256-GCM), never plain SharedPreferences.
Protocol Layer (nostr/)
Each NIP is a standalone Kotlin object:
- Events created via
NostrEvent.create(privkey, pubkey, kind, content, tags) - Hex encoding:
ByteArray.toHex()/String.hexToByteArray()(extensions in Event.kt) - Condensed NIP reference docs at
.claude/nips/*.mdwith index at.claude/nips/README.md
Relay Layer (relay/)
Relay— single WebSocket connection via OkHttpRelayPool— connection pooling with persistent/ephemeral splitOutboxRouter— outbox/inbox routing per NIP-65RelayScoreBoard— tracks relay reliability and author coverageSubscriptionManager— REQ subscription lifecycle
Repository Layer (repo/)
EventRepository— LRU cache (5,000 events), profile parsing, reaction/repost/zap trackingContactRepository— follow list with SharedPreferences persistenceKeyRepository— EncryptedSharedPreferences for private keysDmRepository— conversation caching with ECDH key cache
Code Conventions
- Kotlin with Jetpack Compose — no XML layouts
Dispatchers.Defaultfor CPU-bound work,Dispatchers.IOfor networkStateFlowfor UI state,SharedFlowfor relay events- Default relays:
wss://relay.damus.io,wss://relay.primal.net - Navigation routes defined in
Navigation.kt
Crypto Stack
- Signing: secp256k1-kmp (Schnorr) with JNI Android bindings
- NIP-44 encryption: ECDH + HKDF + XChaCha20 + HMAC-SHA256 (Bouncy Castle)
- Key storage: Android Security Crypto (AES256-GCM)
ProGuard / R8
Release builds use R8 minification. Keep rules in app/proguard-rules.pro cover kotlinx.serialization, secp256k1 JNI, Bouncy Castle, OkHttp, Coil, Security Crypto, Media3, and ZXing.