Skip to content

Latest commit

 

History

History
226 lines (163 loc) · 14 KB

AGENTS.md

File metadata and controls

226 lines (163 loc) · 14 KB

AGENTS.md

This file provides guidance to all AI agents (Claude, Codex, Gemini, etc.) working with code in this repository.

Nextcloud Contribution Policy

All contributions generated or assisted by this agent must fully comply with:

  • AI Contribution Policy — the primary reference for AI-specific rules, covering disclosure, author accountability, communication, security, licensing, code quality, and autonomous agent behavior.
  • Contribution Guidelines — covering testing requirements, the Developer Certificate of Origin (DCO), license headers, conventional commits, and translations. These apply in full to all contributions regardless of how they were produced.

What this agent must always do

  • Add an Assisted-by: AGENT_NAME:MODEL_VERSION git trailer to every commit containing AI-assisted content.
  • Ensure every pull request includes a disclosure of AI tool use in the PR description.
  • Produce focused, scoped pull requests that address exactly one concern. Do not touch unrelated files or introduce incidental refactors.
  • Verify all dependencies against actual package registries before suggesting them. Do not use hallucinated or unverified package names.
  • Write code comments that document the code, never the process that produced it:
    • Comments describe what the code does — method signatures, behavior, and constraints the code itself cannot express (e.g. a non-obvious invariant or workaround).
    • Never add comments that document progress, decisions, or changes (e.g. "changed X to Y", "as requested", "this fixes ...", "previously this did ..."). That belongs in the commit message or PR discussion; in the code it goes stale and becomes misleading.
    • Do not narrate self-explanatory code. If the code is readable without a comment, omit the comment.
    • Keep comments brief — short and simple, matching the comment density of the surrounding code.
  • Reuse existing helper functions and utilities instead of re-implementing their logic inline. When fixing a flawed pattern, fix every occurrence of it across the changed code, not only the instance that was pointed out.
  • Run permission and access-control checks before the operation they guard, never after it and never only in the UI layer.
  • When adding or changing user-facing functionality, wire it up in every context where the affected component is used — the default authenticated view, public share pages, and embedded contexts such as the Smart Picker and reference widgets. When emitting new events, verify that every consumer of the component subscribes to and handles them.
  • Explicitly inform the contributor when any action they are about to take, or have taken, would violate the AI Contribution Policy or the Contribution Guidelines. Do not silently proceed. State which rule is at risk and what the contributor should do instead.
  • Warn the contributor if a pull request is growing too large. A PR approaching several thousand lines of changed code is a signal that it should be split into smaller, focused PRs. Suggest a logical split before the PR is opened, not after.
  • Recommend opening a ticket for discussion before starting implementation whenever a feature or change is sufficiently complex — for example when it touches multiple subsystems, requires architectural decisions, or the right approach is not yet clear. A ticket allows maintainers and the contributor to align on direction before code is written, avoiding wasted effort on a PR that may be rejected or require fundamental rework.

What this agent must never do

  • Open issues, submit pull requests, post review comments, or send security reports autonomously. Every contribution must be reviewed and submitted by a human.
  • Add Signed-off-by tags to commits. Only the human contributor can certify the Developer Certificate of Origin.
  • Generate or submit security reports without independent human verification. Report verified vulnerabilities via HackerOne, not as GitHub issues.
  • Write PR descriptions, review comments, or issue reports on behalf of the contributor. These must be in the contributor's own words.
  • Fully automate the resolution of issues labeled good first issue or similar beginner-friendly labels.
  • Submit code that has not been reviewed and cleaned up by the contributor. Dead code, redundant logic, excessive comments, malformed or garbled characters (e.g. � replacement characters), and unrelated changes must be removed before submission.

Project Overview

Nextcloud Talk for Android — a self-hosted audio/video and chat communication app. Connects to a Nextcloud server backend. Written primarily in Kotlin (some legacy Java), targets API 26+ (minSdk 26, targetSdk 36).

Build Commands

# Assemble a debug APK (F-Droid flavor, no Google services)
./gradlew assembleGenericDebug

# Assemble with Google Play services (push notifications)
./gradlew assembleGplayDebug

# Run all unit tests
./gradlew test

# Run a single unit test class
./gradlew testGenericDebugUnitTest --tests "com.nextcloud.talk.utils.SomeTest"

# Run instrumented (on-device) tests
./gradlew connectedAndroidTest

# Static analysis — all checks (spotbugs, lint, ktlint, detekt)
./gradlew check

# Individual checks
./gradlew ktlintCheck
./gradlew ktlintFormat   # auto-fix
./gradlew detekt
./gradlew lint

# Install git hooks (run once after cloning)
./gradlew installGitHooks

# Clean build
./gradlew clean assembleGenericDebug

Build output: app/build/outputs/apk/

Build Flavors

Flavor App ID Purpose
generic com.nextcloud.talk2 F-Droid release (no Google services)
gplay com.nextcloud.talk2 Google Play (Firebase push notifs)
qa com.nextcloud.talk2.qa Per-PR testing builds

gplay-only dependencies (Firebase, play-services-base) use gplayImplementation. Avoid introducing Play-only dependencies into generic code paths. F-Droid (generic) builds do not support Google push notifications.

Architecture

MVVM with layered architecture:

  • API layer — api/NcApi.java (Retrofit/RxJava2) and api/NcApiCoroutines.kt (Retrofit/coroutines).
  • Data layer — data/ contains Room DB entities/DAOs (data/database/), repository impls (data/user/, repositories/), and a network monitor. The Room DB is encrypted with SQLCipher.
  • Repository layer — repositories/ and data/user/UsersRepository.kt are the single source of truth.
  • ViewModel layer — expose StateFlow/LiveData to UI. Located in per-feature viewmodels/ subdirectories.
  • UI layer — Activities/Fragments per feature. Mix of traditional View/XML and Jetpack Compose (composables live alongside XML layouts in feature packages).

Dependency Injection

Dagger 2 (via AutoDagger2). App component: application/NextcloudTalkApplication.kt (@AutoComponent). Modules in dagger/modules/: RestModule, DatabaseModule, DaosModule, RepositoryModule, ViewModelModule, ManagerModule, UtilsModule.

Use @Inject for Activities/Fragments/Services/BroadcastReceivers. For all other components, prefer constructor injection.

Feature Packages (under com/nextcloud/talk/)

  • conversationlist/ — main screen after login (actively being Compose-migrated, see below)
  • chat/ — ChatActivity, message input, voice recording, scheduled messages
  • call/ — WebRTC participant modeling, MCU/non-MCU strategies
  • webrtc/ — low-level WebRTC: PeerConnectionWrapper, WebSocketInstance, audio
  • signaling/ — SignalingMessageReceiver, SignalingMessageSender, typed notifiers
  • conversationinfo/ / conversationinfoedit/ — room settings
  • account/ — login, account verification
  • settings/ — app settings
  • jobs/ — WorkManager background workers
  • services/ — CallForegroundService
  • ui/theme/ — Nextcloud theming applied to Material components

Signaling Architecture

Two modes selected at runtime based on server capabilities:

  • No-MCU (P2P mesh): call/LocalStateBroadcasterNoMcu.kt, call/MessageSenderNoMcu.kt
  • MCU (media server): call/LocalStateBroadcasterMcu.java, call/MessageSenderMcu.java

signaling/SignalingMessageReceiver.java dispatches to typed notifiers (CallParticipantMessageNotifier, WebRtcMessageNotifier, etc.).

When changing participant or call state handling, always verify both MCU and no-MCU paths — a change that works in one mode can silently break the other.

Active Work: Compose Migration of conversationlist/

ConversationsListActivity is being incrementally migrated to Jetpack Compose. The plan is in docs/compose-migration-conversations-list.md. Steps 1–7 are complete (ViewModel state consolidation, status banners, empty states, FAB, notification warning card, federation invitation card, shimmer loading, conversation item composable). Steps 8–10 (LazyColumn list, toolbar/search bar, full Activity handover) are pending.

