flg 1.2.2
flg: ^1.2.2 copied to clipboard
A CLI tool for generating Flutter projects with Clean Architecture, feature-first organization, and modern state management (Riverpod, Bloc, Provider).
flg #
Flutter Generator - A powerful CLI tool for generating Flutter projects with Clean Architecture, feature-first organization, and your choice of modern state management.
Inspired by Angular CLI, flg eliminates boilerplate and enforces architectural consistency across your Flutter projects.
Features #
| Feature | Description |
|---|---|
| Clean Architecture | Domain, Data, and Presentation layers with clear separation of concerns |
| Feature-First | Each feature is self-contained with all its layers |
| State Management | Riverpod (default), Bloc, or Provider |
| Routing | GoRouter (default) or AutoRoute with code generation |
| Freezed Integration | Immutable data classes with sealed class syntax |
| Code Generation | Automatic build_runner execution |
| Existing Projects | Set up flg in any existing Flutter project |
| AI Agent Workflows | Git worktree management for parallel AI agents |
Quick Start #
Installation #
# From pub.dev (recommended)
dart pub global activate flg
# Or from source
git clone https://github.com/saulram/flg.git
cd flg
dart pub global activate --source path .
Create a New Project #
# Interactive mode (recommended for first-time users)
flg init my_app
# Non-interactive with defaults
flg init my_app -s
# With specific options
flg init my_app --state riverpod --router go_router --org com.mycompany
Set Up an Existing Project #
cd my_existing_flutter_app
flg setup
Generate Components #
# Generate a feature
flg g f auth
# Generate a screen
flg g s login -f auth
# Generate a widget
flg g w user_avatar -f auth
# Generate CRUD use cases
flg g u user -f user --crud
# Generate a repository
flg g r user -f user
Commands #
flg init <project_name> #
Creates a new Flutter project with Clean Architecture.
| Option | Short | Description | Default |
|---|---|---|---|
--org |
-o |
Organization identifier (reverse domain) | com.example |
--state |
State management: riverpod, bloc, provider |
riverpod |
|
--router |
Router: go_router, auto_route |
go_router |
|
--freezed |
Use Freezed for data classes | true |
|
--dio |
Use Dio HTTP client | true |
|
--platforms |
-p |
Target platforms | android,ios |
--feature |
Initial feature name | home |
|
--skip-prompts |
-s |
Skip interactive prompts | false |
--dry-run |
Preview without creating files | false |
|
--verbose |
-v |
Show detailed output | false |
flg setup #
Configures flg in an existing Flutter project.
| Option | Short | Description | Default |
|---|---|---|---|
--state |
State management solution | riverpod |
|
--router |
Router solution | go_router |
|
--freezed |
Use Freezed | true |
|
--dio |
Use Dio | true |
|
--feature |
Initial feature name | (none) | |
--skip-deps |
Don't modify pubspec.yaml | false |
|
--skip-prompts |
-s |
Skip interactive prompts | false |
--force |
-f |
Reconfigure if flg.json exists | false |
--dry-run |
Preview without making changes | false |
flg generate <component> (alias: g) #
Generates code components within a flg project.
| Subcommand | Alias | Description |
|---|---|---|
feature |
f |
Complete feature module with all layers |
screen |
s |
Screen widget with routing setup |
widget |
w |
Widget (stateless, stateful, card, list_tile, form) |
provider |
p |
Provider/Notifier/Bloc based on state management |
usecase |
u |
Use case (single action or CRUD) |
repository |
r |
Repository interface and implementation |
Examples
# Feature with custom entity
flg g f product --entity product_item
# Stateful widget
flg g w product_form -f product -t stateful
# Form widget
flg g w checkout_form -f checkout -t form
# Single use case
flg g u authenticate -f auth -a create
# All CRUD use cases at once
flg g u product -f product --crud
flg task (alias: t) #
Manage git worktrees for AI agent workflows. Perfect for running multiple Claude Code, Cursor, or other AI agents in parallel on separate tasks.
| Subcommand | Alias | Description |
|---|---|---|
add |
Create a new task worktree with branch | |
list |
ls |
List all active task worktrees |
remove |
rm |
Remove a task worktree |
status |
st |
Show status of all task worktrees |
flg task add <name>
| Option | Short | Description | Default |
|---|---|---|---|
--type |
-t |
Branch prefix: feat, fix, ref |
feat |
--agent |
-a |
Setup for AI agent (pub get + .claude/TASK.md) | false |
--base |
-b |
Base branch to create from | main |
--dry-run |
Preview without creating | false |
Examples
# Create tasks for parallel AI agents
flg task add auth-feature --agent
flg task add fix-payment --type fix --agent
flg task add refactor-api --type ref --agent
# Check status of all tasks
flg task status
# List active worktrees
flg task list
# Remove when done
flg task remove auth-feature
Output Example
✓ Created task: feat-auth
→ Path: /Users/dev/my_app-tasks/feat-auth
→ Branch: feat/auth
✓ Running flutter pub get...
✓ Created .claude/TASK.md
Ready for AI Agent:
/Users/dev/my_app-tasks/feat-auth
Worktrees are created in ../[project-name]-tasks/ as sibling directories to your main project.
Project Structure #
After running flg init my_app, you get:
my_app/
├── lib/
│ ├── main.dart
│ ├── core/
│ │ ├── error/
│ │ │ ├── exceptions.dart
│ │ │ └── failures.dart
│ │ ├── usecases/
│ │ │ └── usecase.dart
│ │ ├── router/
│ │ │ └── app_router.dart
│ │ ├── network/
│ │ └── utils/
│ └── features/
│ └── home/
│ ├── domain/
│ │ ├── entities/
│ │ │ └── home_entity.dart
│ │ ├── repositories/
│ │ │ └── home_repository.dart
│ │ └── usecases/
│ ├── data/
│ │ ├── models/
│ │ │ └── home_model.dart
│ │ ├── repositories/
│ │ │ └── home_repository_impl.dart
│ │ └── datasources/
│ │ └── home_remote_datasource.dart
│ └── presentation/
│ ├── screens/
│ │ └── home_screen.dart
│ ├── widgets/
│ │ └── home_card.dart
│ └── providers/
│ ├── home_provider.dart
│ ├── home_provider.g.dart
│ ├── home_state.dart
│ └── home_state.freezed.dart
├── test/
│ ├── unit/
│ ├── integration/
│ └── fixtures/
├── pubspec.yaml
└── flg.json
State Management #
Riverpod (Default) #
Uses modern riverpod_annotation with code generation:
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'home_provider.g.dart';
@riverpod
class Home extends _$Home {
@override
HomeState build() => const HomeState();
Future<void> loadAll() async {
state = state.copyWith(isLoading: true);
final result = await _repository.getAll();
result.fold(
(failure) => state = state.copyWith(
isLoading: false,
errorMessage: failure.message,
),
(items) => state = state.copyWith(
isLoading: false,
homes: items,
),
);
}
}
This generates a provider named homeProvider (not homeNotifierProvider).
State classes use Freezed with sealed class:
@freezed
sealed class HomeState with _$HomeState {
const factory HomeState({
@Default([]) List<HomeEntity> homes,
HomeEntity? selectedHome,
@Default(false) bool isLoading,
String? errorMessage,
}) = _HomeState;
const HomeState._();
bool get hasError => errorMessage != null;
bool get isEmpty => homes.isEmpty;
}
Bloc #
Full Bloc pattern with events and states:
class HomeBloc extends Bloc<HomeEvent, HomeState> {
HomeBloc(this._repository) : super(const HomeInitial()) {
on<LoadHomesEvent>(_onLoadHomes);
}
final HomeRepository _repository;
Future<void> _onLoadHomes(LoadHomesEvent event, Emitter<HomeState> emit) async {
emit(const HomeLoading());
final result = await _repository.getAll();
result.fold(
(failure) => emit(HomeError(failure.message)),
(homes) => emit(HomeLoaded(homes)),
);
}
}
Provider #
Simple ChangeNotifier pattern:
class HomeProvider extends ChangeNotifier {
final HomeRepository _repository;
List<HomeEntity> _homes = [];
bool _isLoading = false;
String? _error;
Future<void> loadAll() async {
_isLoading = true;
notifyListeners();
final result = await _repository.getAll();
result.fold(
(failure) => _error = failure.message,
(homes) => _homes = homes,
);
_isLoading = false;
notifyListeners();
}
}
Configuration #
The flg.json file stores project configuration:
{
"projectName": "my_app",
"org": "com.example",
"stateManagement": "riverpod",
"router": "go_router",
"useFreezed": true,
"useDioClient": true,
"platforms": ["android", "ios"],
"features": ["home"],
"generateTests": true,
"l10n": false
}
This file is automatically created during init or setup and is used by generate commands to maintain consistency.
Architecture Overview #
flg generates code following Clean Architecture principles:
┌─────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ ┌─────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ Screens │ │ Widgets │ │ Providers/Blocs │ │
│ └─────────┘ └──────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Domain Layer │
│ ┌──────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ Entities │ │ Repository Intf. │ │ UseCases │ │
│ └──────────┘ └──────────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Data Layer │
│ ┌────────┐ ┌───────────────────┐ ┌───────────────┐ │
│ │ Models │ │ Repository Impl. │ │ DataSources │ │
│ └────────┘ └───────────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────┘
Key Patterns #
- Entities: Pure Dart classes representing business objects
- Repositories: Abstract interfaces in domain, implementations in data
- Use Cases: Single-responsibility classes for business logic
- Models: Data classes with JSON serialization (Freezed-based)
- DataSources: Handle external data (API, database, cache)
Known Limitations #
Current Limitations #
-
No test file generation: Test scaffolding is not yet implemented. The
test/directory structure is created but test files are not generated. -
No migration support: Upgrading configuration after
setuporinitrequires manual intervention. -
Single datasource per feature: Currently generates only remote datasources. Local caching datasources require manual implementation.
-
No DI container setup: Dependency injection setup (get_it, injectable) is not included. Repository injection in notifiers requires manual wiring.
Planned Features #
- ❌ Test file generation with mocking
- ❌ get_it / injectable integration
- ❌ Local datasource templates (Hive, SQLite)
- ❌ Migration command for config updates
- ❌ Custom template support
Troubleshooting #
build_runner fails #
If code generation fails after project creation:
# For Flutter projects
flutter pub run build_runner build --delete-conflicting-outputs
# Watch mode for development
flutter pub run build_runner watch --delete-conflicting-outputs
Riverpod provider not found #
Ensure you've run build_runner after adding new providers. The .g.dart files must be generated.
Import errors #
flg uses absolute package imports (package:my_app/...). If you rename your project, update the name field in pubspec.yaml and regenerate imports.
Requirements #
- Dart SDK: ^3.0.0
- Flutter (for generated projects): ^3.0.0
AI Assistant Integration #
flg integrates with AI coding assistants through the Model Context Protocol (MCP), enabling AI assistants to create Flutter projects and generate code directly.
Key Feature: When MCP is configured, asking your AI assistant to "create a Flutter project" will automatically use
flg initinstead offlutter create, giving you Clean Architecture from the start.
Supported AI Assistants #
| Assistant | MCP Support | Configuration |
|---|---|---|
| Claude Code | Yes | Global or per-project |
| Gemini CLI | Yes | Global or per-project |
MCP Configuration #
MCP servers can be configured globally (available in all projects) or per-project (only in specific projects).
Option 1: Global Configuration (Recommended)
Global configuration makes flg available in all your projects. Requires flg to be installed globally:
dart pub global activate flg
Claude Code:
# Using Claude CLI (easiest)
claude mcp add --scope user flg -- flg_mcp
Or manually edit ~/.claude/settings.json:
{
"mcpServers": {
"flg": {
"command": "flg_mcp"
}
}
}
Gemini CLI:
# Using Gemini CLI (easiest)
gemini mcp add --scope user flg -- flg_mcp
Or manually edit ~/.gemini/settings.json:
{
"mcpServers": {
"flg": {
"command": "flg_mcp"
}
}
}
Note: If
flg_mcpis not found, ensure Dart's pub cache bin is in your PATH:export PATH="$PATH:$HOME/.pub-cache/bin"
Option 2: Per-Project Configuration
Per-project configuration limits flg to specific projects. You can either use the global flg_mcp command or reference flg as a dev dependency.
Using global flg_mcp (simpler):
# Claude Code
claude mcp add --scope project flg -- flg_mcp
# Gemini CLI
gemini mcp add --scope project flg -- flg_mcp
Using flg as a dev dependency:
First add flg to your project:
dart pub add --dev flg
Then configure MCP:
Claude Code - Create .mcp.json in your project root:
{
"mcpServers": {
"flg": {
"command": "dart",
"args": ["run", "flg:flg_mcp"]
}
}
}
Gemini CLI - Create .gemini/settings.json in your project root:
{
"mcpServers": {
"flg": {
"command": "dart",
"args": ["run", "flg:flg_mcp"]
}
}
}
Configuration Precedence
When both global and per-project configurations exist:
- Per-project settings take precedence over global settings
- This allows you to override or disable specific MCP servers per project
Available MCP Tools #
Once configured, your AI assistant can use these tools:
| Tool | Description |
|---|---|
flg_init |
Create a new Flutter project with Clean Architecture (use instead of flutter create) |
flg_setup |
Setup flg in an existing Flutter project |
flg_generate_feature |
Generate a complete feature module with all layers |
flg_generate_screen |
Generate a screen widget |
flg_generate_widget |
Generate a widget (stateless, stateful, card, list_tile, form) |
flg_generate_provider |
Generate provider/notifier/bloc |
flg_generate_usecase |
Generate use cases (single or CRUD) |
flg_generate_repository |
Generate repository interface and implementation |
flg_info |
Show project configuration |
Each tool accepts a path parameter to specify the Flutter project directory (defaults to current directory).
Usage Examples #
Once MCP is configured, you can interact naturally with your AI assistant:
User: Create a new Flutter app called "todo_app" with Bloc
AI: [Uses flg_init to create the project with Clean Architecture and Bloc]
User: Generate an auth feature for my app
AI: [Uses flg_generate_feature to create the complete auth module]
User: Add a login screen to the auth feature
AI: [Uses flg_generate_screen to create login_screen.dart]
Verifying MCP Configuration #
Claude Code:
# List all configured MCP servers
claude mcp list
# Test the flg server
claude mcp run flg flg_info
Gemini CLI:
# List configured servers
gemini mcp list
# Check MCP server status
/mcp
Claude Code Skill (Alternative) #
In addition to MCP, flg provides a Claude Code skill for quick command reference. When working in a project with flg, the /flg skill is available. The skill documentation is in .claude/skills/flg/SKILL.md.
Contributing #
Contributions are welcome! Please see the GitHub repository for:
License #
MIT License - see LICENSE file for details.
Credits #
Created by Saul Ramirez
Inspired by: