komikku/AGENTS.md
Cuong-Tran 582ea3e60d
chore(agent): Add mandatory rules for AI agents covering Git, i18n, and formatting (#1662)
* 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>
2026-05-27 14:42:44 +07:00

11 KiB
Raw Blame History

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/ or i18n-sy/.
  • Never edit non-base locale strings.xml or plurals.xml files in i18n-kmk/, i18n/, or i18n-sy/ (Weblate owns translations).
  • Import: import tachiyomi.i18n.kmk.KMR for Komikku strings.
  • If a change is inside // KMK -->// KMK <-- or adds Komikku-only behavior, default to KMR + 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 spotlessCheck when verifying changes.
  • If spotlessCheck fails, run spotlessApply and re-run spotlessCheck.
  • On Cloud VM, export ANDROID_HOME and JAVA_HOME first (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: appdomainsource-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.xml in i18n/ or i18n-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): spotlessApplyspotlessCheckassembleDebug (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 from exh.log for Komikku code, Mihon uses logcat { } from tachiyomi.core.common.util.system. Avoid raw android.util.Log.
  • Formatting Spotless + ktlint (buildSrc/.../mihon.code.lint.gradle.kts). Agents must run spotlessApply and spotlessCheck (see Mandatory rules).
  • Fork edits New Komikku features inside // KMK islands; keep // SY / // EXH blocks intact when merging upstream.

Key files

  • App.kt Injekt bootstrap, logging setup
  • MainActivity.kt Voyager host
  • app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt core DI
  • app/src/main/java/eu/kanade/domain/DomainModule.kt domain interactors
  • buildSrc/.../BuildConfig.kt, AndroidConfig.kt flags, SDK versions
  • app/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.properties is .gitignored — it must be recreated if missing (the update script handles this).
  • No Android emulator or device is available on the Cloud VM, so installDebug will fail. Build verification is done via assembleDebug.
  • google-services.json and client_secrets.json are not present (CI secrets); builds without -Pinclude-telemetry succeed without them.
  • Gradle daemon may use significant memory (-Xmx4g in gradle.properties). If OOM occurs, kill and restart the daemon with ./gradlew --stop.