Internal handbook for agents working in this repository.
Use this file to avoid re-discovering the project, preserve the current architecture, and move quickly in a large Android codebase without introducing stack drift.
Primary source of truth:
README.mdsettings.gradle.ktsgradle/libs.versions.toml
- Preserve the current stack and architecture unless the user explicitly asks to change them.
- Follow the existing MVI approach in
presentation. - Keep non-trivial screen state and side effects in stores/components, not in scattered composable state.
- Keep flavor-specific behavior aligned across
app,data, andpresentation. - Write or update tests when changes affect logic, parsing, mapping, repositories, stores, reducers, state transitions, or bug fixes.
- Pure visual copy/layout tweaks may not need tests; behavior changes usually do.
- If a meaningful test should exist and you do not add one, say so explicitly.
- Do not replace core libraries with parallel stacks without explicit user approval.
Gradle modules:
:app= final Android application module:presentation= Compose UI, navigation, MVI stores, feature logic:data= repository implementations, TDLib integration, Room, push, services:domain= shared contracts, domain models, managers:core= low-level shared utilities:baselineprofile= startup/performance benchmarking
Dependency direction:
appdepends onpresentation,data,domain,corepresentationdepends ondomain,coredatadepends ondomain,coredomainandcoreshould remain platform-light
Typical feature flow:
- Android startup and app wiring happen in
app presentation/rootselects startup and navigation flow- a
Default*Componentwires aStore - the
Storeprocesses intents and uses domain contracts dataimplements those contracts and talks to TDLib / DB / push / platform services- results are mapped into UI state rendered by
*Content.kt
Role:
- Android entrypoint
- build types, flavors, signing, APK naming/copying
- app shell wiring and top-level Android integration
Main areas:
app/src/main/java/org/monogram/app/componentsapp/src/main/java/org/monogram/app/diapp/src/main/java/org/monogram/app/uiapp/src/main/java/org/monogram/app/ui/theme
Belongs here:
- application startup
- Android app shell concerns
- theme/bootstrap wiring
- flavor/runtime-specific app setup
Does not belong here:
- repository logic
- TDLib implementation details
- large reusable feature flows already living in
presentation
Role:
- main UI module
- Compose screens, navigation, MVI state management, feature interaction logic
Top-level areas:
presentation/root= app-wide startup/navigationpresentation/di= Koin wiring and presentation-level setuppresentation/core= shared UI/media/util infrastructurepresentation/features= product flowspresentation/settings= settings flowspresentation/src/main/cpp= native media/animation support
Common file roles:
*Content.kt= UI rendering*Store.kt/*StoreFactory.kt= state, intents, side effectsDefault*Component.kt= concrete wiring and navigation integration
Important subareas:
features/chats- largest and most fragile feature area
- chat list, conversation, message rendering, input bar, scrolling, selection, editor flows
features/auth- auth/login flow
features/webapp,features/webview- mini apps and embedded web flows
settings/privacy,settings/proxy,settings/storage- settings areas with substantial behavior/state
Belongs here:
- screen state
- user intent handling
- navigation state
- Compose UI
- presentation-level mapping and UI orchestration
Does not belong here:
- low-level TDLib calls
- Room access
- repository implementation details
Role:
- concrete data layer
- repository implementations and integration boundary with TDLib/platform/storage
Main areas:
data/chatsdata/datasource/cachedata/datasource/remotedata/db/daodata/db/modeldata/didata/gatewaydata/infradata/mapperdata/notificationsdata/pushdata/repositorydata/servicedata/stickersdata/src/official/jniLibsdata/src/telemt/jniLibs
Belongs here:
- repository implementations
- TDLib access
- local cache and DB
- push implementation
- data mapping between external/raw and internal models
Does not belong here:
- Compose UI
- screen state
- app shell concerns
Role:
- shared contract/model layer between
presentationanddata
Main areas:
domain/modelsdomain/models/webappdomain/repositorydomain/managersdomain/proxy
Belongs here:
- interfaces/contracts
- stable domain models
- business-level abstractions
Does not belong here:
- Android framework code
- Room entities/DAOs
- Compose/UI code
- TDLib implementation details
Role:
- low-level shared helpers with low coupling
Known area:
core/date
Belongs here:
- generic reusable utilities
Does not belong here:
- feature-specific behavior
- app-specific orchestration
Role:
- performance/startup benchmark module targeting
:app
Main files:
BaselineProfileGenerator.ktStartupBenchmarks.kt
- UI issue on one screen:
- start at the nearest
*Content.kt - then inspect the related
Store - then inspect the
Default*Componentif navigation/wiring is involved
- start at the nearest
- MVI/state bug:
- start from
*Store.ktand*StoreFactory.kt - check intents, state transitions, side effects, and any reducer/executor-style logic
- start from
- Chat bug:
- start in
presentation/features/chats - if it smells like data/update/state source issue, follow into
data/chats,data/gateway,data/datasource/remote
- start in
- TDLib/API shape bug:
- inspect
data/gatewayanddata/datasource/remote - inspect
data/src/official/java/org/drinkless/tdlib/TdApi.javaordata/src/telemt/java/org/drinkless/tdlib/TdApi.java - then check official TDLib docs
- inspect
- Mapper/parsing bug:
- start in
data/mapper, then trace caller repository/datasource usage
- start in
- Push or flavor bug:
- inspect
firebase/libresource sets inapp,data, andpresentation - confirm the same flavor assumption across modules before changing code
- inspect
- Storage/database bug:
- start in
data/db,data/datasource/cache, and affected repository
- start in
- Build or Android SDK bug:
- if errors look environment-related, assume sandbox may be the cause and escalate quickly
The project uses TdApi.java as the generated TDLib Java API surface.
Important local copies:
data/src/official/java/org/drinkless/tdlib/TdApi.javadata/src/telemt/java/org/drinkless/tdlib/TdApi.java
Upstream/reference copies also exist in:
td/example/android/tdlib/java/org/drinkless/tdlib/TdApi.javatd-telemt/example/android/tdlib/java/org/drinkless/tdlib/TdApi.java
When working on TDLib-related behavior:
- inspect
TdApi.javafirst for object/function types and field names - inspect
data/gatewayfor the project’s TDLib boundary - inspect
data/datasource/remoteand repositories for call sites
External TDLib references:
- Telegram API docs:
https://core.telegram.org/api - TDLib C++/API docs:
https://core.telegram.org/tdlib/docs/td__api_8h.html
IDE note from README.md:
TdApi.javais large enough that Android Studio indexing limits may need to be increased
All dependency versions are centralized in gradle/libs.versions.toml.
Rules:
- change versions in the version catalog, not ad hoc in module files
- extend the current stack before adding a new library
- do not introduce a parallel stack unless the user explicitly asks for it
Current stack and intended use:
Kotlin+kotlinx.coroutines+Flow- default async/concurrency model
- do not introduce
RxJava
Jetpack Compose+Material 3+ adaptive Compose libs- main UI toolkit
- do not pivot new UI work to an XML-first architecture
Decompose- navigation and component lifecycle in
presentation - do not replace with another navigation stack without request
- navigation and component lifecycle in
MVIKotlin- screen state management and MVI flow in
presentation - keep non-trivial presentation logic in the existing MVI shape
- screen state management and MVI flow in
Koin- dependency injection across
app,presentation, anddata - do not replace with
DaggerorHilt
- dependency injection across
kotlinx.serialization- serialization/parsing layer
- avoid introducing
GsonorMoshiwithout explicit need
Room+KSP- persistence and codegen in
data/db - do not replace with another persistence stack casually
- persistence and codegen in
Coil 3- image, GIF, SVG, and video loading in UI
- do not replace with
GlideorPicasso
Media3 / ExoPlayer- media playback
CameraX- camera capture and scanner flows
ZXing- QR/barcode processing
TDLib- Telegram core integration
Firebase Messaging- push for
firebasevariants
- push for
UnifiedPush- non-Firebase compatible push path and abstraction
MapLibre Compose- map UI
AndroidX Security Crypto+Biometric- local security and biometric flows
libphonenumber- phone number parsing/formatting
OSS Licenses plugin+play-services-oss-licenses- licenses screen support
Flavor dimensions:
tdlib:official,telemtruntime:firebase,libre
Meaning:
official/telemt= TDLib source/binariesfirebase= Firebase-backed push/runtime pathlibre= non-Firebase path
Required local config in local.properties:
API_ID=12345678
API_HASH=your_api_hash_hereOptional release signing:
RELEASE_STORE_FILE=keystore/release.jks
RELEASE_STORE_PASSWORD=...
RELEASE_KEY_ALIAS=...
RELEASE_KEY_PASSWORD=...Firebase variants also require:
app/google-services.json
Native prerequisite for presentation:
- go to
presentation/src/main/cpp - set
ANDROID_NDK_HOMEinbuild.sh - run
build.sh
TDLib build commands:
./build-tdlib.sh official
./build-tdlib.sh telemt
./build-tdlib.sh bothWSL examples from Windows PowerShell:
wsl -d Ubuntu -- bash -lc "cd /mnt/z/GitHub/monogram && ./build-tdlib.sh official"
wsl -d Ubuntu -- bash -lc "cd /mnt/z/GitHub/monogram && ./build-tdlib.sh telemt"Useful Gradle tasks:
.\gradlew.bat :app:assembleOfficialLibreDebug
.\gradlew.bat :app:assembleTelemtLibreDebug
.\gradlew.bat :data:testOfficialLibreDebugUnitTest
.\gradlew.bat :presentation:testOfficialLibreDebugUnitTest
.\gradlew.bat :core:testSandbox rule:
- If Gradle, Android SDK, NDK, emulator, ADB, or related tooling fails because SDK paths, environment access, local components, or process spawning appear restricted, assume sandbox is the likely cause.
- Do not waste time on random workaround guesses first.
- Automatically request an out-of-sandbox build/test run with escalation.
- This especially applies to Android SDK lookup errors, missing SDK components that are known to exist locally, emulator/ADB access issues, and Gradle failures that look environment-related rather than code-related.
Add or update tests for:
- bug fixes
- store/reducer/side-effect logic changes
- repository behavior changes
- mapper/parser/utility changes
- chat behavior changes
- webapp/proxy logic changes
- state machine or branching logic changes
Check existing tests first in:
presentation/src/test/javadata/src/test/javadata/src/officialUnitTest/javadata/src/telemtUnitTest/javacore/src/test
Verification rule:
- run the narrowest relevant test task first
- then run broader compile/build validation only if needed
Usually start from:
appfor startup/theme/bootstrap problemspresentationfor UI, navigation, MVI state, and user interaction issuesdatafor TDLib, repository, cache, DB, push, and mapper issuesdomainfor interfaces/contracts/model boundariescorefor generic shared utility problems
Usually ignore unless debugging build internals:
.git/.gradle/.idea/.kotlin/build/app/build/data/build/presentation/build/presentation/.cxx/domain/build/core/build/baselineprofile/build/
presentation/features/chats- largest UI/logic surface and easiest place to introduce regressions
- flavor alignment across
app,data, andpresentation- one-module-only fixes often break another variant
data/gateway- TDLib boundary; small changes can fan out widely
data/mapper- easy place for subtle model regressions
presentation/src/main/cpp- native build/setup can fail for environment reasons unrelated to app code