Complete Kotlin Multiplatform migration with iOS parity: - All 13 modules converted to KMP (commonMain + androidMain + iosMain) - 100% feature parity: auth, chat, SSE streaming, conversations, settings, agents, files, voice input, TTS, OAuth, file picker, clipboard paste - Platform consolidation: DataStore path, SessionCacheCleaner, bubble layouts, ChatInput core, MIME types, mention parsing, TextField styling, FilterChip components extracted to commonMain - iOS crash reporting via Kotlin/Native exception hook - YAML parsing via custom pure-Kotlin parser (zero dependencies) - Dependency health: Timber removed, kaml replaced, FuzzyWuzzy removed, security-crypto stabilized - CONTRIBUTING.md - Gradle configuration cache enabled
3.4 KiB
3.4 KiB
LibreChat Android
Native Android client for LibreChat. Connects to existing LibreChat backend servers (no backend changes). Users specify server URL during onboarding.
Tech Stack
- UI: Jetpack Compose + Compose Navigation
- DI: Koin (KMP-ready)
- Network: Ktor Client (OkHttp engine)
- Serialization: Kotlinx Serialization
- Local Storage: Room (cache), DataStore (prefs), EncryptedSharedPreferences (tokens)
- Build: Gradle 8.11.1, AGP 8.7.3, Kotlin 2.1.0, compileSdk 35, minSdk 26
Module Layout
app/ → Single Activity, adaptive navigation (phone/tablet)
build-logic/ → 7 convention plugins for consistent Gradle config
core/common/ → Result type, dispatcher DI, coroutine scopes, extensions
core/model/ → @Serializable data classes (pure Kotlin, no Android deps)
core/network/ → Ktor client, 16 API services, SSE client, auth interceptor
core/data/ → Room DB, DataStore, EncryptedSharedPrefs, repository impls
core/ui/ → Material 3 theme, shared composables
feature/auth/ → Server URL, Login, Register, 2FA, OAuth, Forgot Password
feature/chat/ → Real-time chat with SSE streaming, message rendering
feature/conversations/→ Paginated list, CRUD, tags, search, export/import
feature/settings/ → Account, appearance, about, danger zone
feature/agents/ → Agent marketplace with search and categories
feature/files/ → File upload, management, image viewer
Each module has its own CLAUDE.md with specific guidance.
Architecture Rules
- Feature modules depend on
:core:*only, never on each other - Single Activity with Compose Navigation
- Unidirectional data flow: UI → ViewModel → Repository → API/Room
- Room is a read-through cache; server is source of truth
- Custom SSE parser over raw ByteReadChannel (not Ktor SSE plugin)
Adding a New Feature Module
- Create the module directory under
feature/ - Apply the
librechat.android.featureconvention plugin inbuild.gradle.kts— this auto-applies Koin + Compose deps - Create
di/<Feature>Module.ktwith a Koinmodule { }containingviewModelOf(::YourViewModel)definitions - Register the module in
LibreChatApplication.kt'sstartKoin { modules(...) }list - Use
koinViewModel()in screen composables to inject ViewModels
Backend Quirks
- Mutation endpoints wrap body in
argfield:{ "arg": { ... } } - Two-phase SSE: POST →
{ streamId }, then GET stream.streamId === conversationId GET /api/configdrives feature availability — never hardcode- ua-parser-js middleware rejects non-browser User-Agents with 403 (workaround: Chrome UA string)
- Refresh token sent via request body (not HTTP-only cookies)
Upstream Sync
upstream/— Git submodule of the official LibreChat repo. Read-only reference for API and web app parity. Do not modify.UPSTREAM_VERSION— Tracks which official tag/commit this Android build is based on. Updated by the/sync-upstreamskill.BackendVersion.kt(core/common/) —SUPPORTED_BACKEND_VERSIONconstant must match the tag inUPSTREAM_VERSION(withoutvprefix)./sync-upstream— Claude Code skill to diff upstream releases, identify gaps, propose changes, and implement them with user approval. Uses Agent Teams (investigator, android-expert, implementer, verifier).