SuperAPI AI Directory

mobile-flutter

Coding & development

View repository

Updated 10-15 22:41

About this skill

Mobile Flutter Stack

Cross-platform mobile app stack:

  • Flutter - UI framework (iOS, Android, macOS, Web)
  • Riverpod - State management (not Provider/ChangeNotifier)
  • go_router - Declarative routing with deep linking
  • dio - HTTP client with interceptors
  • storybook_toolkit - Component development with device frames

No code generation. Models use hand-written fromJson/toJson.

Optional: drift (local SQLite)

For offline-first apps that need a local relational database, add drift. This is the one exception to the no-codegen rule — drift generates typed query code from table definitions. See offline-first.md for setup and patterns.

Environment Setup

Use asdf to manage Flutter and all tool versions:

# Install Flutter plugin (one-time)
asdf plugin add flutter

# Set project Flutter version
asdf set flutter latest

# Also set support tools as needed
asdf set ruby latest
asdf set cocoapods latest
asdf set rust latest  # needed by some native deps

This creates a .tool-versions file in the project root. Never use the official Flutter installer, mise, or other version managers.

MCP Setup

If .mcp.json doesn't exist in the project root, create it with this content:

{
  "mcpServers": {
    "dart": {
      "type": "stdio",
      "command": "dart",
      "args": [
        "mcp-server"
      ],
      "env": {}
    }
  }
}

This wires up dart mcp-server so the agent can drive the app, inspect widgets, capture screenshots, and analyze files. See mcp-driving-and-screenshots.md for usage.

Reference Files

File When to Use
setup-guide.md Starting a new Flutter project from scratch
patterns.md Riverpod providers, repositories, screen architecture
offline-first.md Adding drift for local SQLite, offline download/collect/sync
storybook.md Setting up storybook, adding stories, mock data
gotchas.md Common mistakes and platform-specific issues
mcp-driving-and-screenshots.md Launching, driving (tap/type), debugging, and screenshotting a running app via the Dart MCP — and delivering screenshots to the user
mcp.json Sample .mcp.json for the project root — copy here if it doesn't exist

Companion Skills

This skill defines the stack; pair it with the foundational Dart & Flutter agent skills that apply to essentially any project on it. Install them into a project with npx skills (the agent is auto-detected, so -y runs non-interactively):

# Quality, testing & debugging foundations
npx skills add dart-lang/skills \
  -s dart-run-static-analysis \
  -s dart-add-unit-test \
  -s dart-fix-runtime-errors -y

npx skills add flutter/skills \
  -s flutter-apply-architecture-best-practices \
  -s flutter-add-widget-test \
  -s flutter-add-integration-test -y
Skill Why it's foundational
dart-run-static-analysis dart analyze + dart fix --apply — during dev and before every commit
dart-add-unit-test unit tests for logic with package:test
dart-fix-runtime-errors stack-trace → fix → hot_reload loop
flutter-apply-architecture-best-practices layered UI/logic/data structure (complements patterns.md)
flutter-add-widget-test component-level tests with WidgetTester
flutter-add-integration-test Flutter Driver / integration_test harness — pairs with mcp-driving-and-screenshots.md

Everything else is project-dependent — pick based on what the app actually does (JSON serialization, declarative routing, localization, responsive layout, HTTP, drift, coverage, mocks, pattern matching, …). Browse the full catalogs and --list to choose:

Quick Reference

Commands

# Install dependencies
flutter pub get

# Run on macOS (local dev)
flutter run -d macos

# Run storybook
flutter run -d macos -t lib/storybook/main.dart

# Run on web
flutter run -d chrome

# Analyze
flutter analyze lib/

Package Management

Always use CLI commands — never edit pubspec.yaml directly:

# Add runtime dependency
flutter pub add <package>

# Add dev dependency
flutter pub add --dev <package>

# Add from git
flutter pub add --dev storybook_toolkit --git-url https://github.com/org/repo.git --git-ref branch-name

Project Structure

├── lib/
│   ├── main.dart           # App entrypoint
│   ├── app.dart            # MaterialApp.router + GoRouter + theme
│   ├── models/             # Plain Dart classes with fromJson/toJson
│   ├── providers/          # Riverpod providers
│   ├── repositories/       # Abstract interfaces + implementations
│   ├── database/           # drift tables + generated code (if using drift)
│   ├── screens/            # One directory per route
│   ├── storybook/          # Storybook entrypoint + mock data
│   ├── widgets/            # Shared reusable widgets
│   └── constants/          # Theme, colors, typography
├── specs/                  # Feature specifications (if using spec-first)
├── .env                    # Environment config (gitignored)
├── .env.example            # Template
└── pubspec.yaml

Architecture Layers

Screens (widgets)        → read from providers, dispatch actions
Providers (Riverpod)     → async state, business logic
Repositories (abstract)  → data access boundary
API Client / Local DB    → external boundaries

Screens never call repositories directly — always through providers. Repositories are abstract interfaces with real and fake implementations. Fakes are injected via Riverpod provider overrides in storybook and tests.

Key Patterns

// Riverpod provider
final stationsProvider = FutureProvider<List<Station>>((ref) {
  return ref.watch(stationRepositoryProvider).getAll();
});

// Family provider (parameterized)
final stationProvider = FutureProvider.family<Station?, String>((ref, id) {
  return ref.watch(stationRepositoryProvider).get(id);
});

// Consumer widget
class MyScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final dataAsync = ref.watch(stationsProvider);
    return dataAsync.when(
      data: (stations) => ListView(...),
      loading: () => CircularProgressIndicator(),
      error: (e, _) => Text('Error: $e'),
    );
  }
}

// Navigation with go_router
context.push('/items/${item.id}');  // push onto stack
context.go('/login');               // replace stack

Common Gotchas

  • Package management: Use flutter pub add, never edit pubspec.yaml directly

  • VSCode SDK path: Use ~ not ${env:HOME} in .vscode/settings.json:

    {"dart.flutterSdkPath": "~/.asdf/installs/flutter/3.41.6-stable"}
    
  • macOS entitlements: Network requests need com.apple.security.network.client, keychain needs keychain-access-groups — both in macos/Runner/DebugProfile.entitlements and Release.entitlements

  • macOS signing: Set development team in Xcode (Runner target → Signing & Capabilities → Team → All configurations)

  • Commit generated code separately: After any command that generates/changes code, commit those changes with the exact command in the message BEFORE making manual edits