Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .aiexclude
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.gradle/
build/
!build/reports/
*/build/
Comment on lines +2 to +4
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If .aiexclude uses gitignore-style semantics (the patterns/negation syntax suggest it does), !build/reports/ (and the similar module rules) won’t take effect because the parent build/ directory is excluded. To ensure reports/outputs/test-results are actually included, un-exclude the parent directories and then re-exclude everything else (e.g., unignore build/ + selectively allow subpaths), or restructure the patterns accordingly.

Suggested change
build/
!build/reports/
*/build/
build/*
!build/reports/
*/build/*

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about .aiexclude. Neat. Hopefully it takes hold as a wider standard.

Regarding the syntax, Copilot's suggestion is good. From the docs:

An .aiexclude file follows the same syntax as a .gitignore file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully it takes hold as a wider standard.

🤞 x 🤞 ^ 🤞

!*/build/reports/
!*/build/outputs/
!*/build/test-results/
local.properties
gradle.properties
16 changes: 10 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ proguard/
# Log Files
*.log

# Intellij project files
*.iml
*.ipr
*.iws
.idea/

# private config file
gradle.properties
!/benchmark/gradle.properties
Expand All @@ -47,3 +41,13 @@ gradle.properties
# OS X generated file
.DS_Store

# Agent config local files (Claude, Codex, Gemini, Cursor, Windsurf, etc.)
# Keep main config files under version control, ignore user-local overrides
**/AGENTS.local.md
**/CLAUDE.local.md
Comment on lines +46 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know these were a thing. The docs don't mention supporting a CLAUDE.local.md file.

However, it seems to be working

Image

Not sure if it's a compatibility thing that they'll phase out, as it's not documented, or just a standard pattern that will be maintained.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, same @mokagio and thanks for taking a closer look at it, plus testing it! 🥇

I too just found it myself as I was writing those Agent Readiness PRs, of course with AI help and support, and thought, why not adding those in there, wouldn't hurt, would it? Worse case scenario, I thought, we'll stop adding them into more repos (should that not become a standard), and maybe, delete this configuration from those repos that we've added them in already, right? Having said that, usually, this .gitignore file becomes a fire and forget file, with ignore files/folders been added in there but rarely removed/edited, only when REALLY needed... 🤷

**/.claude/**/*.local.*
**/.codex/**/*.local.*
**/.gemini/**/*.local.*
**/.cursor/**/*.local.*
**/.windsurf/**/*.local.*

70 changes: 70 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# AGENTS.md

This file provides guidance to coding agents when working with code in this repository.

## Project Overview

Android client library for tracking user events (Nosara/Tracks), A/B testing (ExPlat), and crash logging (Sentry). Published to Automattic's S3 Maven repository. Used internally by Automattic mobile apps. Includes a `sampletracksapp` app module that can be used for manual testing.

## Build Commands

```bash
./gradlew assembleDebug # Build all modules
./gradlew testDebugUnitTest # Run all unit tests
./gradlew lintDebug # Run lint checks
Comment on lines +13 to +14
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documented lint/test commands (lintDebug, testDebugUnitTest) don’t match what CI runs (./gradlew lint and ./gradlew test per .buildkite/pipeline.yml). Consider documenting the CI-equivalent tasks (or noting the difference) so agents reproduce CI locally without guessing the right task names.

Suggested change
./gradlew testDebugUnitTest # Run all unit tests
./gradlew lintDebug # Run lint checks
./gradlew testDebugUnitTest # Run unit tests for the debug variant (CI runs `./gradlew test`)
./gradlew lintDebug # Run lint checks for the debug variant (CI runs `./gradlew lint`)

Copilot uses AI. Check for mistakes.
./gradlew ktlint # Check Kotlin code style (custom task from ktlint.gradle)
./gradlew ktlintFormat # Fix Kotlin code style deviations (custom task from ktlint.gradle)
./gradlew ciktlint # Same as ktlint but with checkstyle XML output for CI (custom task from ktlint.gradle)
./gradlew buildHealth # Dependency analysis
./gradlew :experimentation:apiCheck # Binary compatibility check (`experimentation` module only)
./gradlew :benchmark:assembleDebugAndroidTest # Build benchmark instrumented tests
./gradlew :benchmark:connectedDebugAndroidTest # Run benchmark instrumented tests on a connected device
```

