Development protocol for mobile-dev agent working with Flutter (primary) and React Native (secondary). Covers project detection, architecture patterns, state management conventions, testing, and platform-specific guidelines. Automatically loaded by the mobile-dev agent.
From ennam-dev-agent-teamnpx claudepluginhub en-nam/ennam-claude-agent-team --plugin ennam-dev-agent-teamThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Executes pre-written implementation plans: critically reviews, follows bite-sized steps exactly, runs verifications, tracks progress with checkpoints, uses git worktrees, stops on blockers.
On task start, auto-detect the project type:
pubspec.yaml → Flutter projectpackage.json with react-native dependency → React Native projectBefore starting work on a new Flutter project:
pubspec.yaml dependencies:
flutter_riverpod or riverpod for state managementgo_router for routingflutter_test in dev_dependenciesintegration_test in dev_dependenciesanalysis_options.yaml for strict linting ruleslib/ for existing architecture patterns (feature-first, layer-first)Use Riverpod as the default state management solution:
// lib/features/products/presentation/providers/product_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
final productListProvider = FutureProvider.autoDispose<List<Product>>((ref) async {
final repository = ref.read(productRepositoryProvider);
return repository.getProducts();
});
Rules:
ConsumerWidget or ConsumerStatefulWidget (not StatelessWidget + Consumer)autoDispose for providers that should clean up when no longer listened toref.watch in build methods, ref.read in callbacks// lib/core/router/app_router.dart
final routerProvider = Provider<GoRouter>((ref) {
return GoRouter(
routes: [
GoRoute(path: '/', builder: (_, __) => const HomeScreen()),
GoRoute(path: '/products/:id', builder: (_, state) =>
ProductDetailScreen(id: state.pathParameters['id']!)),
],
);
});
const constructors when possibleKey for list items — ValueKey(item.id) for listsPlatform.isIOS / Platform.isAndroid for platform-specific behaviorLayoutBuilder or MediaQuery for adaptive layouts# Unit tests
flutter test test/unit/ --reporter=expanded
# Widget tests
flutter test test/widget/ --reporter=expanded
# Integration tests (requires device/emulator)
flutter test integration_test/ --reporter=expanded
# All tests
flutter test --reporter=expanded
Test structure:
test/
├── unit/
│ └── features/
│ └── products/
│ └── product_repository_test.dart
├── widget/
│ └── features/
│ └── products/
│ └── product_card_test.dart
└── helpers/
├── test_helper.dart
└── mocks.dart
# Quick analysis
dart analyze
# Format check
dart format --set-exit-if-changed lib/ test/
# Build Android (debug, fast)
flutter build apk --debug
# Build iOS (debug, fast — macOS only)
flutter build ios --debug --no-codesign
When working on a React Native project, adapt these patterns:
npx jest --passWithNoTests
npx react-native run-android
npx react-native run-ios
mobile/<task-id>-<short-description>
Examples:
mobile/task-010-product-listing-screenmobile/task-011-cart-providermobile/task-012-checkout-flowYou may ONLY modify:
lib/, android/, ios/, test/, integration_test/, pubspec.yaml, analysis_options.yamlsrc/, android/, ios/, __tests__/, package.json (dependencies only, with team-lead approval)NEVER modify shared types, backend code, or web frontend code.