# AGENTS.md — Element X Android > **Repo:** `element-hq/element-x-android` — Android Matrix client (Compose UI + `matrix-rust-sdk`). --- ## Strong Conventions PRs must meet these rules. ### Code Style - Style enforced by **Editor config** (`.editorconfig`). - Set "Hard wrap at" to 160 chars in Android Studio. ### PII & Logging - We use **Timber** for logging. Never use `android.util.Log`. - **Never log secrets, passwords, keys, or user content** (e.g. message bodies). - Matrix IDs (User IDs, Room IDs, Event IDs) are safe to log. ### Strings & Localisation - Default localisation: `en` (en-GB strings), shared with Element X iOS via [Localazy](https://localazy.com/p/element). - **Never edit `localazy.xml`** — it is auto-generated and overwritten. - New English strings go in **`temporary.xml`**. The core team imports these to Localazy. - **Key naming**: - Cross-screen verbs: `action_` (e.g., `action_copy`). - Common nouns/other: `common_` (e.g., `common_error`). - Accessibility: `a11y_`. - Screen-specific: `screen__` (e.g., `screen_onboarding_welcome_title`). - Errors: `error_` prefix. - Platform-specific: `_ios` or `_android` suffix. - Placeholders: Use numbered form `%1$s`, `%2$d`. ### Previews - Create previews for **all main states** of a Composable. - Use `@PreviewsDayNight` for consistency. - Use `PreviewParameterProvider` (e.g., `FooStateProvider`) to provide states. - Wrap previews in `ElementPreview { ... }`. --- ## Pull Request Guidelines - Use sentence-style commit/PR messages (no conventional commits). - Apply exactly **one** `PR-` label for changelog categorization. - PR title = changelog entry — make it descriptive; no "Fixes #…" prefixes. - Include screenshots or screen recordings for any UI changes. - Keep PRs focused; split changes over 1000 lines. --- ## Project Structure ### Build System Common Gradle tasks: - Build: `./gradlew assembleDebug` - Unit Tests: `./gradlew test` - Lint: `./gradlew lint` - Format: `./gradlew ktlintFormat` - Update Docs TOC: `./gradlew generateDocsToc` ### Gradle Modules Features follow a 3-module structure: - `features/foo/api`: Public interfaces and data classes. - `features/foo/impl`: Internal implementation, Presenter, and View. - `features/foo/test`: Test fakes and utilities. --- ## Architecture: Appyx + Molecule We use [Appyx](https://bumble-tech.github.io/appyx/) for navigation and [Molecule](https://github.com/cashapp/molecule) for Presenters. ### Files Per Screen (`Foo`) | File | Purpose | | :--- | :--- | | `FooNode.kt` | Appyx Node: Handles navigation and wires the Presenter to the View. | | `FooPresenter.kt` | A `@Composable` function that produces `FooState` from `FooEvent`s. | | `FooView.kt` | Stateless Composable rendering the UI from `FooState`. | | `FooState.kt` | Data class representing the immutable UI state. | | `FooEvent.kt` | Sealed interface for UI actions sent to the Presenter. | | `FooStateProvider.kt` | Provides sample states for Previews and Screenshot tests. | | `FooPresenterTest.kt` | Unit tests for the Presenter logic using Turbine. | --- ## Dependency Injection (Metro) - We use [Metro](https://zacsweers.github.io/metro/) for DI. - Inject via constructor parameters using `@Inject`. - Use `@AssistedInject` and `@AssistedFactory` for components requiring runtime arguments (like Navigators or IDs). - Use `@ContributesBinding(AppScope::class)` for singleton-like services. - Use `@ContributesNode(RoomScope::class)` for Appyx Nodes. --- ## Compound Design System Always prefer Compound components and tokens from `libraries/compound/` module. - **Colours**: `ElementTheme.colors.textPrimary`, `ElementTheme.colors.bgCanvasDefault`. - **Typography**: `ElementTheme.typography.fontBodyMdRegular`. - **Icons**: Use `CompoundIcons.IconName()` (e.g., `CompoundIcons.UserProfileSolid()`). --- ## The Rust SDK Layer We wrap the `matrix-rust-sdk` to isolate the UI from the underlying SDK. - Naming: SDK `Room` → `JoinedRoom` or `RoomInfo`. - Type Mapping: Map Rust SDK types to Kotlin data classes in the `api` module to avoid leaking `MatrixRustSDK` into the UI. - Always follow Kotlin naming conventions (e.g., `userId` instead of `userID`).