Convention: During the migration each component is replaced one at a time so the app remains fully functional after every step. New composables go in conversationlist/ui/. The existing FlexibleAdapter/RecyclerView is kept until Step 8.

Code Style

  • Line length: 120 characters

  • Standard Android Studio formatter with EditorConfig.

  • Kotlin preferred for new code; legacy Java still present.

  • Do not use decorative section-divider comments of any kind (e.g. // ── Title ───, // ------, // ======).

  • Every new file must end with exactly one empty trailing line (no more, no less).

  • All new files require an SPDX license header:

    Kotlin/Java:

    /*
     * Nextcloud Talk - Android Client
     *
     * SPDX-FileCopyrightText: <year> Nextcloud GmbH and Nextcloud contributors
     * SPDX-License-Identifier: GPL-3.0-or-later
     */

    XML:

    <!--
      ~ Nextcloud Talk - Android Client
      ~
      ~ SPDX-FileCopyrightText: <year> Nextcloud GmbH and Nextcloud contributors
      ~ SPDX-License-Identifier: GPL-3.0-or-later
    -->
  • Translations via Transifex — only modify values/strings.xml, never translated values-*/strings.xml files.

File Naming

Layout/menu files follow the component they belong to:

Component Class Name File Name
Activity UserProfileActivity activity_user_profile.xml
Fragment SignUpFragment fragment_sign_up.xml
Dialog ChangePasswordDialog dialog_change_password.xml
AdapterView item — item_person.xml
Partial layout — partial_stats_bar.xml

Design

After Making Changes

After finishing code changes, run ./gradlew detekt ktlintCheck and fix any new errors or warnings before considering the task done.

Static Analysis

  • detekt: config in detekt.yml
  • ktlint: via org.jlleitschuh.gradle.ktlint plugin
  • SpotBugs: filter in spotbugs-filter.xml; FindSecBugs and fb-contrib active
  • lint: HTML report at app/build/reports/lint/lint.html

Testing

  • Unit tests: app/src/test/ — JUnit 4/5, Mockito, Robolectric, MockWebServer. Uses useJUnitPlatform().
  • Instrumented tests: app/src/androidTest/ — Espresso. Integration tests need real server credentials in gradle.properties (NC_TEST_SERVER_BASEURL, etc.).
  • Room migrations: if you change the schema, add or update migration tests under androidTest/data/. See data/source/local/TalkDatabase.kt for migration declarations.
  • A new test must fail without its fix: a passing test is not evidence that it reached the code it names. Revert the change under test, confirm the test fails, then restore it. Tests have been merged here asserting behaviour they never exercised, because an earlier guard returned before the code under test ran — and running the suite cannot tell you that.
  • Assertions come from the requirement, fixtures come from the code: derive what the behaviour should be from the spec, but derive the setup from the code path, since only the code says which preconditions reach the branch. A fixture written from the description alone often puts the system in a state where the behaviour under test cannot occur at all.
  • App startup workers: NextcloudTalkApplication.kt schedules periodic workers (CapabilitiesWorker, signaling/WebSocket workers) at startup. Worker scheduling changes can cause subtle startup regressions.

Commits

  • All PRs target master. Backports use /backport to stable-X.Y in a PR comment.

  • The DCO requires a Signed-off-by on every commit. This must be added by the human contributor (git commit -s) — the agent must never add it (see contribution policy above).

  • Commit messages must follow the Conventional Commits v1.0.0 specification — e.g. feat(chat): add voice message playback, fix(call): handle MCU disconnect gracefully.

  • Every commit made with AI assistance must include an Assisted-by trailer identifying the coding agent and model:

    Assisted-by: Claude Code:claude-sonnet-4-6
    Assisted-by: Copilot:claude-sonnet-4-6
    

    General pattern: Assisted-by: <coding-agent>:<model-version>