To run a single test class:

```bash
./gradlew :experimentation:testDebugUnitTest --tests "com.automattic.android.experimentation.ExPlatTest"
./gradlew :crashlogging:testDebugUnitTest --tests "com.automattic.android.tracks.crashlogging.SentryCrashLoggingTest"
```

**Note:** `gradle.properties` is gitignored. CI copies `gradle.properties-example` before building. Locally, copy it manually if needed: `cp gradle.properties-example gradle.properties`.

## Architecture

Three independently published library modules plus a sample app and benchmark module:

| Module | Artifact | Language | Description |
|--------|----------|----------|-------------|
| `AutomatticTracks` | `com.automattic:Automattic-Tracks-Android` | Java + Kotlin | Core event tracking with SQLite storage and background network transmission |
| `experimentation` | `com.automattic.tracks:experimentation` | Kotlin | ExPlat A/B testing SDK with file-based caching and OkHttp REST client |
| `crashlogging` | `com.automattic.tracks:crashlogging` | Kotlin | Sentry-based crash logging, performance monitoring, and error tracking |
| `sampletracksapp` | — | Kotlin | Sample app demonstrating library usage |
| `benchmark` | — | Kotlin | Performance benchmarking via `androidTest` instrumented tests using `androidx.benchmark` |

### Key architectural details

- **AutomatticTracks** uses a queue-based architecture with background threads for event buffering, DB-to-network transfer, and network transmission. Events expire after 14 days.
- **experimentation** has `explicitApi()` enabled and uses binary compatibility validation (`apiCheck`). Public API surface is tracked in `experimentation/api/experimentation.api`.
- **crashlogging** wraps Sentry SDK via `SentryErrorTrackerWrapper` and exposes a `CrashLoggingDataProvider` interface for host apps to supply user/app context.
- Modules publish independently to S3. No product flavors or build variants.

## Testing Conventions

- **Frameworks:** JUnit 4, AssertJ, Mockito-Kotlin, kotlinx-coroutines-test, MockWebServer
- **Assertions:** Use AssertJ (`assertThat`), not kotlin.test assertions
- **Naming:** Backtick-quoted names: `` `given ..., when ..., then ...` ``
- **Coroutines:** Use `runTest` from `kotlinx.coroutines.test`

## Important Gotchas

- Build files use **Groovy** (`build.gradle`, `settings.gradle`), not Kotlin DSL — except `benchmark/build.gradle.kts` which uses Kotlin DSL
- Dependency versions are defined as `ext` properties in root `build.gradle`, not a version catalog
- Lint treats warnings as errors (`warningsAsErrors true`). `AutomatticTracks` uses a lint baseline file
Comment on lines +61 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first and last seem like stuff the model would notice when reading the code, without needing to be explicit

Suggested change
- Build files use **Groovy** (`build.gradle`, `settings.gradle`), not Kotlin DSL — except `benchmark/build.gradle.kts` which uses Kotlin DSL
- Dependency versions are defined as `ext` properties in root `build.gradle`, not a version catalog
- Lint treats warnings as errors (`warningsAsErrors true`). `AutomatticTracks` uses a lint baseline file
- Dependency versions are defined as `ext` properties in root `build.gradle`, not a version catalog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good comment @mokagio ! 💯

I was thinking about that too, in the end chose to keep it in there because this version catalog is indeed the standard nowadays (years now), and I think AI would try to enforce this standard, maybe creating such a version catalog pattern, that is, instead of using the existing legacy ext properties pattern this repo uses. What I wanted here, is for AI to avoid doing that, thinking in version catalog terms, thus me being explicit giving it instructions on how dependency versions are and should be defined on this repo, being (somehow) explicit that we DON'T WANT version catalog. Does that make any sense to you? 💭 (I probably over-complicating this 😊 for sure)


## Publishing

CI publishes on every PR commit and trunk merge:
- PR: `{pr-number}-{commit-full-sha1}`
- Trunk merge: `trunk-{commit-full-sha1}`
- Tag: `{tag-name}`
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md