This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
OtakuWorld is a multi-app Android project with three main consumer apps: MangaWorld (manga
reader), AnimeWorld (anime streamer), and NovelWorld (novel reader). They share a large
common codebase and are actively being migrated to Kotlin Multiplatform (KMP) to eventually support
JVM/Desktop (via Compose Multiplatform). A Desktop build of MangaWorld (mangaworld:desktop)
already exists.
Apps contain no bundled sources — sources are loaded as external plugins/APKs at runtime via the extension loader system.
# Build a specific app (use noFirebase flavor for local builds — no google-services.json needed)
./gradlew :mangaworld:assembleNoFirebaseDebug
./gradlew :animeworld:assembleNoFirebaseDebug
./gradlew :novelworld:assembleNoFirebaseDebug
# Build the desktop app
./gradlew :mangaworld:desktop:run
# Run all tests
./gradlew test
# Run tests for a specific module
./gradlew :UIViews:test
./gradlew :kmpuiviews:test
# Run a single test class
./gradlew :UIViews:test --tests "com.programmersbox.uiviews.ExampleUnitTest"
# Clean build
./gradlew cleanImportant: Always use the noFirebase build variant for local development. This is set as the
default (isDefault = true). The full flavor requires google-services.json secrets.
Three product flavors (dimension version):
noFirebase— default for local dev, no Firebase dependency, appId suffix.noFirebasenoCloudFirebase— Firebase crashlytics only, no cloud syncfull— complete Firebase integration
Build types: debug, release, beta (beta = non-debuggable debug).
Flavor-specific Firebase utility implementations live in
sharedutils/src/{noFirebase,noCloudFirebase,full}/java/.
| Module | Purpose |
|---|---|
kmpmodels |
KMP data models (KmpItemModel, KmpInfoModel, KmpChapterModel, KmpStorage, KmpApiService) — the source plugin contract |
kmpuiviews |
KMP shared UI, ViewModels, repositories, DI modules, navigation (targets: Android, JVM, iOS) |
UIViews |
Android-only shared UI layer extending kmpuiviews; BaseMainActivity, GenericInfo interface |
favoritesdatabase |
KMP Room database for favorites, history, custom lists, recommendations |
datastore |
KMP DataStore/protobuf settings handling |
datastore:mangasettings |
Manga-specific protobuf settings |
sharedutils |
Firebase utilities with flavor-specific implementations |
source_utilities |
NetworkHelper for HTTP source plugins |
mangaworld |
MangaWorld Android app, GenericManga implementation |
mangaworld:shared |
Shared manga reader UI (KMP) |
mangaworld:desktop |
JVM/Desktop Compose app for MangaWorld |
animeworld |
AnimeWorld Android app |
novelworld |
NovelWorld Android app |
novelworld:shared |
Shared novel reader UI (KMP) |
app |
OtakuWorld companion/manager app |
This is the core extensibility pattern. Sources are not bundled — they are loaded as external plugins at runtime.
KmpApiService(kmpmodels) — interface all sources implement. Key methods:recent(),allList(),itemInfo(),chapterInfo(),search()KmpItemModel/KmpInfoModel/KmpChapterModel— data model hierarchy flowing from source to UIOtakuWorldCatalog— fetches the remote extension index fromOtakuWorldSourcesrepo and providesKmpRemoteSourcesfor in-app installationKmpExternalApiServicesCatalog/KmpSources— catalog abstraction for extension marketplace
Sources compatible with Mihon (Tachiyomi forks) work with MangaWorld after the bridge is installed. Aniyomi-compatible sources work with AnimeWorld similarly.
Each app supplies a GenericInfo implementation that customizes app-specific behavior injected via
Koin:
KmpGenericInfo(interface,kmpuiviews/commonMain) — KMP contract:chapterOnClick,downloadChapter, list composables, nav setup hooksPlatformGenericInfo(expect/actual per platform) — platform-specific extension pointGenericInfo(UIViews, Android) — extendsPlatformGenericInfo, provides account UI defaults- App-specific class e.g.
GenericManga(mangaworld) — final implementation registered in Koin:singleOf(::GenericManga) { bindsGenericInfo() }
Uses Navigation3 (AndroidX). Navigation graph is built in entryGraph() (
kmpuiviews/commonMain/.../navigation/Nav3Graph.kt). Screens are NavKey data objects/classes
defined in Screen.kt.
KmpGenericInfo has globalNav3Setup() and settingsNav3Setup() context functions that let each
app inject additional nav entries into the shared graph.
NavigationActions is a Koin singleton that abstracts navigation calls — use it instead of directly
accessing the nav controller.
Koin is used throughout. Module registration follows this pattern:
kmpuiviewsprovides base KMP modules (AppModule.kt,NavigationModule.kt, platformRepositoryModule,ViewModelModule)- Each app module adds its own
appModule(e.g.,mangaworld/GenericManga.kt) UIViewsprovides Android-specific additions (di/AppModule.kt,di/ViewModelModule.kt)
kmpuiviews and kmpmodels use this hierarchy:
commonMain— shared logic and interfacesandroidMain— Android implementationsjvmMain— Desktop/JVM implementationsiosMain— iOS stubsdeviceMain/httpMain— intermediate groupings defined inapplyDefaultHierarchyTemplate
Custom Gradle plugins in buildSrc/src/main/kotlin/plugins/:
otaku-application→AndroidApplicationPlugin— Android app with Firebase, Compose, product flavorsotaku-library→AndroidLibraryPlugin— Android libraryotaku-multiplatform→MultiplatformLibraryPlugin— KMP library
Apply with backtick syntax in build.gradle.kts: `otaku-application`
AppInfo.kt in buildSrc holds compileSdk, minSdk, targetSdk, and version name constants.
- Compose Multiplatform — UI across Android and Desktop
- Koin — DI (with
koin-compose,koin-androidx-compose) - Kamel — KMP image loading
- Ktor — KMP HTTP client for source catalog
- Room (KMP) — favorites database
- Haze — blur/glassmorphism effects
- kotlinx.serialization — JSON throughout (replacing Gson in progress)
- Hotswan — Compose hot-reload support (Desktop dev)
gradle/libs.versions.toml is the primary version catalog. An additional androidx catalog is
imported from androidx.gradle:gradle-version-catalog. Reference libs as libs.* or androidx.*
in build files.
The project is mid-migration to KMP. Key in-progress changes (see Multiplatform Roadmap.md):
- Gson → kotlinx.serialization removal in progress
- ViewModels being moved from Android modules into
kmpuiviews UIViewsis the Android-specific layer that will shrink over time as more moves tokmpuiviews
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
Don't assume. Don't hide confusion. Surface tradeoffs.
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
Touch only what you must. Clean up only your own mess.
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
Define success criteria. Loop until verified.
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.