flg 1.2.0
flg: ^1.2.0 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 assistants like Claude Code for enhanced productivity.
Claude Code Skill #
When working in a project with flg installed, the /flg skill is available for quick command reference. The skill documentation is in .claude/skills/flg/SKILL.md.
MCP Server #
flg provides an MCP (Model Context Protocol) server for deeper AI assistant integration. This exposes flg functionality as tools that AI assistants can call directly.
Configuration
Add to your Claude Code MCP configuration (~/.claude.json or project settings):
{
"mcpServers": {
"flg": {
"command": "dart",
"args": ["run", "flg:flg_mcp"]
}
}
}
Or configure via CLI:
claude mcp add --scope user flg -- dart run flg:flg_mcp
Available MCP Tools
| Tool | Description |
|---|---|
flg_generate_feature |
Generate a complete feature module |
flg_generate_screen |
Generate a screen widget |
flg_generate_widget |
Generate a widget |
flg_generate_provider |
Generate provider/notifier/bloc |
flg_generate_usecase |
Generate use cases |
flg_generate_repository |
Generate repository |
flg_setup |
Setup flg in existing project |
flg_info |
Show project configuration |
Each tool accepts a path parameter to specify the Flutter project directory (defaults to current directory).
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: