clean-flutter
Skill7 starsChanged 18 days agoMITView on GitHub
Idiomatic Flutter and Dart rules: feature-first layout, Riverpod, freezed, go_router, const correctness.
In this repository15 other files it gives its agents.
- askamaSkill
- cargo-toml-optimizationSkill
- clean-codeSkill
- clean-rustSkill
- clean-shellSkill
- docs-syncSkill
- emulator-testingSkill
- maudSkill
- mcp-statelessSkill
- name-checkSkill
- ratatui-patternsSkill
- terminal-uxSkill
- todoSkill
- ux-patternsSkill
- webapp-testingSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 49
After any await inside a State or callback, a BuildContext may be dead.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

