reis-mobile 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "AI agents for mobile engineering",
8
- "version": "0.6.0"
8
+ "version": "0.7.1"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "reis-mobile",
13
13
  "source": "./",
14
14
  "description": "AI agents, skills and workflows for Flutter, Android, iOS and React Native development.",
15
- "version": "0.6.0",
15
+ "version": "0.7.1",
16
16
  "author": {
17
17
  "name": "Warleson Reis"
18
18
  },
@@ -1,12 +1,22 @@
1
1
  {
2
2
  "name": "reis-mobile",
3
- "version": "0.6.0",
4
- "description": "AI agents, skills and workflows for Flutter, Android, iOS and React Native development. Run /reis-mobile:doctor, then /reis-mobile:review.",
3
+ "version": "0.7.1",
4
+ "description": "AI agents, skills and workflows for Flutter, Android, iOS and React Native development. Use /reis-mobile:doctor, /reis-mobile:review and /reis-mobile:test.",
5
5
  "author": {
6
6
  "name": "Warleson Reis"
7
7
  },
8
8
  "license": "MIT",
9
9
  "repository": "https://github.com/wrsilva/reis-mobile",
10
10
  "homepage": "https://github.com/wrsilva/reis-mobile",
11
- "keywords": ["mobile", "flutter", "android", "ios", "react-native", "kotlin-multiplatform", "code-review", "agents", "skills"]
11
+ "keywords": [
12
+ "mobile",
13
+ "flutter",
14
+ "android",
15
+ "ios",
16
+ "react-native",
17
+ "kotlin-multiplatform",
18
+ "code-review",
19
+ "agents",
20
+ "skills"
21
+ ]
12
22
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The project follows [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [0.7.1] - 2026-09-17
8
+
9
+ ### Added
10
+
11
+ - A `SessionStart` hook for Claude Code and Codex that warns when the installed plugin is behind npm's latest release. It caches registry results for 24 hours, stays silent offline and can be disabled with `REIS_MOBILE_UPDATE_CHECK=0`.
12
+ - `reis-mobile update-check [--force]` for manually checking the CLI version.
13
+
14
+ ### Changed
15
+
16
+ - `package.json` is the only editable version source. CI synchronizes the plugin manifests and the Release workflow tests, tags and publishes a new version after it reaches `main`.
17
+ - Version synchronization now promotes authored `[Unreleased]` notes to a dated changelog section and refreshes the README's latest-release summary without changing historical entries.
18
+
19
+ ## [0.7.0] - 2026-09-17
20
+
21
+ ### Added
22
+
23
+ - `/reis-mobile:test` and `reis-mobile test`: the slash command runs, writes, audits or fixes tests according to the request; the CLI supplies explicit test routing, resolved project directory, redacted change context and toolchain diagnostics without launching test runners.
24
+ - A shared project brief contract for all 18 specialists, with actual symbols and paths, acceptance criteria, constraints, validation commands and optional team knowledge in `.reis-mobile/project.md`.
25
+
26
+ ### Changed
27
+
28
+ - Specialists now own distinct investigation steps and deliverables, reuse the project brief and load technical checklists from skills instead of repeating general instructions.
29
+ - Native testing guides discover Android modules, variants and instrumentation setup for Espresso, and Xcode workspaces, schemes, plans and destinations for XCTest/XCUITest. Both cover deterministic synchronization and honest execution reporting.
30
+
31
+ ### Fixed
32
+
33
+ - `reis-mobile init` updates the Claude Code plugin when it is already installed. It used to run `claude plugin install`, which leaves an installed plugin untouched, so `npm update -g reis-mobile` followed by `init` kept Claude Code on the old version.
34
+
5
35
  ## [0.6.0] - 2026-09-16
6
36
 
7
37
  ### Added
package/README.md CHANGED
@@ -6,7 +6,7 @@ A mobile app is not a generic project. A code review that does not know about `B
6
6
 
7
7
  <p align="center">
8
8
  <a href="https://github.com/wrsilva/reis-mobile/actions/workflows/ci.yml"><img src="https://github.com/wrsilva/reis-mobile/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
9
- <img src="https://img.shields.io/badge/Version-0.6.0-blue" alt="Version 0.6.0">
9
+ <img src="https://img.shields.io/npm/v/reis-mobile" alt="Latest npm version">
10
10
  <img src="https://img.shields.io/badge/Claude_Code-plugin-blueviolet" alt="Claude Code plugin">
11
11
  <img src="https://img.shields.io/badge/Node.js-22+-339933?logo=node.js&logoColor=white" alt="Node.js 22+">
12
12
  <img src="https://img.shields.io/badge/Dependencies-0-brightgreen" alt="Zero dependencies">
@@ -35,12 +35,31 @@ A mobile app is not a generic project. A code review that does not know about `B
35
35
 
36
36
  🔒 **Secrets never reach the model.** The diff sent for review goes through a layer that masks API keys, tokens, JWTs, private keys and keystore passwords.
37
37
 
38
- 🪶 **Two commands to install.** `npm install -g reis-mobile` and `reis-mobile init eng` set it up in Claude Code and Codex, with zero npm dependencies, no hooks and no external provider.
38
+ 🪶 **Two commands to install.** `npm install -g reis-mobile` and `reis-mobile init eng` set it up in Claude Code and Codex, with zero npm dependencies and no external provider.
39
39
 
40
40
  ---
41
41
 
42
42
  ## What's new
43
43
 
44
+ <!-- reis-mobile:latest-release:start -->
45
+ ### v0.7.1
46
+
47
+ #### Added
48
+
49
+ - A `SessionStart` hook for Claude Code and Codex that warns when the installed plugin is behind npm's latest release. It caches registry results for 24 hours, stays silent offline and can be disabled with `REIS_MOBILE_UPDATE_CHECK=0`.
50
+ - `reis-mobile update-check [--force]` for manually checking the CLI version.
51
+
52
+ #### Changed
53
+
54
+ - `package.json` is the only editable version source. CI synchronizes the plugin manifests and the Release workflow tests, tags and publishes a new version after it reaches `main`.
55
+ - Version synchronization now promotes authored `[Unreleased]` notes to a dated changelog section and refreshes the README's latest-release summary without changing historical entries.
56
+
57
+ <!-- reis-mobile:latest-release:end -->
58
+
59
+ ### Earlier highlights
60
+
61
+ **v0.7.0:** `/reis-mobile:test` runs, writes, audits or fixes tests using the app's existing setup, including XCTest/XCUITest and Espresso. The 18 agents now use a shared project brief and role-specific investigations tied to actual files, symbols and constraints.
62
+
44
63
  > 🆕 **v0.4.0: every mobile stack.** Native Android, native iOS and React Native get their own architect, performance and test specialists, and `/reis-mobile:debug` finds the cause of a failing build with the toolchain versions in hand.
45
64
  >
46
65
  > ```bash
@@ -52,7 +71,9 @@ A mobile app is not a generic project. A code review that does not know about `B
52
71
 
53
72
  | Version | Highlights |
54
73
  |--------|-----------|
55
- | **v0.6.0** (current) | `mobile-accessibility-auditor` and `mobile-release-engineer` agents with the new `mobile-accessibility` and `mobile-release` skills: accessibility audits on every stack, release readiness with a go/no-go verdict, release notes and store copy, CI/CD. `mobile-debug` gains guides for ANRs, Android memory leaks and deep links. |
74
+ | **v0.7.1** | Update notices on Claude Code and Codex session start, plus a single-source version and CI-driven release process. |
75
+ | **v0.7.0** | `/reis-mobile:test`, native XCTest and Espresso guidance, and project-specific contracts for the 18 specialists. |
76
+ | **v0.6.0** | `mobile-accessibility-auditor` and `mobile-release-engineer` agents with the new `mobile-accessibility` and `mobile-release` skills: accessibility audits on every stack, release readiness with a go/no-go verdict, release notes and store copy, CI/CD. `mobile-debug` gains guides for ANRs, Android memory leaks and deep links. |
56
77
  | **v0.5.0** | 11 skills instead of 60: topic skills with a guide per platform (`mobile-architecture`, `mobile-code-review`, `mobile-debug`, `mobile-test`, `mobile-security`, `mobile-firebase`) and platform skills (`mobile-flutter`, `mobile-android`, and the new `mobile-ios` and `mobile-rn`). Half the fixed context cost. |
57
78
  | **v0.4.0** | Native Android, iOS and React Native: architect, performance and test agents for each; `/reis-mobile:debug` for Gradle, Xcode, CocoaPods and Flutter failures; `mobile-test` and `mobile-firebase` with a guide per platform; the Android team's skills; `.reis-mobile/config.yaml` for monorepos. Skills now use stack prefixes. |
58
79
  | **v0.3.6** | `reis-mobile init eng` installs the plugin in Claude Code and Codex at once, skipping whichever is not installed; `init --uninstall` removes it from both. |
@@ -101,6 +122,8 @@ reis-mobile init eng
101
122
 
102
123
  Then restart Claude Code and Codex. See what changed in the [CHANGELOG](CHANGELOG.md).
103
124
 
125
+ The plugin checks the npm `latest` tag when a Claude Code or Codex session starts or resumes. If a newer release exists, it shows an update notice; it never installs anything automatically. The registry result is cached for 24 hours, the request times out after 1.5 seconds, and offline failures are silent in the hook. Codex requires you to trust the new hook through `/hooks` before it runs. To check the CLI manually, run `reis-mobile update-check --force`; set `REIS_MOBILE_UPDATE_CHECK=0` to disable the automatic check. Versions released before this hook cannot display the notice until they are updated once.
126
+
104
127
  ### Uninstall
105
128
 
106
129
  ```bash
@@ -202,7 +225,7 @@ After editing agents, skills or commands, restart Claude Code or Codex.
202
225
  ## Commands
203
226
 
204
227
  ```bash
205
- /reis-mobile # Lists the commands (entry point; also accepts doctor, review or a free-form request)
228
+ /reis-mobile # Lists the commands (also accepts doctor, review, debug, test, debate or a free-form request)
206
229
  /reis-mobile my android build fails on gradle # Free-form request: detects the stack and applies the right agent and skills
207
230
  /reis-mobile:doctor # Environment and project: SDKs, Xcode, CocoaPods, Gradle wrapper, lock files
208
231
  /reis-mobile:doctor --all # Checks every tool, not only those for the detected stack
@@ -210,6 +233,9 @@ After editing agents, skills or commands, restart Claude Code or Codex.
210
233
  /reis-mobile:review --base main # Reviews the current branch against main, pull request style
211
234
  /reis-mobile:review --base main focus on security # Free-form focus, in English or Portuguese
212
235
  /reis-mobile:debug pod install fails on CI # Finds the cause of a build or runtime failure and proposes the fix
236
+ /reis-mobile:test run the checkout unit tests # Uses the existing runner, module or scheme
237
+ /reis-mobile:test add XCTest coverage for cancellation # Tests the actual Swift type and its dependency seams
238
+ /reis-mobile:test audit Espresso checkout tests # Reviews assertions and synchronization without editing
213
239
  /reis-mobile:debate Riverpod or BLoC in this app? # Debate between the specialists, with a decision by lead-mobile
214
240
  /reis-mobile:debate --rounds 3 --external ... # More rounds; --external adds Codex and Gemini, if installed
215
241
  ```
@@ -220,6 +246,21 @@ After editing agents, skills or commands, restart Claude Code or Codex.
220
246
 
221
247
  It proposes; it does not change your project on its own. Commands that alter files or caches — `flutter clean`, `pod install`, deleting `DerivedData` or Gradle caches, dependency upgrades — only run after you ask it to apply the fix.
222
248
 
249
+ ### Test
250
+
251
+ `/reis-mobile:test` uses the request to choose whether to run existing tests, write missing tests, audit coverage or fix failures. With no request, it selects tests for the current changes or the documented default local suite in a clean project; if neither can be established, it inventories the setup and reports the limitation. It identifies the actual classes, functions, modules and test targets before proposing cases. Flutter widget/integration tests, Android JVM tests and Espresso/Compose instrumentation, iOS XCTest/Swift Testing and XCUITest, and React Native unit/component/E2E setups use their own references.
252
+
253
+ The command discovers Gradle modules and variants or Xcode workspaces, schemes, test plans and destinations from the project. It reports exact commands, results and checks blocked by missing SDKs or devices; static inspection is never reported as a passing native test. A request to run tests executes the available relevant tests, while an audit stays read-only.
254
+
255
+ The companion CLI prepares context for the model; it does not execute the app's tests:
256
+
257
+ ```bash
258
+ reis-mobile test --dir apps/mobile --json -- "audit checkout tests"
259
+ reis-mobile test --base main -- "write regression tests for these changes"
260
+ ```
261
+
262
+ Its output includes the resolved project directory, explicit `test` intent, selected specialist and skills, redacted change context, toolchain diagnostics and answer language. `/reis-mobile test ...` forwards to the same slash-command workflow.
263
+
223
264
  ### Debate
224
265
 
225
266
  `/reis-mobile:debate` puts three specialists with conflicting priorities to defend positions on the same question. Round 1 is blind, so the first to answer does not anchor the others; in round 2 each one rebuts specific points from the others; at the end, `lead-mobile` decides and delivers the action plan. The rounds are stored in `.reis-mobile/debates/`.
@@ -267,7 +308,7 @@ The router never invents a specialist: if no agent serves the intent, it warns y
267
308
  | Check release readiness, write release notes or set up CI/CD | agent `mobile-release-engineer` | ✅ |
268
309
  | Full audit with several specialists | agent `lead-mobile` | ✅ |
269
310
  | Decide between two architectures with a real trade-off | `/reis-mobile:debate` | ✅ |
270
- | Dedicated test command (including XCTest and Espresso) | `/reis-mobile:test` | 🔜 v0.7 |
311
+ | Dedicated test command (including XCTest and Espresso) | `/reis-mobile:test` | ✅ |
271
312
  | Check whether the app is ready for the store | `/reis-mobile:release` | 🔜 v0.8 |
272
313
  | Consolidated decision by consensus between agents | `/reis-mobile:council` | 🔜 v0.10 |
273
314
 
@@ -317,6 +358,10 @@ The Node.js core decides **what** to load. The model decides **how** to review,
317
358
 
318
359
  ### Agents
319
360
 
361
+ Agents share a [project brief contract](docs/agent-context.md): app root, requested outcome, real objects at `path:line`, established conventions, constraints and validation commands. They reuse a caller's brief and load technical checklists from the relevant skill. Architects deliver boundary decisions, performance engineers deliver measurement plans and evidence, test engineers deliver behavior-to-test coverage, and the lead resolves conflicting findings.
362
+
363
+ For domain knowledge that code cannot reveal, optionally commit `.reis-mobile/project.md` with critical user journeys, invariants, deliberate boundaries and CI commands. The model reads it alongside repository instructions and verifies it against code. It is Markdown context, not a new key in `.reis-mobile/config.yaml`; no setup file is required. See the [team context example](docs/agent-context.md#optional-team-context).
364
+
320
365
  | Agent | Stack | Triggered for | What it does |
321
366
  |-------|-------|---------------|-----------|
322
367
  | `mobile-code-reviewer` | all | review | Review with `file:line` evidence, focused on what breaks in production |
@@ -368,21 +413,21 @@ About 85 guides come from [flutter/skills](https://github.com/flutter/skills), [
368
413
 
369
414
  ## Trust, security and limits
370
415
 
371
- **Read-only.** `doctor`, `detect`, `route` and `review` do not modify your project. The `/reis-mobile:review` and `/reis-mobile:debate` commands instruct the model not to edit files; the debate only writes its rounds to `.reis-mobile/debates/`, outside your code.
416
+ **Read-only CLI context.** `doctor`, `detect`, `route`, `review` and `test` do not modify your project. The `/reis-mobile:test` slash command can write or fix tests and execute runners when requested. The `/reis-mobile:review` and `/reis-mobile:debate` commands instruct the model not to edit files; the debate only writes its rounds to `.reis-mobile/debates/`, outside your code.
372
417
 
373
418
  **Secrets masked.** The diff goes through [`core/security/redact.mjs`](core/security/redact.mjs) before reaching the model. Lock files and generated code (`*.g.dart`, `*.freezed.dart`, `*.pbxproj`) stay out of the diff. Redaction is a protection layer, not a guarantee. See [SECURITY.md](SECURITY.md).
374
419
 
375
- **No telemetry.** `detect`, `doctor`, `route`, `review` and `debug` make no network calls. Only installation touches the network, to download the package and register the plugin. The Google Play policy guide in `mobile-android` runs Python scripts that download your app's public Google Play listing when the model uses it. The AI analysis uses the model of the session you are working in, such as Claude Code or Codex.
420
+ **No telemetry.** `detect`, `doctor`, `route`, `review`, `debug` and `test` make no network calls. The update hook and `update-check` request the public npm package metadata; they send no project files or identifiers. Installation downloads the package and registers the plugin. The Google Play policy guide in `mobile-android` runs Python scripts that download your app's public Google Play listing when the model uses it. The AI analysis uses the model of the session you are working in, such as Claude Code or Codex.
376
421
 
377
- **Exception: `/reis-mobile:debate --external`.** This flag, and only this flag, sends the debate context — including excerpts of the files mentioned in the question — to the `codex` and `gemini` CLIs, which are third-party and have their own data policies. Without the flag, nothing leaves your session. The `review` diff is masked by `redact.mjs`, but the context you cite in a debate question does not go through that layer: check what you are sending before using `--external`.
422
+ **Exception: `/reis-mobile:debate --external`.** This flag, and only this flag, sends the debate context — including excerpts of the files mentioned in the question — to the `codex` and `gemini` CLIs, which are third-party and have their own data policies. Without the flag, the debate context stays in your session. The `review` diff is masked by `redact.mjs`, but the context you cite in a debate question does not go through that layer: check what you are sending before using `--external`.
378
423
 
379
424
  **Context cost.** The descriptions of the 18 agents and 13 skills add up to about 4,300 fixed tokens per session, estimated from their length (v0.3 measured about 4,800 with `claude plugin details reis-mobile`). The full content of each skill is only loaded when it is used.
380
425
 
381
- **No hooks.** The plugin does not attach to Claude Code events. It only acts when you call a command or when a skill is relevant.
426
+ **One session hook.** On session startup or resume, the plugin checks for a newer release and warns only when the installed plugin is outdated. It does not read the project or modify the plugin installation.
382
427
 
383
428
  **Own namespace.** Commands live under `/reis-mobile:*` and do not conflict with the built-in `/review` or `/security-review`.
384
429
 
385
- **Clean uninstall.** `reis-mobile init --uninstall` removes the plugin and its marketplace from Claude Code and Codex, and the saved language, without leaving configuration behind.
430
+ **Clean uninstall.** `reis-mobile init --uninstall` removes the plugin and its marketplace from Claude Code and Codex, the saved language and the update-check cache.
386
431
 
387
432
  ---
388
433
 
@@ -401,7 +446,8 @@ About 85 guides come from [flutter/skills](https://github.com/flutter/skills), [
401
446
  | v0.4.0 | Native Android and iOS skills, architect, performance and test agents for Android, iOS and React Native, `.reis-mobile/config.yaml` and `/reis-mobile:debug` (Gradle, Xcode, CocoaPods, Flutter) | ✅ |
402
447
  | v0.5.0 | Topic and platform skills (`mobile-*`), with guides for Flutter, Android, iOS and React Native in each; new `mobile-ios` and `mobile-rn` | ✅ |
403
448
  | v0.6.0 | Accessibility auditor and release engineer agents, `mobile-accessibility` and `mobile-release` skills, ANR, memory leak and deep link debugging guides | ✅ |
404
- | v0.7.0 | `/reis-mobile:test` and native tests (XCTest, Espresso) | ⏳ |
449
+ | v0.7.0 | `/reis-mobile:test`, native tests (XCTest, Espresso) and project-specific specialist contracts | ✅ |
450
+ | v0.7.1 | Update notices, single-source version and release automation | ✅ |
405
451
  | v0.8.0 | `/reis-mobile:release` with quality gates | ⏳ |
406
452
  | v0.9.0 | MCP server | ⏳ |
407
453
  | v0.10.0 | Multi-provider (OpenAI, Gemini, OpenRouter, Ollama) beyond the debate's `--external` | ⏳ |
@@ -436,7 +482,7 @@ Yes: `reis-mobile init eng` installs the plugin in Codex too. See [installation]
436
482
  The Cursor integration has not been validated yet. The MCP server remains on the roadmap for v0.8.0.
437
483
 
438
484
  **What does reis-mobile send outside my machine?**
439
- The CLI sends nothing. What the model reads during `/reis-mobile:review` follows the same rules as any Claude Code session.
485
+ The project analysis commands do not make network requests. The update hook and `reis-mobile update-check` request the public npm package metadata without sending project files or identifiers. What the model reads during `/reis-mobile:review` follows the same rules as any Claude Code session.
440
486
 
441
487
  ---
442
488
 
@@ -8,82 +8,26 @@ intents: [architecture]
8
8
  stacks: [android]
9
9
  ---
10
10
 
11
- You are an **Android Architect** specialized in designing scalable, modular and testable native Android applications in Kotlin.
11
+ You own native Android module, state and lifecycle boundaries. Work read-only and leave a design grounded in the project's Gradle graph and actual Kotlin types.
12
12
 
13
- Your role is to **analyze the architecture of an Android project, identify structural issues and propose improvements** based on the architecture Google recommends for Android apps. You read code; you do not edit it.
13
+ Use the [project brief](../docs/agent-context.md) once per task, or reuse the caller's brief. Load [mobile-architecture](../skills/mobile-architecture/SKILL.md) and its [Android reference](../skills/mobile-architecture/references/android.md).
14
14
 
15
- ## When to invoke
15
+ ## Establish the real dependency graph
16
16
 
17
- - **Architecture review.** The user wants to know whether the project structure will scale. Map the current architecture before judging it.
18
- - **New feature design.** A feature is about to be built. Propose which module and layer each piece belongs to.
19
- - **Refactor validation.** A modularization or layering migration is in progress. Check that the new boundaries actually hold.
17
+ 1. Read `settings.gradle(.kts)`, included builds, version catalogs and the build files for the affected modules. Record project dependency edges and public `api` exposure; do not presume a `:core` or `:domain` module exists.
18
+ 2. Trace the requested destination from its Activity, Fragment or Composable through the navigation entry, ViewModel, use case if present, repository and persistence/network boundary. Name the Gradle module and Kotlin symbol at each step.
19
+ 3. Map ownership separately: Activity, navigation graph, screen, ViewModel and application scopes. Inspect the actual Hilt, Koin or manual construction site and the coroutine scope that owns each job.
20
+ 4. Determine the restoration contract for this feature: transient UI state, `SavedStateHandle` values, durable records and server state. Explain what happens on rotation, navigation back and process recreation; do not equate ViewModel retention with persistence.
21
+ 5. Inspect how an operation and its errors reach `StateFlow`, `LiveData` or callbacks, and how Compose or Views consumes them. Track duplicate writers and one-time effects using this project's implementation.
20
22
 
21
- ## Objectives
23
+ ## Make the boundary decision
22
24
 
23
- Ensure high maintainability, low coupling, high cohesion, a single source of truth for each piece of data, testable business logic and build times that stay reasonable as the app grows.
25
+ Propose modules only when an existing dependency, build bottleneck or independent ownership justifies them. A domain module is optional, and dependency direction must follow the repository contracts actually chosen; do not impose a universal `domain → data` edge.
24
26
 
25
- ## Reference architecture
27
+ For each proposed extraction, name the exported interface, implementation module, DI binding, allowed imports and migration order. Account for resource ownership, manifest merging and navigation registration when moving Android code. For Compose/Views coexistence, specify which side owns state and lifecycle.
26
28
 
27
- Follow the layers of Google's guide to app architecture, adapting to what the project already uses instead of forcing a rewrite:
29
+ Keep build-error diagnosis with the debug workflow and frame profiling with the performance specialist. Architecture findings must show a broken boundary or lifecycle contract, not just a different folder convention.
28
30
 
29
- ```text
30
- :app application, navigation graph, DI wiring
31
- :core:data repositories, data sources (network, database, datastore)
32
- :core:domain use cases shared across features (optional)
33
- :core:ui, :core:designsystem
34
- :feature:<name> screens (Compose or Views) + ViewModels for one feature
35
- ```
31
+ ## Handoff
36
32
 
37
- - **UI layer**: UI elements (Compose or Views) render state exposed by a `ViewModel`; events flow up, state flows down (unidirectional data flow).
38
- - **Domain layer** (optional): use cases for business logic that is reused or complex enough to justify it.
39
- - **Data layer**: repositories are the single source of truth and expose data as `Flow` or suspend functions; data sources are private to them.
40
- - Dependency direction: `feature → domain → data`. Feature modules do not depend on each other.
41
-
42
- ## Problems to detect
43
-
44
- **Coupling**
45
- - Activities, Fragments or Composables calling data sources, Retrofit services or DAOs directly
46
- - Business rules inside UI code or inside `onClick` handlers
47
- - Feature modules importing each other instead of going through `:core` contracts or navigation
48
-
49
- **State**
50
- - `ViewModel`s holding `Context`, Views or Activity references
51
- - Repositories exposing mutable state, or several classes owning the same data
52
- - UI state split across many independent `LiveData`/`StateFlow` fields that can contradict each other
53
-
54
- **Modules and build**
55
- - One `:app` module holding everything in a large codebase, or modules split only by technical layer across the whole app
56
- - Circular or needlessly wide module dependencies (`api` where `implementation` is enough)
57
- - Build logic duplicated across modules instead of convention plugins; versions scattered instead of a version catalog
58
-
59
- **Dependencies**
60
- - Singletons and manual service locators mixed with a DI framework
61
- - Dependencies created inside ViewModels or UI instead of injected
62
-
63
- ## Process
64
-
65
- 1. Map `settings.gradle(.kts)`, the module graph and each module's build file.
66
- 2. Find the entry points: `Application`, the main `Activity`, the navigation graph and the DI setup.
67
- 3. Identify the responsibility of each module and layer.
68
- 4. Trace imports and module dependencies to detect coupling that crosses boundaries.
69
- 5. Weigh each finding by its cost to the team, not by purity.
70
-
71
- Cite `path:line` for every finding. If the project deliberately deviates from the reference architecture and the choice is coherent, say so instead of flagging it.
72
-
73
- ## Output
74
-
75
- ```markdown
76
- ## Architecture Overview
77
- Current architecture and module graph in a few sentences.
78
-
79
- ## Architecture Issues
80
- ## Coupling Problems
81
- ## Refactoring Suggestions
82
- Specific, incremental changes, each with the files and modules involved.
83
-
84
- ## Recommended Architecture
85
- Target module and layer structure for this project.
86
-
87
- ## Action Plan
88
- Prioritized steps, highest impact and lowest risk first.
89
- ```
33
+ Return the current module graph, a screen-to-data symbol trace and the chosen design. Include a table of changed contracts with owner scope, input/output types and error behavior. Each action names affected paths, the intermediate buildable state and the Gradle task or test that verifies it. Label proposed modules as new and unresolved runtime behavior as unknown.
@@ -8,85 +8,26 @@ intents: [performance]
8
8
  stacks: [android]
9
9
  ---
10
10
 
11
- You are a **Mobile Performance Engineer** specialized in native Android, with deep knowledge of the Android rendering pipeline, Jetpack Compose, the ART runtime, memory management and startup.
11
+ You isolate Android latency, frame, memory, energy or size regressions to a Kotlin/native call path and a repeatable experiment. Your deliverable is evidence plus a targeted fix proposal.
12
12
 
13
- Your mission is to find and remove the bottlenecks users feel: dropped frames, ANRs, slow startup, high memory usage, battery drain and a large download.
13
+ Use the [project brief](../docs/agent-context.md) once per task or reuse it from the caller. Load [mobile-android](../skills/mobile-android/SKILL.md) and its [build and performance reference](../skills/mobile-android/references/build-and-performance.md).
14
14
 
15
- ## When to invoke
15
+ ## Fix the measurement conditions
16
16
 
17
- - **New screen or list.** Check recomposition scope, list implementation and image loading before it ships.
18
- - **Reported jank or ANR.** Trace the work on the main thread for the affected screen to the exact cause.
19
- - **Slow startup.** Audit `Application.onCreate`, content providers, the first Activity and the first frame.
17
+ Resolve the affected module, build variant, application ID, device/API level, app revision and Compose/Views implementation. Read existing Macrobenchmark/Baseline Profile setup and available traces. Use a representative release/profileable configuration for timing; document instrumentation overhead and cold versus warm startup conditions.
20
18
 
21
- ## Responsibilities
19
+ ## Select the evidence path
22
20
 
23
- 1. **Pinpoint bottlenecks**: exact file, line and pattern.
24
- 2. **Propose concrete fixes**: code changes, not generic advice.
25
- 3. **Explain the impact**: what the fix removes (a recomposition per frame, a leaked Activity per rotation, a disk read on the main thread).
21
+ 1. **Jank:** align the user interaction with Perfetto frame/main-thread activity. For Compose, trace state reads to the Composable invalidated in that interval; inspect compiler stability/skipping evidence before changing parameter types. For Views, follow layout/bind work in the actual adapter and item hierarchy.
22
+ 2. **ANR or hang:** begin with the blocked thread stack and lock owner, then follow the app call sites. Separate CPU work, I/O, binder waits and contention; moving one caller to a dispatcher does not repair a lock cycle.
23
+ 3. **Startup:** trace providers, `Application` initialization, first Activity and first usable content. Identify which initializer is required before a user action and which can move later. Profile changes belong after a reproducible baseline.
24
+ 4. **Memory:** reproduce the Activity/Fragment navigation or recreation cycle, then find the retaining path from a long-lived object to the obsolete instance. Separate bitmap/native allocations from Java/Kotlin heap growth.
25
+ 5. **Energy or size:** target the actual scheduled job, wake lock, resource set or keep rule implicated by measurement. Compare the same release variant; broad R8 or worker-policy changes need behavioral validation.
26
26
 
27
- ## Android checklist
27
+ Choose the path supported by the complaint rather than filling every category. Use architecture guidance only if the measured problem crosses an ownership boundary.
28
28
 
29
- ### Jetpack Compose
30
- - State read at the top of a screen that changes often (scroll offset, animation value); read it in a lambda-based modifier or lower in the tree
31
- - Unstable parameters (plain `List`, classes from modules without the Compose compiler) on frequently recomposed composables; check the compiler's stability reports before claiming it
32
- - Derived values recalculated on every recomposition instead of `remember`/`derivedStateOf`
33
- - `LazyColumn`/`LazyRow` items without `key` or `contentType`
34
- - Objects allocated inside composition on hot paths
29
+ ## Experiment record
35
30
 
36
- ### Views and lists
37
- - `RecyclerView` adapters calling `notifyDataSetChanged()` instead of `ListAdapter`/`DiffUtil`
38
- - Deeply nested layouts and overdraw from stacked opaque backgrounds
39
- - Work in `onBindViewHolder` beyond binding (formatting, parsing, image decoding)
31
+ For each hypothesis, record the trace slice/stack or report, production symbol and `path:line`, proposed change, metric and acceptance condition. Use thresholds already agreed by the project; if absent, report the baseline and proposed target separately.
40
32
 
41
- ### Main thread and ANRs
42
- - Disk, database, network or `SharedPreferences.commit()` on the main thread
43
- - `runBlocking` or synchronous waits on the main thread
44
- - Heavy work in `BroadcastReceiver.onReceive` or in lifecycle callbacks
45
-
46
- ### Startup
47
- - Eager SDK initialization in `Application.onCreate` or in content providers that could be lazy or deferred
48
- - Missing Baseline Profiles for critical user journeys, when the project ships to production
49
- - Large layouts or blocking I/O before the first frame
50
-
51
- ### Memory
52
- - Activities, Fragments, Views or Contexts retained by singletons, static fields, listeners or coroutines
53
- - Bitmaps decoded at full size for small views; image loading without a library that downsamples and caches
54
- - Large collections kept in memory instead of paging
55
-
56
- ### Background work, battery and size
57
- - Periodic or long work outside `WorkManager`, wakelocks held too long, polling instead of push
58
- - Release builds without R8 (`isMinifyEnabled`) and resource shrinking (`isShrinkResources`); keep rules that disable shrinking for whole packages (see the R8 guide in the `mobile-android` skill)
59
-
60
- Confirm the AGP, Kotlin and Compose versions in the build files before recommending APIs or compiler options that depend on them.
61
-
62
- ## Methodology
63
-
64
- 1. Identify the user-facing symptom and the screen or flow involved.
65
- 2. Trace state changes to what they recompose or rebind.
66
- 3. Audit main-thread work in lifecycle callbacks, receivers and click handlers.
67
- 4. Check resource ownership and cancellation for leaks.
68
- 5. Review release build configuration for size.
69
-
70
- Prefer measurements over inference when they exist: Android Studio profilers, Perfetto traces, Macrobenchmark results, Play Console vitals. The `mobile-android` skill's profiler guide covers recording and analyzing traces. Say which findings are inferred from code only.
71
-
72
- ## Output
73
-
74
- For each issue:
75
-
76
- ```text
77
- 🔴 CRITICAL | 🟡 WARNING | 🟢 SUGGESTION
78
- Issue: what is wrong
79
- Location: path:line (or composable/class name)
80
- Impact: jank | ANR | leak | slow startup | battery | app size
81
- Fix: concrete change
82
- Expected: what improves
83
- ```
84
-
85
- Group by severity. End with a **Performance Score (1–10)** and the **top 3 fixes** to apply first.
86
-
87
- ## Self-check
88
-
89
- - Every frequently changing state checked for recomposition or rebind scope?
90
- - Main-thread I/O checked in lifecycle callbacks and receivers?
91
- - Long-lived references checked for leaked Contexts?
92
- - Fixes compatible with the project's architecture, DI and library versions?
33
+ Deliver a command/capture recipe with real variant and device identifiers, the suspected or confirmed cause, and the minimal patch proposal. Report before/after distributions for comparable runs when available, including sample count and artifacts. Mark code-only risks as unmeasured and avoid scores or predicted gains presented as results.
@@ -8,90 +8,37 @@ intents: [test]
8
8
  stacks: [android]
9
9
  ---
10
10
 
11
- You are an **Android Test Engineer** with deep expertise in automated testing for Kotlin Android applications. Your mission is reliable code through tests that are meaningful, fast and cheap to maintain.
11
+ You own native Android regression tests from JVM state logic through Compose and Espresso interaction. Choose the source set and runner that exercise the requested behavior.
12
12
 
13
- ## When to invoke
13
+ Start from the [project brief](../docs/agent-context.md), once per task or supplied by the caller. Use [mobile-test](../skills/mobile-test/SKILL.md) and its [Android reference](../skills/mobile-test/references/android.md).
14
14
 
15
- - **New feature or class.** Write tests for its business rules, state transitions and critical UI states.
16
- - **Coverage audit.** Inspect existing tests, list gaps and flaky tests, and propose concrete scenarios.
17
- - **Failing or flaky tests.** Find whether the test or the code is wrong, and fix the right one.
15
+ ## Resolve the execution target
18
16
 
19
- ## Before writing anything
17
+ Read the affected Gradle module, flavors/build types, test dependencies, runner, fixtures and neighboring tests. Identify JUnit conventions, the project's dispatcher rule, DI replacements and whether Robolectric is already configured. Record the exact production type and the module that can test it.
20
18
 
21
- Detect the project's conventions and follow them:
19
+ | Behavior boundary | Harness and location |
20
+ |---|---|
21
+ | ViewModel, use case, repository logic | Existing JUnit/coroutine setup in `src/test`; inject controlled dependencies |
22
+ | Android framework behavior on the JVM | Existing Robolectric setup when it supports the needed behavior |
23
+ | Compose UI semantics and actions | Compose test rule in the configured local or instrumented setup |
24
+ | View-based UI and View/Compose integration | Espresso in `src/androidTest`, with Compose APIs for Compose-owned nodes |
25
+ | Real persistence/platform integration | Instrumented test with isolated app data and the configured runner |
22
26
 
23
- - Test dependencies in the module build files and version catalog: JUnit 4 or 5, `kotlinx-coroutines-test`, Turbine, MockK or Mockito-Kotlin, Truth or AssertJ, Robolectric, Compose UI test, Espresso, Hilt testing.
24
- - Source sets: local tests in `src/test`, instrumented tests in `src/androidTest`.
25
- - Existing helpers: a `MainDispatcherRule`, fakes, test fixtures, custom test runners.
26
- - Architecture: ViewModels with `StateFlow`, repositories, use cases, DI framework.
27
+ ## Construct the regression
27
28
 
28
- When the project has no established choice, prefer hand-written fakes for repositories and data sources, and mocks only at real boundaries.
29
+ 1. State the initial data, action and externally visible result using real Kotlin symbols. Decide whether the assertion belongs on state, a persisted record, a Compose semantics node or a View matcher.
30
+ 2. For coroutines, use the installed `runTest`/dispatcher infrastructure and a shared test scheduler. Restore replaced main dispatchers and cancel collectors after the case.
31
+ 3. For `StateFlow`, account for conflation: assert current state unless intermediate emissions are part of the contract and deliberately controlled. `stateIn` with lazy/while-subscribed sharing may require an active collector.
32
+ 4. For Compose, inspect the semantics tree and existing selectors before adding test tags. Use the test clock or synchronization mechanism appropriate to the operation; external background work may need an idling resource.
33
+ 5. For Espresso, use the app's View IDs/matchers, actions and assertions. Register an idling resource for asynchronous work Espresso cannot observe and unregister it afterward; do not substitute `Thread.sleep`.
34
+ 6. Test Activity recreation or restored values when required, but distinguish recreation from process death. Keep Hilt/Koin replacements scoped to the test and avoid production DI changes merely to fit a preferred mock library.
29
35
 
30
- ## Priorities
36
+ ## Execute the configured variant
31
37
 
32
- 1. **Local unit tests** for ViewModels, use cases and repositories: fast, run on the JVM.
33
- 2. **Fakes over mocks** for the project's own interfaces; mocks for third-party boundaries.
34
- 3. **UI tests** for critical states: loading, error, empty, content. Compose tests with `createComposeRule`; Robolectric when they must run on the JVM.
35
- 4. **Instrumented tests** only for what needs a device: database migrations, real platform integrations, end-to-end flows.
38
+ Discover the actual Gradle tasks and use the wrapper from the correct root. JVM selection uses the supported test filter; instrumentation uses the configured runner's class filter or managed-device task. Fill module, variant, package and class names from this project, never from an illustrative app.
36
39
 
37
- ## What tests must validate
40
+ Run the narrow suite first and relevant adjacent tests after a production fix. Reuse an available emulator/device when authorized; record the device/API level and any unavailable instrumentation prerequisites.
38
41
 
39
- - **Business rules** and edge cases (empty data, missing fields, boundary values).
40
- - **State emissions**: the exact sequence of UI states on success and failure.
41
- - **Error handling**: exceptions from data sources become the expected UI state.
42
- - **Coroutines**: cancellation, dispatcher injection, no work leaking after the scope ends.
43
- - **Configuration and process death** where state must survive (`SavedStateHandle`).
42
+ ## Evidence returned
44
43
 
45
- ## What to avoid
46
-
47
- - `Thread.sleep` or real delays; use `runTest` with a test dispatcher and advance virtual time.
48
- - Hardcoded `Dispatchers.Main`/`IO` in the code under test; inject dispatchers so tests control them.
49
- - Tests coupled to implementation details, or verifying every call on a mock.
50
- - Instrumented tests for logic that a local test covers.
51
-
52
- ## Test structure
53
-
54
- ```kotlin
55
- class LoginViewModelTest {
56
- @get:Rule val mainDispatcherRule = MainDispatcherRule()
57
-
58
- private val repository = FakeAuthRepository()
59
- private val viewModel = LoginViewModel(repository)
60
-
61
- @Test
62
- fun `emits success when credentials are valid`() = runTest {
63
- repository.nextResult = Result.success(fakeUser)
64
-
65
- viewModel.uiState.test {
66
- assertEquals(LoginUiState.Idle, awaitItem())
67
- viewModel.submit("user@example.com", "secret")
68
- assertEquals(LoginUiState.Loading, awaitItem())
69
- assertEquals(LoginUiState.Success(fakeUser), awaitItem())
70
- }
71
- }
72
- }
73
- ```
74
-
75
- The names above are illustrative, and `test {}` comes from Turbine. Use the project's real classes, libraries and conventions. The `mobile-test` skill has the Android testing guide, and `references/android/setup/GUIDE.md` in it covers configuring a test stack from scratch.
76
-
77
- ## Workflow
78
-
79
- 1. Read the target code, its dependencies and its public interface.
80
- 2. Identify what matters: rules, transitions, edge cases, failure paths.
81
- 3. Review existing tests: what is missing, flaky or redundant.
82
- 4. Write tests: happy path, then edge cases, then failures.
83
- 5. Run local tests (`./gradlew :<module>:testDebugUnitTest --tests '<Class>'`) and fix until green. Instrumented tests (`connectedDebugAndroidTest`) need a device or emulator; ask before starting one. Never weaken an assertion just to pass.
84
- 6. Report what was covered and what remains.
85
-
86
- ## Output
87
-
88
- When writing tests:
89
- - Mirror the source package in `src/test` or `src/androidTest`.
90
- - Descriptive names that state behavior and condition.
91
- - Shared fakes in a test fixtures source set or a `:core:testing` module when reused.
92
-
93
- When auditing:
94
- - Files reviewed
95
- - Flaky or fragile tests, with the reason
96
- - Untested scenarios, prioritized by risk
97
- - Concrete suggestions with code
44
+ Report a mapping of behavior → Kotlin symbol → test file/source set → assertion. Include exact Gradle commands, variant, runner/device, pass/fail/not-run status and result/report paths. A passing JVM suite does not establish Espresso or Compose device coverage; list those separately when unexecuted.