account-state
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
Android shim in `amethyst/`: MainActivity, AndroidManifest/intent filters, :napplet process, play/fdroid flavors, R8 + tools/r8-verify, permissions, Intent/Context ports. Use when editing amethyst/. NOT for screens/navigation (compose-expert).
Claude Code
$ npx -y skills add vitorpamplona/amethyst --skill android-expert --agent claude-code
Codex
$ npx skills add vitorpamplona/amethyst --skill android-expert -a codex -y
Cursor
$ npx skills add vitorpamplona/amethyst --skill android-expert -a cursor -y
Gemini CLI
$ npx skills add vitorpamplona/amethyst --skill android-expert -a gemini-cli -y
GitHub Copilot
$ npx skills add vitorpamplona/amethyst --skill android-expert -a github-copilot -y
OpenCode
$ npx skills add vitorpamplona/amethyst --skill android-expert -a opencode -y
Windsurf
$ npx skills add vitorpamplona/amethyst --skill android-expert -a windsurf -y
name: android-expert description: Android shim in `amethyst/`: MainActivity, AndroidManifest/intent filters, :napplet process, play/fdroid flavors, R8 + tools/r8-verify, permissions, Intent/Context ports. Use when editing amethyst/. NOT for screens/navigation (compose-expert).
`amethyst/` is shrinking to an Android shim: entry points, services, system integrations and the actuals of shared ports. Screens, the nav host and the bar / rail / drawer are shared UI in `commonsUI` (see `compose-expert`). A new screen goes there even when only Android shows it.
Source root: `amethyst/src/main/java/com/vitorpamplona/amethyst/` (an Android app module, not KMP: there is no `androidMain` here). Flavor code is in `amethyst/src/play/` and `amethyst/src/fdroid/`.
process only.
`onCreate` calls `enableEdgeToEdge()` and sets `AmethystTheme { ... AmethystApp(Amethyst.instance.sessionManager, AndroidAppRoot) }`. Everything from there down is shared UI.
shared shell port (`commonsUI/.../commons/ui/app/AppRoot.kt`). It registers the Android-only destinations (`androidDestinations` in `ui/navigation/AppNavigation.kt`) and runs `NavigateIfIntentRequested`.
(`AppServices`, the interface is in `commons/.../commons/service/AppServices.kt`): the other two ports the shared UI calls.
`ui/screen/loggedIn/nests/room/activity/NestActivity`, `service/playback/pip/PipVideoActivity`, the signer / napplet consent activities, and `HealthConnectRationaleActivity`.
The app runs in **main** and **`:napplet`**. Read `references/two-processes.md` before touching `Amethyst.kt`, an Application callback, or anything under `napplet/`. The sandbox activities and services (`NappletHostActivity`, `NappletBrowserActivity`, `NappletHostService`, `NappletBrowserService`) live in the `:nappletHost` module and are declared with `android:process=":napplet"`. The broker side (`napplet/NappletBrokerService.kt`, `NappletLaunchRegistry`, consent) stays in `amethyst/`.
`amethyst/src/main/AndroidManifest.xml`; each flavor merges its own `AndroidManifest.xml`.
wallet-connect schemes and several `https` hosts, and `SEND`.
`ShareAsPictureAlias`, `ShareAsShortVideoAlias`, `ShareAsVideoAlias`, `ShareAsHighlightAlias`, `ScanQrCodeAlias`). Which one the user picked is visible only in the launching intent's component class name, which `ShareIntentRouting.targetOf` in `commonsUI/.../commons/ui/navigation/ShareIntentRouting.kt` maps to a `ShareTarget`. Renaming an alias without updating its constant there silently routes the share to New Post. Adding a target means an alias, a constant, and a `ShareTarget` entry.
`SEND_MULTIPLE` / NFC intents into `nav.newStack(...)` calls.
`NotificationRelayService`, ...) read their notification strings synchronously, which is the one case where a string may stay in Android `res/`. See `AGENTS.md` "Strings" and `amethyst/src/main/res/AGENTS.md`.
Shared composables never touch `Context` directly. Use the existing shape: a small interface plus an `expect fun rememberX()` in `commonsUI` `commonMain`, with the Android actual in `commonsUI/src/androidMain`. Examples: `TextSharer` / `rememberTextSharer()` (the actual builds the `ACTION_SEND` chooser from `LocalContext`), `FileSharer`, `PlatformBackHandler`, `HideFromScreenshots`, `rememberCoarseLocationPermission(): PlatformPermission` (the actual wraps Accompanist's `rememberPermissionState`). When the behavior needs app-only state (an Activity class, a service, `Amethyst.instance`), put a member on `AppPlatform` / `AppServices` and implement it in `AndroidAppPlatform` / `AndroidAppServices`, as `openNestRoom` does with `NestActivity.launch`.
`amethyst/build.gradle.kts` declares `flavorDimensions += "channel"` with `play` (default) and `fdroid`. They differ in `BuildConfig.IS_CASTING_AVAILABLE` and in their dependencies:
prompt / image description), Play Services Cast, androidx AppFunctions.
Classes that `main` calls exist in **both** `src/play/java/...` and `src/fdroid/java/...` with the same name and signature (`PushNotificationUtils`, `SelectNotificationProvider`, `LanguageTranslatorService`, `WritingAssistantFactory`, `ChromecastCaster`, `TermsGate`, ...). Add or change one side and the other flavor stops compiling. Build both when you touch them. Play-only code (`appfunctions/AmethystAppFunctions.kt`, `AmethystCastOptionsProvider`) needs no twin as long as `main` never references it. Build types: `debug` (`.debug` suffix), `release`, and `benchmark` (release config, debug-signed, profileable).
Gradle details beyond this (catalog, versions, KMP source sets) belong to `kotlin-multiplatform`.
`service/images/ImageLoaderSetup.kt` installs the singleton Coil loader. It is called from `AppModules.setImageLoader()` with a `callFactory` built from `roleBasedHttpClientBuilder.okHttpClientForImage`, so Tor routing and the "image" traffic tag apply. Cha
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
amy CLI in cli/: adding an `amy <verb>` command, Main.kt dispatch, Output.emit/--json contract, exit codes 0/1/2/124, ~/.amy…
NostrSigner in Amethyst: NostrSignerInternal (local key), NostrSignerRemote (NIP-46 bunker), NostrSignerExternal (NIP-55 Android…
Shared Compose UI in `commonsUI/`: screens, components, the nav shell (`ScreenLayoutSpec`, `AppShellLayout`, Navigation 3 back…
Desktop JVM shim in desktopApp/: AmethystDesktop window, DesktopMenuBar, platform ports, OS keyring; :desktopApp:run, packaging.…
Translation audits of `strings.xml` locales in `commonsUI/.../composeResources` and `amethyst/src/main/res`: missing or…
Decompile Android APK, XAPK, JAR, and AAR files using jadx or Fernflower/Vineflower. Reverse engineer Android apps, extract HTTP…