Files
amethyst/.claude/skills/gradle-expert/references/dependency-graph.md
T

8.8 KiB

Module Dependency Graph

Visual Hierarchy

┌─────────────────────────────────────────────────────────┐
│                    Root Project                          │
│                     (Amethyst)                           │
└─────────────────────────────────────────────────────────┘
                          │
         ┌────────────────┼────────────────┬────────────┐
         │                │                │            │
         ▼                ▼                ▼            ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌──────────┐
│  :amethyst  │  │ :desktopApp │  │ :benchmark  │  │:ammolite │
│  (Android)  │  │   (JVM)     │  │  (Android)  │  │ (Support)│
└─────────────┘  └─────────────┘  └─────────────┘  └──────────┘
       │                │                │
       │                │                │
       └────────────────┼────────────────┘
                        │
                        ▼
                ┌─────────────┐
                │  :commons   │
                │  (KMP UI)   │
                │             │
                │ jvmAndroid  │
                │  /      \   │
                │ jvm   android│
                └─────────────┘
                        │
                        │
                        ▼
                ┌─────────────┐
                │  :quartz    │
                │(KMP Library)│
                │             │
                │ commonMain  │
                │     │       │
                │ jvmAndroid  │
                │  /  |  \    │
                │jvm and ios  │
                └─────────────┘

Module Details

:quartz (KMP Nostr Library)

Type: Kotlin Multiplatform Library Targets: JVM, Android, iOS (iosArm64, iosSimulatorArm64) Dependencies:

  • External: secp256k1, jackson, okhttp, kotlinx.coroutines, kotlinx.collections.immutable
  • Source sets: commonMain → jvmAndroid → {androidMain, jvmMain}, iosMain

Role: Core Nostr protocol implementation, shared across all platforms

:commons (Shared UI Components)

Type: Kotlin Multiplatform Library Targets: JVM, Android Dependencies:

  • Module: :quartz
  • External: Compose Multiplatform, Material3, kotlinx.collections.immutable
  • Source sets: commonMain → jvmAndroid → {androidMain, jvmMain}

Role: Shared Compose UI components for Desktop and Android

:desktopApp (Desktop Application)

Type: JVM Application Targets: JVM (Desktop) Dependencies:

  • Modules: :commons, :quartz
  • External: Compose Desktop, kotlinx.coroutines.swing

Role: Desktop-specific navigation, layouts, and entry point

:amethyst (Android Application)

Type: Android Application Targets: Android Dependencies:

  • Modules: :commons, :quartz, :ammolite
  • External: Android SDK, AndroidX, Firebase, Tor

Role: Android-specific navigation, layouts, and entry point

:benchmark (Android Benchmark)

Type: Android Library Targets: Android Dependencies:

  • Modules: :commons, :quartz
  • External: AndroidX Benchmark

Role: Performance benchmarking for Android builds

:ammolite (Support Module)

Type: Android Library Targets: Android Dependencies: Android-specific utilities

Role: Android support utilities for amethyst

Dependency Flow Patterns

Desktop Build Chain

:desktopApp → :commons (jvmMain) → :quartz (jvmMain)
                                         ↓
                                   jvmAndroid
                                         ↓
                                   commonMain

Android Build Chain

:amethyst → :commons (androidMain) → :quartz (androidMain)
    ↓                                      ↓
:ammolite                            jvmAndroid
                                         ↓
                                   commonMain

Source Set Dependencies

:quartz Source Sets

commonMain (base)
    ├─ jvmAndroid (shared JVM code)
    │   ├─ androidMain (Android platform)
    │   └─ jvmMain (Desktop platform)
    └─ iosMain (iOS platform)
        ├─ iosArm64Main
        └─ iosSimulatorArm64Main

Key Dependencies per Source Set:

  • commonMain: secp256k1-kmp, kotlinx.coroutines, collection, immutable collections
  • jvmAndroid: jackson, okhttp, url-detector, rfc3986
  • androidMain: secp256k1-kmp-jni-android, lazysodium-android, jna (aar)
  • jvmMain: secp256k1-kmp-jni-jvm, lazysodium-java, jna (jar)

:commons Source Sets

commonMain (base UI)
    └─ jvmAndroid (shared JVM UI)
        ├─ androidMain (Android UI utilities)
        └─ jvmMain (Desktop UI utilities)

Key Dependencies per Source Set:

  • commonMain: Compose Multiplatform, Material3, :quartz
  • jvmAndroid: url-detector
  • androidMain: AndroidX Compose tooling
  • jvmMain: Compose Desktop

Critical Dependency Patterns

1. secp256k1 Variants

// commonMain - API only
api(libs.secp256k1.kmp.common)

// androidMain - JNI Android
api(libs.secp256k1.kmp.jni.android)

// jvmMain - JNI JVM
implementation(libs.secp256k1.kmp.jni.jvm)

Why: Different JNI bindings for Android vs Desktop JVM

2. JNA Variants (for LibSodium)

// androidMain
implementation("com.goterl:lazysodium-android:5.2.0@aar")
implementation("net.java.dev.jna:jna:5.18.1@aar")

// jvmMain
implementation(libs.lazysodium.java)
implementation(libs.jna)  // JAR variant

Why: Android needs AAR packaging, JVM needs JAR

3. Compose Alignment

// commons/build.gradle.kts
implementation(compose.ui)              // Compose Multiplatform BOM
implementation(compose.material3)

// Version catalog alignment
composeMultiplatform = "1.9.3"
composeBom = "2025.12.01"  // AndroidX Compose

Why: Two Compose ecosystems (Multiplatform + AndroidX) must align

Dependency Configuration Types

API vs Implementation

Use api when:

  • Dependency types appear in module's public API
  • Used in expect/actual declarations visible to consumers
  • Example: secp256k1-kmp-common in quartz (public types)

Use implementation when:

  • Internal implementation detail
  • Not exposed to module consumers
  • Example: okhttp in quartz (internal network client)

Example from quartz

// Public API - exposed to consumers
api(libs.secp256k1.kmp.common)
api(libs.jackson.module.kotlin)  // Event serialization public

// Internal implementation
implementation(libs.okhttp)
implementation(libs.kotlinx.coroutines.core)

Transitive Dependency Impact

When :desktopApp depends on :commons

  • Gets :quartz transitively (via :commons)
  • Gets secp256k1-kmp-jvm transitively (via :quartz jvmMain)
  • Does NOT get Android-specific dependencies (scoped to androidMain)

When :amethyst depends on :commons

  • Gets :quartz transitively (via :commons)
  • Gets secp256k1-kmp-jni-android transitively (via :quartz androidMain)
  • Does NOT get JVM/Desktop-specific dependencies (scoped to jvmMain)

Verifying Dependencies

Check Module Dependencies

./gradlew :desktopApp:dependencies
./gradlew :amethyst:dependencies

Check Specific Library

./gradlew dependencyInsight --dependency secp256k1
./gradlew dependencyInsight --dependency compose-ui

Visualize with Build Scan

./gradlew :desktopApp:dependencies --scan
# Opens interactive dependency graph in browser

Common Dependency Issues

Issue 1: Wrong secp256k1 Variant in Desktop

Symptom: UnsatisfiedLinkError: no secp256k1jni in java.library.path Cause: Desktop using Android JNI variant Fix: Ensure jvmMain uses secp256k1-kmp-jni-jvm

Issue 2: Compose Version Mismatch

Symptom: IllegalStateException: Version mismatch Cause: Compose Multiplatform plugin vs runtime version mismatch Fix: Align composeMultiplatform version in libs.versions.toml with Kotlin plugin

Issue 3: Duplicate JNA Classes

Symptom: DuplicateClassException: com.sun.jna.Native Cause: Both JAR and AAR JNA variants in classpath Fix: Use AAR (@aar) in androidMain, JAR in jvmMain (never in shared source sets)