← Open Source
ai skill

utopia-hooks

The skill our agents follow when they write a Flutter screen - Screen/State/View, the hook catalog, and a quality gate that runs after every Dart edit.

/plugin marketplace add Utopia-USS/utopia-flutter-skills /plugin install utopia-hooks@utopia-flutter-skills
flutter pub add utopia_hooks
why it exists
Our agents do not improvise off a blank prompt. When one writes a screen, it follows the same structure a senior engineer here would: a Screen that wires exactly one hook, a State class that holds all the logic in immutable fields, and a View that is a pure StatelessWidget reading only that state. Logic never leaks into the widget tree, so the screen stays testable and decoupled by construction.

The skill encodes that discipline in full - the hook catalog for async, pagination, forms, and submission; how global state is registered and consumed; how a state is unit-tested with no widget tree. A PostToolUse quality gate runs utopia hooks analyze after every Dart edit, so the rules hold on every line, not just the first draft. We publish it: a CTO can read how the agents work before signing anything, and it is the same skill your team keeps after hand-over.

This is the same discipline behind Habicy - eighteen hook-driven states, one Screen/State/View pattern.
utopia-hooks/SKILL.md15 refs
name
utopia-hooks
Referencesread before writing
Screen · State · ViewCRITICAL
Hook catalogCRITICAL
Global shared stateCRITICAL
Async patternsHIGH
Paginated listsHIGH
App bootstrapHIGH
Error handlingHIGH
NavigationHIGH
Multi-page shellHIGH
Complex state examplesHIGH
Composable hooksHIGH
Flutter conventionsHIGH
TestingHIGH
DI & servicesMEDIUM
utopia_cli surfacesMEDIUM
Read the full skill
usage

A screen an agent writes without this skill still compiles. It just does not look like ours - a StatefulWidget with logic threaded through setState calls, instead of one hook and one State class. Here is the difference the skill enforces:

// Without the skill: logic lives in the widget, mutated by setState.
class CounterPage extends StatefulWidget {
  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int value = 0;

  @override
  Widget build(BuildContext context) => CounterView(
        value: value,
        onPressed: () => setState(() => value++),
      );
}

// With the skill: a State class holds the logic, one hook drives it,
// the View is a pure StatelessWidget reading only that state.
class CounterPageState {
  final int value;
  final VoidCallback onPressed;
  const CounterPageState({required this.value, required this.onPressed});
}

CounterPageState useCounterPageState() {
  final state = useState(0);
  return CounterPageState(value: state.value, onPressed: () => state.value++);
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) =>
      const HookCoordinator(use: useCounterPageState, builder: CounterView.new);
}
talk to us

Want this in your build?

The team behind utopia-hooks ships production Flutter on the same stack. Tell us what you are building.