CLAUDE.md
packages/android/CLAUDE.mdCLAUDE.md
Quality
100/100
Scores the file, not the repository.Length
1,027 words
15 headings · 3 code blocksRepository
1.4k
— · pushed 1 days agoLast changed
3 days ago
First indexed 3 days ago.1# Android Package (Native Android App)23This package contains the native Android app for Nimbalyst. It mirrors the iOS native app architecture where practical: a pure native mobile shell with a single embedded web transcript view that renders the shared React transcript bundle.45## Overview67The Android app is:89- **Pure native Android** using Kotlin and Jetpack Compose10- **Room-backed** for local persistence11- **WebSocket-synced** with CollabV3 Durable Objects12- **End-to-end encrypted** using the same seed + user-derived key model as iOS13- **Transcript-rendered** through a single `WebView` that loads the bundled React transcript UI1415Voice agent features are intentionally out of scope for Android.1617## Package Structure1819```text20packages/android/21 app/22 src/main/java/com/nimbalyst/app/23 attachments/ # Image attachment preparation/compression24 auth/ # Auth callback parsing25 crypto/ # AES-GCM + PBKDF2 key derivation26 data/ # Room entities, DAOs, repository27 notifications/ # Android notification + FCM token plumbing28 pairing/ # QR payload parsing and persistent pairing state29 sync/ # WebSocket sync manager and wire protocol30 transcript/ # WebView host and JS bridge31 ui/ # Compose screens and app shell32 src/test/ # Unit tests33 src/transcript/ # Shared React transcript bundle entrypoint/assets34 scripts/ # Transcript asset sync helpers35```3637## Key Architecture Rules3839### Transcript4041- The transcript UI lives in `src/transcript/main.tsx` and is bundled into Android assets.42- `TranscriptWebView.kt` is the Android host. `TranscriptBridge.kt` is the only place JS bridge actions should be decoded and routed.43- Keep transcript behavior aligned with iOS unless Android-specific UX requires a different path.4445### Sync and Encryption4647- `SyncManager.kt` owns the device sync lifecycle, room joins, index updates, queued prompt handling, and session control messages.48- `CryptoManager.kt` must remain wire-compatible with iOS and desktop. Be cautious with any PBKDF2, AES-GCM, or payload format changes.49- User routing identity and crypto identity are distinct. Do not collapse them back into a single field.5051### Persistence5253- Room is the source of truth for local Android UI state.54- Prefer repository/DAO changes over screen-local state duplication.55- If you add persisted fields, update schema, migrations, and any seed/demo paths together.5657### Firebase / Notifications5859- `app/google-services.json` is local environment config. Do **not** commit it. The `google-services` Gradle plugin is applied conditionally (only when the file exists), so a build without it stays green and push stays inert.60- Client push registration lives in `notifications/NotificationManager.kt`.61- Server push delivery lives in the collab server, which is the sibling `nimbalyst-collab` repository, not this monorepo. Clone it next to this repo at `../nimbalyst-collab` (override with `COLLAB_SERVER_PATH`); collab tests are gated by `RUN_COLLAB_TESTS=1`. See `.github/workflows/ci.yml`. Android push changes usually require coordinated client + server work.6263## Development6465### Prerequisites6667- Android Studio Ladybug / AGP-compatible version for this project68- JDK 17 for Gradle builds. The project targets `JavaVersion.VERSION_17` and `jvmTarget = "17"`, and Temurin 17 matches CI. A non-17 JDK (e.g. GraalVM) can fail the AGP `jlink` step.69- Android SDK + emulator tooling70- Node.js 20+ for transcript bundle builds7172### Commands7374From the repository root the npm scripts wrap the Gradle tasks:7576```bash77npm run android:build:transcript # build the transcript bundle78npm run android:test:unit # ./gradlew :app:testDebugUnitTest79npm run android:assemble:debug # ./gradlew :app:assembleDebug80npm run android:assemble:release # ./gradlew :app:assembleRelease81npm run android:bundle:release # ./gradlew :app:bundleRelease82```8384To invoke Gradle directly, point `JAVA_HOME` at a Temurin 17 install (no hard-coded user path):8586```bash87cd packages/android88JAVA_HOME=/path/to/temurin-17 ./gradlew :app:assembleDebug89JAVA_HOME=/path/to/temurin-17 ./gradlew :app:testDebugUnitTest90```9192### Play Store screenshots and video9394`npm run android:screenshots` and `npm run android:walkthrough` drive an emulator against the debug-only screenshot mode in `app/src/debug/java/com/nimbalyst/app/screenshots/` (inert stub in `app/src/release/`). Never move that code into `src/main` — it seeds demo data and a fake paired state. See [ANDROID_MARKETING_SCREENSHOTS.md](../../docs/ANDROID_MARKETING_SCREENSHOTS.md).9596### Builds, signing, and CI9798- The `google-services` plugin is applied only when `app/google-services.json` is present, so a build without it succeeds and push stays inert until the file is added.99- CI can inject Firebase config from the optional `ANDROID_GOOGLE_SERVICES_JSON_BASE64` GitHub secret by decoding it to `app/google-services.json` before the Gradle build.100- The release `signingConfig` reads the keystore path and credentials from environment variables: `NIMBALYST_ANDROID_KEYSTORE`, `NIMBALYST_ANDROID_KEYSTORE_PASSWORD`, `NIMBALYST_ANDROID_KEY_ALIAS`, `NIMBALYST_ANDROID_KEY_PASSWORD`. When the keystore is absent the release build is simply unsigned. Minification stays off (signed is not the same as minified).101- CI builds both the APK and Play-ready AAB via `.github/workflows/android-build.yml`, which supplies the keystore and signing secrets to produce signed release artifacts when secrets are present. CI also decodes `google-services.json` from the `ANDROID_GOOGLE_SERVICES_JSON_BASE64` secret and fails a signed build if that secret is missing, so a signed AAB never ships with push silently inert.102- To build a signed release locally, run `npm run android:bundle:signed` (wraps `scripts/android-bundle-signed.sh`). It pulls all signing secrets from the 1Password item `Nimbalyst Android Signing` (Nimbalyst vault) at build time via `op read`: the upload keystore is fetched to a temp file deleted on exit, and passwords/alias are injected into the Gradle env only. Never commit a keystore — `*.jks`/`*.keystore` are gitignored.103104Open `packages/android/` in Android Studio, not the repo root.105106## Agent Guidance107108- Read the root `CLAUDE.md` before changing this package.109- Prefer following iOS behavior and naming when implementing cross-platform mobile features.110- Do not commit secrets or local machine config such as:111 - `app/google-services.json`112 - `local.properties`113 - build outputs114- If Android Studio reports AGP incompatibility, the correct fix is usually to update Android Studio rather than downgrade AGP/Kotlin.115- When changing sync protocol behavior, inspect the matching iOS code paths in this repo and the collab server code paths in the sibling `nimbalyst-collab` repository before editing.116- When changing transcript bridge behavior, update or add Android tests in `app/src/test/` where possible.117118## Important Files119120| File | Purpose |121| --- | --- |122| `app/src/main/java/com/nimbalyst/app/NimbalystApplication.kt` | App-level dependency setup and startup wiring |123| `app/src/main/java/com/nimbalyst/app/MainActivity.kt` | Activity entry point and deep-link handling |124| `app/src/main/java/com/nimbalyst/app/ui/NimbalystAndroidApp.kt` | Root Compose app shell and navigation |125| `app/src/main/java/com/nimbalyst/app/sync/SyncManager.kt` | Core mobile sync lifecycle and message handling |126| `app/src/main/java/com/nimbalyst/app/sync/SyncProtocol.kt` | Android wire protocol types |127| `app/src/main/java/com/nimbalyst/app/crypto/CryptoManager.kt` | Encryption and key derivation |128| `app/src/main/java/com/nimbalyst/app/data/NimbalystDatabase.kt` | Room database definition |129| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptWebView.kt` | WebView transcript host |130| `app/src/main/java/com/nimbalyst/app/transcript/TranscriptBridge.kt` | JS/native bridge handler |131| `src/transcript/main.tsx` | Shared transcript app entry point for Android |132
Also in nimbalyst/nimbalyst
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| nimbalyst/nimbalystCLAUDE.md · 1.4k | CLAUDE.md | setupbuildteststyle+11 | 84/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/electron/CLAUDE.md · 1.4k | CLAUDE.md | buildtestgitapi+2 | 83/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/ios/CLAUDE.md · 1.4k | CLAUDE.md | setupbuildtestarch+3 | 82/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/runtime/CLAUDE.md · 1.4k | CLAUDE.md | agent-behaviour | 44/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| dotCMS/corecore-web/CLAUDE.md · 950 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 3 days ago | |
| Adit-Jain-srm/NightmareNetCLAUDE.md · 45 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 3 days ago | |
| microsoft/playwrightCLAUDE.md · 94k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| filamentphp/filamentCLAUDE.md · 32k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| bagisto/bagistoCLAUDE.md · 28k | CLAUDE.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| dotCMS/coreCLAUDE.md · 950 | CLAUDE.md | setupbuildteststyle+7 | 99/100 | 3 days ago | |
| lollipopkit/flutter_server_boxCLAUDE.md · 8.3k | CLAUDE.md | buildteststylearch+2 | 98/100 | 3 days ago | |
| oven-sh/buntest/CLAUDE.md · 95k | CLAUDE.md | teststyletesting-strategydo-not | 97/100 | 3 days ago |
