* chore(agent): Add mandatory rules for AI agents covering Git, i18n, and formatting * Explicit path for strings resource Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Specify both strings.xml & plurals.xml Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Also exclude non-base local folders from i18n-kmk Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
11 KiB
Komikku – AI Agent Guide
Komikku is an Android manga reader (min SDK 26, target SDK 36, JVM 17 / Kotlin) forked from Mihon + TachiyomiSY. Stack: Jetpack Compose + Material3, Voyager navigation, SQLDelight, Injekt DI. applicationId: app.komikku.
Mandatory rules for AI agents
Read this section before every change. These rules override shortcuts (e.g. copying nearby MR imports or only running compileDebugKotlin).
Git
| Rule | Required behavior |
|---|---|
| Branch | Create a feature branch for the task (git checkout -b <type>/<short-description>). |
| Commit | OK on a feature branch when work is ready. Never commit directly to master / main unless the user explicitly asks. |
| Push | OK to push the current feature branch when work is ready. Never push to master / main unless the user explicitly asks. |
Before git push, confirm the current branch is not master or main (git branch --show-current).
Internationalization (strings)
| String kind | Module | Resource class | Base folder only |
|---|---|---|---|
| Komikku-only (new features, KMK UI, library-update errors, WebDAV, Discord, etc.) | i18n-kmk/ |
KMR |
i18n-kmk/src/commonMain/moko-resources/base/ |
| Shared Mihon / upstream behavior | i18n/ |
MR |
i18n/src/commonMain/moko-resources/base/ |
| TachiyomiSY-only | i18n-sy/ |
SYMR |
i18n-sy/src/commonMain/moko-resources/base/ |
Hard rules:
- Never add Komikku-specific strings to
i18n/ori18n-sy/. - Never edit non-
baselocalestrings.xmlorplurals.xmlfiles ini18n-kmk/,i18n/, ori18n-sy/(Weblate owns translations). - Import:
import tachiyomi.i18n.kmk.KMRfor Komikku strings. - If a change is inside
// KMK -->…// KMK <--or adds Komikku-only behavior, default toKMR+i18n-kmk.
Self-check before finishing: git diff must not add new <string name="…"> or <plurals name="…"> entries under non-base locales in i18n-kmk/src/, i18n/src/, or i18n-sy/src/.
Formatting & build verification
“Build passes” is not enough. After Kotlin/XML edits, run in this order before marking work complete:
./gradlew spotlessApply # fix formatting
./gradlew spotlessCheck # must pass (same as CI)
./gradlew assembleDebug # or :app:compileDebugKotlin for a faster compile-only check
- Do not skip
spotlessCheckwhen verifying changes. - If
spotlessCheckfails, runspotlessApplyand re-runspotlessCheck. - On Cloud VM, export
ANDROID_HOMEandJAVA_HOMEfirst (see Cursor Cloud).
Module layout
| Module | Purpose |
|---|---|
app/ |
UI (eu.kanade.*, exh/, mihon/), DI, workers, build variants |
domain/ |
Use cases in …/interactor/ (e.g. GetManga), models, repo interfaces |
data/ |
SQLDelight DB, *RepositoryImpl (tachiyomi.data.*) |
core:common/ |
Network (OkHttp), security, storage, shared utils |
core:archive/ |
CBZ/archive reading with optional encryption |
core-metadata/ |
Comic-info metadata parsing |
source-api/ / source-local/ |
Extension Source API + local source |
presentation-core/ |
Shared Compose components |
presentation-widget/ |
Home-screen Glance widget |
i18n/ |
Mihon strings → MR (moko-resources) |
i18n-kmk/ |
Komikku strings → KMR |
i18n-sy/ |
TachiyomiSY strings → SYMR |
flagkit/ |
Country-flag drawables |
telemetry/ |
Firebase/Crashlytics (noop unless -Pinclude-telemetry) |
macrobenchmark/ |
Macrobenchmark tests |
Dependency flow: app → domain → source-api; data implements domain repos.
Version catalogs: gradle/libs.versions.toml, kotlinx.versions.toml, androidx.versions.toml, compose.versions.toml, sy.versions.toml.
Architecture
DI – uy.kohesive.injekt (not Hilt). Register in AppModule.kt, DomainModule.kt, KMKDomainModule.kt, SYDomainModule.kt via addSingleton / addSingletonFactory. Resolve with Injekt.get<T>() or injectLazy<T>().
UI & navigation – Voyager: Screen in eu.kanade.tachiyomi.ui.*, composables in eu.kanade.presentation.*. Base type: eu.kanade.presentation.util.Screen. State via rememberScreenModel { … }; most models extend StateScreenModel<State> or bases like SearchScreenModel; some use plain ScreenModel. Prefer screenModelScope and ioCoroutineScope; use launchIO / withIOContext from tachiyomi.core.common.util.lang. rememberCoroutineScope() is fine in Compose; long-lived services may use their own CoroutineScope.
Activities (not Voyager) – MainActivity (shell), ReaderActivity + ReaderViewModel, WebViewActivity, UnlockActivity, OAuth login activities, DeepLinkActivity. Reader: ReaderActivity.newIntent(context, mangaId, chapterId). Web: both WebViewScreen (Voyager) and WebViewActivity.newIntent(...).
Example: DeepLinkScreen + DeepLinkScreenModel in app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/.
Domain / data – One class per operation under domain/…/interactor/ (verb names, not *Interactor suffix). Also app/src/main/java/eu/kanade/domain/…/interactor/ for app-specific cases. Wire repos in eu.kanade.domain.DomainModule.kt (+ KMKDomainModule, SYDomainModule).
Database – SQLDelight in data/src/main/sqldelight/tachiyomi/ (.sq queries, migrations/*.sqm). After schema changes add a new .sqm and often // KMK blocks in .sq / mappers. Regenerate: ./gradlew :data:generateSqlDelightInterface (or any compile that touches :data).
App preference migrations – app/src/main/java/mihon/core/migration/migrations/ (mihon.core.migration.Migration).
Images – Coil 3 (coil3.*, context.imageLoader). No Glide/Picasso.
Komikku-specific work
- Strings: see Mandatory rules – Internationalization. Summary: Komikku →
KMR/i18n-kmk/…/base/only. - Do not edit locale
strings.xmlini18n/ori18n-sy/except when syncing upstream; translations via Weblate. - Komikku code/DI: search
// KMK(e.g.KMKDomainModule,HideCategory, library-update errors). - Prefs:
eu.kanade.domain.*.service.*Preferences(e.g.SourcePreferences.relatedMangas()).
Examples (Komikku → i18n-kmk, not i18n): library update error UI, sync-before-update messages, WebDAV/Discord settings, updater notifications, mihon/feature/* Komikku screens.
Extensions & sources
- Catalog sources: installable APK extensions (not in this repo).
- In-repo: delegated sources and metadata in
exh/(E-Hentai, NHentai, MangaDex,exh/recs/). source-api:eu.kanade.tachiyomi.source.*— avoid breaking extension ABI.
Build & CI
Build types: debug (.dev), release, releaseTest (.rt), foss (.foss), preview (.beta, CI default), benchmark.
Gradle -P flags (buildSrc/.../BuildConfig.kt):
| Flag | Effect |
|---|---|
include-telemetry |
Firebase Analytics + Crashlytics |
enable-updater |
In-app update checker |
disable-code-shrink |
Skip R8 minification |
include-dependency-info |
Dependency metadata in APK |
./gradlew spotlessApply # format (run before spotlessCheck)
./gradlew spotlessCheck # REQUIRED before considering work done (CI gate)
./gradlew assemblePreview # main CI/dev APK
./gradlew assemblePreview -Pinclude-telemetry -Penable-updater # full upstream CI build
./gradlew testReleaseUnitTest # CI unit tests (or ./gradlew test for all modules)
./gradlew installDebug # device install
./gradlew :data:generateSqlDelightInterface # after .sq / .sqm changes
Agent verification checklist (minimum): spotlessApply → spotlessCheck → assembleDebug (or compileDebugKotlin only if the user asked for a quick compile check—but still run Spotless).
JDK 17.
Fork-origin markers
Preserve inline blocks when editing:
// KMK --> … // KMK <-- Komikku
// SY --> … // SY <-- TachiyomiSY
// EXH --> … // EXH <-- E-Hentai / exh (existing); prefer KMK for new Komikku-only code
Package roots: eu.kanade.tachiyomi.* (legacy UI), tachiyomi.* (domain/data), mihon.* (Mihon upstream), exh.* (enhanced sources).
Tests
- Unit tests:
domain/src/test/; app:app/src/test/.../MigratorTest.kt. No broad UI test suite.
Conventions
- Logging – Prefer
xLogE()/xLog()helpers fromexh.logfor Komikku code, Mihon useslogcat { }fromtachiyomi.core.common.util.system. Avoid rawandroid.util.Log. - Formatting – Spotless + ktlint (
buildSrc/.../mihon.code.lint.gradle.kts). Agents must runspotlessApplyandspotlessCheck(see Mandatory rules). - Fork edits – New Komikku features inside
// KMKislands; keep// SY/// EXHblocks intact when merging upstream.
Key files
App.kt– Injekt bootstrap, logging setupMainActivity.kt– Voyager hostapp/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt– core DIapp/src/main/java/eu/kanade/domain/DomainModule.kt– domain interactorsbuildSrc/.../BuildConfig.kt,AndroidConfig.kt– flags, SDK versionsapp/build.gradle.kts,settings.gradle.kts
Cursor Cloud specific instructions
Environment
The VM update script installs the Android SDK (platform 36, build-tools 35.0.1, platform-tools, cmdline-tools) into /opt/android-sdk and writes local.properties with sdk.dir. JDK 21 is pre-installed and works fine for compiling to JVM target 17. ANDROID_HOME, JAVA_HOME, and PATH are set in ~/.bashrc.
Running key commands
All Gradle commands require the environment variables set above. Export them before invoking ./gradlew if running in a fresh shell:
export ANDROID_HOME=/opt/android-sdk
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
| Task | Command |
|---|---|
| Required format fix | ./gradlew spotlessApply (run first after code edits) |
| Required format gate | ./gradlew spotlessCheck (must pass before task is done) |
| Debug APK build | ./gradlew assembleDebug |
| Preview APK build (CI) | ./gradlew assemblePreview |
| Unit tests (CI) | ./gradlew testReleaseUnitTest |
| All module tests | ./gradlew test |
| SQLDelight codegen | ./gradlew :data:generateSqlDelightInterface |
Gotchas
- First Gradle build downloads ~1 GB of dependencies; subsequent builds use the Gradle cache and are much faster.
local.propertiesis.gitignored — it must be recreated if missing (the update script handles this).- No Android emulator or device is available on the Cloud VM, so
installDebugwill fail. Build verification is done viaassembleDebug. google-services.jsonandclient_secrets.jsonare not present (CI secrets); builds without-Pinclude-telemetrysucceed without them.- Gradle daemon may use significant memory (
-Xmx4gingradle.properties). If OOM occurs, kill and restart the daemon with./gradlew --stop.