agentleFS
uwuclxdyuwuclxdy/agenticat/skills/clean-flutter/SKILL.md

clean-flutter

Skill7 starsChanged 18 days agoMITView on GitHub

Idiomatic Flutter and Dart rules: feature-first layout, Riverpod, freezed, go_router, const correctness.

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
  1. Very specific:

    After any await inside a State or callback, a BuildContext may be dead.

    line 49

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 touchesFile
Project layout, MVVM layering, repository boundaries, Resultreferences/architecture.md
Providers, Notifier/AsyncNotifier, ref.watch/read/listen, DI, autoDisposereferences/state-management.md
Routes, deep links, nested or guarded navigationreferences/navigation.md
Data models, freezed, JSON serialization, build_runner workflowreferences/models-serialization.md
Writing tests: unit, widget, golden, integrationreferences/testing.md
Rebuild storms, async-gap crashes, layout overflow, dynamic leaksreferences/pitfalls.md
Picking a package (storage, network, forms, i18n, background), pubspec hygienereferences/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_analysis in analysis_options.yaml as the lint floor. It layers strict-casts, strict-raw-types, and strict-inference on top of flutter_lints, catching the exact classes of mistake generated code produces (implicit dynamic, unchecked casts). Fix warnings; never loosen a rule to silence one. flutter analyze stays clean in CI.
  • Codegen (freezed, json_serializable, riverpod_generator, retrofit) runs through dart run build_runner build --delete-conflicting-outputs. Generated *.g.dart and *.freezed.dart are build output: regenerate after editing the annotated source, never hand-edit them. Detail in references/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.
  • const wherever the analyzer allows (prefer_const_constructors). A const widget is skipped on rebuild, the cheapest perf win and the one generated code drops most.
  • Extract widget subtrees into their own StatelessWidget/ConsumerWidget classes, not Widget _buildFoo() methods. A helper method rebuilds with its parent and can't be const; a widget class gets its own rebuild boundary and const-ness.
  • Compose small widgets. A deep build method 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.watch in build to react to changes; ref.read in callbacks and event handlers for a one-shot read. Watching in a callback re-subscribes on every call; reading in build misses updates. Detail in references/state-management.md.
  • Push state to the smallest widget that needs it. Scope ref.watch with .select(...) so a one-field change doesn't rebuild the whole screen.
  • setState is 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 await inside a State or callback, a BuildContext may be dead. Guard with if (!context.mounted) return; (or if (!mounted) return; in a State) before touching context, Navigator, setState, or a controller. use_build_context_synchronously flags the common cases, not all of them.
  • Dispose what you create. TextEditingController, ScrollController, AnimationController, FocusNode, and StreamSubscription all leak and can fire after teardown without a matching dispose()/cancel().

Errors

  • Repositories catch throwing calls (network, disk, platform channels) internally and return a sealed Result<T> (Ok/Failure); callers switch on it exhaustively. The failure path becomes part of the signature instead of an invisible throw. Detail in references/architecture.md.
  • Let genuine bugs (programmer error, broken preconditions) throw and reach crash reporting. Don't wrap them in a try/catch that swallows them into a silent no-op.

Naming & Style

  • lowerCamelCase for members and locals, UpperCamelCase for types, lowercase_with_underscores for files and directories. Match dart format; never hand-format around it.
  • Private by default (_name); widen visibility only when another library needs it.
  • async/await over raw .then() chains. Type every public signature and let strict-inference reject accidental dynamic.

Pre-Submit Checklist

  • flutter analyze clean under very_good_analysis; no rule loosened to pass
  • codegen regenerated after any model/provider edit; no hand-edited *.g.dart/*.freezed.dart
  • const on every eligible widget; subtrees extracted to classes, not _build methods
  • no BuildContext/Navigator/setState after an await without a mounted guard
  • every controller, subscription, and notifier disposed
  • ref.watch in build, ref.read in callbacks, ref.listen for 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)

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.