From 8fee1aba50014f8db65d6f9e84e8765cc3992388 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 25 Mar 2026 11:55:42 +0100 Subject: [PATCH] Create AGENTS.md --- AGENTS.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 119 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..454c347a9f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,118 @@ +# 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`). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..eef4bd20cf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md \ No newline at end of file