Flutter Master AI Agent Prompt
MVVM+ (mvvm_plus) + Bilocator — Repo‑Enforceable Architecture (for editing an existing Flutter codebase)
Executive Summary
MVVM+: Tiny API layered on Flutter:
get,listenTo,buildView;ViewWidget<T>for views;ViewModelfor state/logic;Modelfor shared logic. UsecreateProperty<T>()for view‑bound state. (Dart packages)Bilocator DI: Register single services (registry) and/or inherited models (widget tree). Access with
Bilocator.get<T>(), orget<T>()/listenTo<T>()in MVVM+ classes. (Dart packages)Registry vs Tree:
Location.registry(global access) vsLocation.tree(descendant scope). Pick the narrowest scope that fits. (Dart packages)Hot‑reload safety: Wrap multiple registrations in
Bilocatorsand assign a stablekeyto avoid re‑registration errors on hot‑reload. (Dart packages)View rules: Prefer
ViewWidget<T>, keep widgets stateless; noStatefulWidgetunless a package forces it. NoListenableBuilder. Logic & side‑effects live in ViewModels/services. (Dart packages)Streams & disposal: Mirror repository/stream changes into MVVM+ Properties via
createProperty/createStreamProperty; cancel subscriptions indispose(). (Dart packages)Navigation boundary: Prefer
go_routerbehind a RouterService; Views call ViewModel → service. Keep routing APIs out of Views. (Dart packages)Models: Use
json_serializablefor (de)serialization; keep models immutable where practical. (Dart packages)Style: Follow Effective Dart + PWI standards; match existing project patterns. (Dart, PWI Works Help)
Architecture & Patterns (mvvm_plus + bilocator)
Core APIs & Lifecycle
View (
ViewWidget<T extends ViewModel>): a widget whoseviewModelis provided by a builder; MVVM+ addsget/listenTohelpers. Use it instead of hand‑rolledStatefulWidget. (Dart packages)ViewModel: extends
Model; owns UI state and orchestrates services; triggers view rebuilds viabuildView(). Lifecycle includesinitState/dispose. (Dart packages)Property: MVVM+ typedef over
ValueNotifier<T>; create withcreateProperty<T>()(auto‑wiresbuildView). Prefer this over rawValueNotifier. (Dart packages)Streams: Use
createStreamProperty<T>(stream); dispose indispose(). (Dart packages)
DI & Service Location (bilocator)
Register
Single service (registry):
Bilocator<MyService>(builder: () => MyService(), child: ...).Multiple:
Bilocators(delegates: [BilocatorDelegate<T>(builder: ...), ...]).Inherited model (tree): set
location: Location.tree. (Dart packages)
Access
Anywhere:
Bilocator.get<T>().Inside MVVM+ classes:
get<T>()/listenTo<T>(); preferlistenToto avoid.of‑style rebuild coupling. (Dart packages)
Hot‑reload: Assign a repeatable
keytoBilocatorsto prevent delegate re‑registration on hot reload. (Dart packages)
Widget‑Tree Patterns
Register cross‑cutting services at the app root (
main.dart) withBilocators(stable key). Register feature‑scoped models closer to their Views usinglocation: Location.tree. (Dart packages)
Navigation Boundary
Use
go_routerwithMaterialApp.router(routerConfig: ...); expose only a RouterService to ViewModels; Views invoke ViewModel methods. (Dart packages)
Style & Docs
Conform to Effective Dart + PWI standards; keep comments purposeful and at the API/decision points. (Dart, PWI Works Help)
Repo Editing Guide & Scaffold (match current patterns)
Directory Conventions (adapt, don’t rename without approval)
Typical PWI structure:
lib/system,lib/data/{models,repositories,services},lib/ui/<page>/{view.dart,view_model.dart},lib/utils, plus app entry (main.dart). See PWI standards for an example tree. (PWI Works Help)
Canonical Bilocators Initialization (use this; replace other init examples)
(Why: Bilocators manages multiple registrations; the stable key prevents hot‑reload re‑registration issues.) (Dart packages)
Canonical ViewModel (mirror repo changes from a repository into a Property)
Notes: createProperty<T> auto‑adds a buildView listener; streams use createStreamProperty when appropriate. (Dart packages)
Minimal View (stateless UI; reads Property via viewModel)
Why this shape: stateless View; no StatefulWidget; all state in the ViewModel; rebuilds are driven by MVVM+ Properties. (Dart packages)
Minimal model with json_serializable (adapt names/fields)
README “Agent Contract” (copy‑ready for the repo)
Do
Views: Use
ViewWidget<T>; keep widgets stateless; noStatefulWidgetunless a package forces it. (Dart packages)State & Logic: In ViewModels via
createProperty<T>()/createStreamProperty<T>(); callbuildView()to redraw. (Dart packages)DI: Register via Bilocators/BilocatorDelegate at the app root (stable
key); access viaBilocator.get<T>()or MVVM+get<T>()/listenTo<T>(). PreferLocation.treefor feature‑scoped models. (Dart packages)Navigation: Use
go_routerbehind a RouterService; Views don’t call router APIs directly. (Dart packages)Models: Use
json_serializable; keep conversions out of Views. (Dart packages)Style/Docs: Follow Effective Dart + PWI + existing repo patterns. (Dart, PWI Works Help)
Do Not
❌ No
ListenableBuilderor rawValueNotifierin examples/components; use MVVM+Property/createProperty. (Dart packages)❌ No globals/singletons outside bilocator. Use DI. (Dart packages)
❌ No direct routing calls from Views. Call ViewModel → RouterService. (Dart packages)
Directory & File Rules
Keep
lib/ui/<page>/{view.dart,view_model.dart}; services/repos/models underlib/data; DI inlib/system/. Align with the repo’s current structure and PWI guidance. (PWI Works Help)
PR & Review Checklist
[ ] View is
ViewWidget<T>; no stray state in widgets. (Dart packages)[ ] ViewModel holds all state via Properties; no raw
ValueNotifier. (Dart packages)[ ] Services via bilocator; no globals.
Bilocatorshas a stablekey. (Dart packages)[ ] Navigation only through RouterService; no view‑router coupling. (Dart packages)
[ ] Effective Dart + PWI style. (Dart, PWI Works Help)
Agent Prompting Toolkit (repo‑aware; reference the README)
1) Add a screen (View + ViewModel) “Edit the existing codebase to add Foo. Create lib/ui/foo/foo_view.dart and foo_view_model.dart using ViewWidget<FooViewModel>. Keep the View stateless; use createProperty in the ViewModel. Wire UI to the Property. Follow the README contract (DI via Bilocator, style via Effective Dart/PWI).”
2) Add a service + DI “Add UserRepository and register it in Bilocators (stable key) in main.dart. Expose a Stream<User?> dataStream. Update UserViewModel to resolve via Bilocator.get<UserRepository>() and mirror changes into a Property<User?>. Follow the README.”
3) Refactor to MVVM+ “Refactor OldWidget (was StatefulWidget) into ViewWidget<OldViewModel>. Move all state to the ViewModel using createProperty. Replace any raw ValueNotifier with Property. Access services via get<T>().”
4) Navigation change “Add a RouterService wrapping go_router calls (go, push). Inject via bilocator; Views call ViewModel → RouterService. No direct router calls in Views.”
5) Repo rules sync “Ensure .github/copilot-instructions.md mirrors the README ‘Agent Contract’ sections (Do/Do Not, DI rules, directory rules).” (GitHub Docs)
Migration & Pitfalls (when touching existing features)
From Provider/Riverpod/get_it/stacked: Replace provider scopes/singletons with bilocator registrations; replace
notifyListeners‑heavy flows withbuildView()+ Properties in ViewModels; move view logic into ViewModels. (MVVM+ docs showbuildView/createPropertypatterns.) (Dart packages)Hot‑reload:
Bilocatorsneeds a stablekeyor you may get duplicate registration errors. (Dart packages)Streams: Prefer
createStreamPropertyor mirror repository streams into aProperty; cancel subscriptions indispose(). (Dart packages)Navigation: Keep
go_routerbehind a service; configureMaterialApp.router(routerConfig: ...). Avoid coupling Views to router APIs. (Dart packages)Avoid
.ofwhere possible: preferlistenTo/getto reduce unwanted rebuild dependencies. (Dart packages)
Examples (minimal, aligned with docs)
Register multiple services at root (hot‑reload safe):
(Bilocators + stable key; lifecycle bound to the widget.) (Dart packages)
ViewModel with MVVM+ Properties (no raw ValueNotifier):
(Property triggers view rebuild via buildView listener.) (Dart packages)
Access another ViewModel/service:
Version Awareness (re‑check before upgrades)
mvvm_plus: 1.5.4, published \~22 months ago on pub.dev; docs include
ViewWidget,buildView,createProperty,createStreamProperty,Location.registry/tree. (Dart packages)bilocator: 0.6.1, published \~23 months ago; supports registry/tree,
Bilocators,BilocatorDelegate, and hot‑reload stablekeyguidance. (Dart packages)
Required Reading (for agents; follow the links)
PWI Standards: Flutter & coding standards (structure, naming, package prefs). Last modified Aug 21, 2025. (PWI Works Help)
MVVM+ official docs & API: patterns,
ViewWidget, lifecycle, Properties, registry/tree. (Dart packages)Bilocator official docs & API: single services vs inherited models,
Bilocators,get/listenTo, hot‑reload key. (Dart packages)Effective Dart: style/docs/design. (Dart)
json_serializable: usage + API. (Dart packages)
go_router: router config & features (for RouterService). (Dart packages)
Deviation Notes (if conflicts arise)
If this page conflicts with mvvm_plus or bilocator docs, add a short Deviation Note in your PR description with a link to the exact API doc section and the smallest possible change to align the code. (Dart packages)