Clean flutter
Some of my Agents & Skills, compatible with most AI coding tools
npx -y skills add uwuclxdy/agenticat --skill clean-flutterAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Clean, idiomatic Flutter/Dart conventions: feature-first architecture, Riverpod, freezed, go_router, const correctness. Use when writing or reviewing Dart, widgets, `BuildContext`, `build_runner`, or state management.
SKILL.md
6.2 KB, as published. Nobody here has run it
Clean Flutter
Flutter and Dart conventions for writing, reviewing, and refactoring. The core rules below always apply. Load the one reference file matching the task's domain; don't load them all.
If the clean-code skill is installed, its language-agnostic principles (function size, naming hygiene, comment discipline) still apply. Where generic advice conflicts with Flutter idiom, this skill wins: "replace switch with polymorphism" maps to exhaustive switch over a sealed class, which in Dart is the intended tool, not a smell.
| Task touches | File |
|---|---|
Project layout, MVVM layering, repository boundaries, Result | references/architecture.md |
Providers, Notifier/AsyncNotifier, ref.watch/read/listen, DI, autoDispose | references/state-management.md |
| Routes, deep links, nested or guarded navigation | references/navigation.md |
| Data models, freezed, JSON serialization, build_runner workflow | references/models-serialization.md |
| Writing tests: unit, widget, golden, integration | references/testing.md |
Rebuild storms, async-gap crashes, layout overflow, dynamic leaks | references/pitfalls.md |
| Picking a package (storage, network, forms, i18n, background), pubspec hygiene | references/packages.md |
Toolchain & Setup
- Pin the Flutter SDK with fvm (
.fvmrc,fvm use) and commit the pin so every machine and CI build the same stable SDK. very_good_analysisinanalysis_options.yamlas the lint floor. It layersstrict-casts,strict-raw-types, andstrict-inferenceon top offlutter_lints, catching the exact classes of mistake generated code produces (implicitdynamic, unchecked casts). Fix warnings; never loosen a rule to silence one.flutter analyzestays clean in CI.- Codegen (
freezed,json_serializable,riverpod_generator,retrofit) runs throughdart run build_runner build --delete-conflicting-outputs. Generated*.g.dartand*.freezed.dartare build output: regenerate after editing the annotated source, never hand-edit them. Detail inreferences/models-serialization.md.
Widgets & Build
build()is pure: no side effects, no I/O, no allocation you can hoist out. It runs often; assume every rebuild is free to happen at any time.constwherever the analyzer allows (prefer_const_constructors). Aconstwidget is skipped on rebuild, the cheapest perf win and the one generated code drops most.- Extract widget subtrees into their own
StatelessWidget/ConsumerWidgetclasses, notWidget _buildFoo()methods. A helper method rebuilds with its parent and can't beconst; a widget class gets its own rebuild boundary and const-ness. - Compose small widgets. A deep
buildmethod that could be five classes is the Flutter equivalent of a 200-line function. Keys only where identity matters (reordered or inserted list items, state preserved across a position change). Don't scatter keys nothing reads.
State
- Riverpod with codegen (
@riverpod) is the default for both state and DI.ref.watchinbuildto react to changes;ref.readin callbacks and event handlers for a one-shot read. Watching in a callback re-subscribes on every call; reading inbuildmisses updates. Detail inreferences/state-management.md. - Push state to the smallest widget that needs it. Scope
ref.watchwith.select(...)so a one-field change doesn't rebuild the whole screen. setStateis fine for genuinely local ephemeral state (a toggle, focus, an animation flag). Not for app state or anything shared across widgets.- Package-specific deprecation/trend verdicts (GetX, Isar, old Hive, golden_toolkit) live in
references/pitfalls.md's Named traps list, even when the package's own topic has a dedicated reference file (e.g.state-management.md).
Async & Lifecycle
- After any
awaitinside aStateor callback, aBuildContextmay be dead. Guard withif (!context.mounted) return;(orif (!mounted) return;in aState) before touchingcontext,Navigator,setState, or a controller.use_build_context_synchronouslyflags the common cases, not all of them. - Dispose what you create.
TextEditingController,ScrollController,AnimationController,FocusNode, andStreamSubscriptionall leak and can fire after teardown without a matchingdispose()/cancel().
Errors
- Repositories catch throwing calls (network, disk, platform channels) internally and return a sealed
Result<T>(Ok/Failure); callersswitchon it exhaustively. The failure path becomes part of the signature instead of an invisible throw. Detail inreferences/architecture.md. - Let genuine bugs (programmer error, broken preconditions) throw and reach crash reporting. Don't wrap them in a
try/catchthat swallows them into a silent no-op.
Naming & Style
lowerCamelCasefor members and locals,UpperCamelCasefor types,lowercase_with_underscoresfor files and directories. Matchdart format; never hand-format around it.- Private by default (
_name); widen visibility only when another library needs it. async/awaitover raw.then()chains. Type every public signature and let strict-inference reject accidentaldynamic.
Pre-Submit Checklist
-
flutter analyzeclean under very_good_analysis; no rule loosened to pass - codegen regenerated after any model/provider edit; no hand-edited
*.g.dart/*.freezed.dart -
conston every eligible widget; subtrees extracted to classes, not_buildmethods - no
BuildContext/Navigator/setStateafter anawaitwithout amountedguard - every controller, subscription, and notifier disposed
-
ref.watchin build,ref.readin callbacks,ref.listenfor side effects; watch scoped with.select - repository calls return
Result; genuine bugs throw rather than being swallowed - no unmaintained package added (pub.dev signals checked, see
references/packages.md) - tests fail if the logic breaks; layer chosen per the pyramid (
references/testing.md)