Files
amethyst/.claude/skills/gradle-expert/references/dependency-graph.md
T
Claude 2e8bf0d45d build: remove unused :ammolite module
The :ammolite module contained no production Kotlin/Java sources (just
a manifest, build.gradle, and proguard stubs) and no module in the
codebase imports com.vitorpamplona.ammolite.*.

Removes:
- ammolite/ directory (5 files)
- :ammolite project include in settings.gradle
- implementation project(':ammolite') from :amethyst
- androidTestImplementation project(':ammolite') from :benchmark
- :ammolite:testDebugUnitTest from CI workflow and pre-push hook
- -keep class com.vitorpamplona.ammolite.** rules from
  :amethyst, :commons, and :desktopApp proguard files
- Stale references in CONTRIBUTING.md, CLAUDE.md, and the
  gradle-expert skill dependency-graph doc

Small build-graph win: one fewer module to configure, compile, lint,
and spotless-check on every build, and one fewer unit-test target in
both CI and the local pre-push hook.
2026-05-16 14:40:03 +00:00

8.5 KiB

Module Dependency Graph

Visual Hierarchy

┌─────────────────────────────────────────────────────────┐
│                    Root Project                          │
│                     (Amethyst)                           │
└─────────────────────────────────────────────────────────┘
                          │
         ┌────────────────┼────────────────┐
         │                │                │
         ▼                ▼                ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│  :amethyst  │  │ :desktopApp │  │ :benchmark  │
│  (Android)  │  │   (JVM)     │  │  (Android)  │
└─────────────┘  └─────────────┘  └─────────────┘
       │                │                │
       │                │                │
       └────────────────┼────────────────┘
                        │
                        ▼
                ┌─────────────┐
                │  :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, :nestsClient
  • 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

Dependency Flow Patterns

Desktop Build Chain

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

Android Build Chain

:amethyst → :commons (androidMain) → :quartz (androidMain)
                                           ↓
                                     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)