# Jarvus Flutter

> Mobile app development using Flutter + Riverpod + go_router. Use when creating Flutter apps, adding screens, managing state with Riverpod, implementing routing, building offline-first features, or setting up storybook component development. Also use when the user mentions Flutter, Dart, mobile apps, or cross-platform development.

- Skill: `jarvusinnovations/jarvus-flutter` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add jarvusinnovations/jarvus-flutter`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jarvusinnovations/jarvus-flutter/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: JarvusInnovations (https://skillmd.com/u/jarvusinnovations)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/jarvusinnovations/jarvus-flutter

---


# 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](references/offline-first.md) for setup and patterns.

## Environment Setup

Use [asdf](https://asdf-vm.com/) to manage Flutter and all tool versions:

```bash
# 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:

```json
{
  "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](references/mcp-driving-and-screenshots.md) for usage.

## Reference Files

| File | When to Use |
|------|-------------|
| [setup-guide.md](references/setup-guide.md) | Starting a new Flutter project from scratch |
| [patterns.md](references/patterns.md) | Riverpod providers, repositories, screen architecture |
| [offline-first.md](references/offline-first.md) | Adding drift for local SQLite, offline download/collect/sync |
| [storybook.md](references/storybook.md) | Setting up storybook, adding stories, mock data |
| [gotchas.md](references/gotchas.md) | Common mistakes and platform-specific issues |
| [mcp-driving-and-screenshots.md](references/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](references/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):

```bash
# 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](references/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](references/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:

- **Dart:** <https://github.com/dart-lang/skills> — `npx skills add dart-lang/skills --list`
- **Flutter:** <https://github.com/flutter/skills> — `npx skills add flutter/skills --list`

## Quick Reference

### Commands

```bash
# 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:

```bash
# 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

```dart
// 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`:

  ```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

## CI & Code Quality

Wire analyze, format, and tests into CI from the start. The cross-cutting CI harness — asdf
provisioning + caching, path-filtered workflows, the `setup-asdf` composite — lives in the
**`ci-quality-gates`** skill; reuse it here. The *tools* differ from the TS/Python stacks:
Dart ships its own analyzer and formatter, so there's no oxc/ruff here.

**The gate (Dart-native):**

| Gate | Command |
|---|---|
| Lint / analyze | `flutter analyze lib/ test/` |
| Format check | `dart format --output=none --set-exit-if-changed lib/ test/` |
| Test | `flutter test` |

`flutter analyze` reads `analysis_options.yaml` — start from `package:flutter_lints` (and add
`riverpod_lint` only if it doesn't clash with `drift_dev`'s analyzer version; see
[gotchas.md](references/gotchas.md)). The companion `dart-run-static-analysis` skill (see
**Companion Skills** above) drives `dart analyze` + `dart fix --apply` locally — the same gate,
just in the dev loop.

**Provisioning.** Flutter is pinned in `.tool-versions` (plus ruby/cocoapods for iOS), so the
`setup-asdf` composite from `ci-quality-gates` provisions CI exactly as for the other stacks.
Commit `pubspec.lock` and use `flutter pub get` (it respects the lock). The credential-free,
path-filtered, IDE-over-pre-commit principles all carry over — only the tool commands change.

