[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-flutter-flutter-apply-architecture-best-practices":3,"mdc-zh2izg-key":31,"related-repo-flutter-flutter-apply-architecture-best-practices":1209,"related-org-flutter-flutter-apply-architecture-best-practices":1288},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":21,"repoUrl":22,"updatedAt":23,"license":24,"forks":25,"topics":26,"repo":27,"sourceUrl":29,"mdContent":30},"flutter-apply-architecture-best-practices","architect Flutter applications with layered approach","Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"flutter","Flutter (Google)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fflutter.png",[12,15,18],{"name":13,"slug":8,"type":14},"Flutter","tag",{"name":16,"slug":17,"type":14},"Architecture","architecture",{"name":19,"slug":20,"type":14},"Engineering","engineering",2664,"https:\u002F\u002Fgithub.com\u002Fflutter\u002Fagent-plugins","2026-07-15T05:22:36.405249",null,155,[],{"repoUrl":22,"stars":21,"forks":25,"topics":28,"description":24},[],"https:\u002F\u002Fgithub.com\u002Fflutter\u002Fagent-plugins\u002Ftree\u002FHEAD\u002Fskills\u002Fflutter-apply-architecture-best-practices","---\nname: flutter-apply-architecture-best-practices\ndescription: Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability.\nmetadata:\n  model: models\u002Fgemini-3.1-pro-preview\n  last_modified: Tue, 21 Apr 2026 20:11:20 GMT\n---\n# Architecting Flutter Applications\n\n## Contents\n- [Architectural Layers](#architectural-layers)\n- [Project Structure](#project-structure)\n- [Workflow: Implementing a New Feature](#workflow-implementing-a-new-feature)\n- [Examples](#examples)\n\n## Architectural Layers\n\nEnforce strict Separation of Concerns by dividing the application into distinct layers. Never mix UI rendering with business logic or data fetching.\n\n### UI Layer (Presentation)\nImplement the MVVM (Model-View-ViewModel) pattern to manage UI state and logic.\n*   **Views:** Write reusable, lean widgets. Restrict logic in Views to UI-specific operations (e.g., animations, layout constraints, simple routing). Pass all required data from the ViewModel.\n*   **ViewModels:** Manage UI state and handle user interactions. Extend `ChangeNotifier` (or use `Listenable`) to expose state. Expose immutable state snapshots to the View. Inject Repositories into ViewModels via the constructor.\n\n### Data Layer\nImplement the Repository pattern to isolate data access logic and create a single source of truth.\n*   **Services:** Create stateless classes to wrap external APIs (HTTP clients, local databases, platform plugins). Return raw API models or `Result` wrappers.\n*   **Repositories:** Consume one or more Services. Transform raw API models into clean Domain Models. Handle caching, offline synchronization, and retry logic. Expose Domain Models to ViewModels.\n\n### Logic Layer (Domain - Optional)\n*   **Use Cases:** Implement this layer only if the application contains complex business logic that clutters the ViewModel, or if logic must be reused across multiple ViewModels. Extract this logic into dedicated Use Case (interactor) classes that sit between ViewModels and Repositories.\n\n## Project Structure\n\nOrganize the codebase using a hybrid approach: group UI components by feature, and group Data\u002FDomain components by type.\n\n```text\nlib\u002F\n├── data\u002F\n│   ├── models\u002F         # API models\n│   ├── repositories\u002F   # Repository implementations\n│   └── services\u002F       # API clients, local storage wrappers\n├── domain\u002F\n│   ├── models\u002F         # Clean domain models\n│   └── use_cases\u002F      # Optional business logic classes\n└── ui\u002F\n    ├── core\u002F           # Shared widgets, themes, typography\n    └── features\u002F\n        └── [feature_name]\u002F\n            ├── view_models\u002F\n            └── views\u002F\n```\n\n## Workflow: Implementing a New Feature\n\nFollow this sequential workflow when adding a new feature to the application. Copy the checklist to track progress.\n\n### Task Progress\n- [ ] **Step 1: Define Domain Models.** Create immutable data classes for the feature using `freezed` or `built_value`.\n- [ ] **Step 2: Implement Services.** Create or update Service classes to handle external API communication.\n- [ ] **Step 3: Implement Repositories.** Create the Repository to consume Services and return Domain Models.\n- [ ] **Step 4: Apply Conditional Logic (Domain Layer).**\n  - *If the feature requires complex data transformation or cross-repository logic:* Create a Use Case class.\n  - *If the feature is a simple CRUD operation:* Skip to Step 5.\n- [ ] **Step 5: Implement the ViewModel.** Create the ViewModel extending `ChangeNotifier`. Inject required Repositories\u002FUse Cases. Expose immutable state and command methods.\n- [ ] **Step 6: Implement the View.** Create the UI widget. Use `ListenableBuilder` or `AnimatedBuilder` to listen to ViewModel changes.\n- [ ] **Step 7: Inject Dependencies.** Register the new Service, Repository, and ViewModel in the dependency injection container (e.g., `provider` or `get_it`).\n- [ ] **Step 8: Run Validator.** Execute unit tests for the ViewModel and Repository.\n  - *Feedback Loop:* Run tests -> Review failures -> Fix logic -> Re-run until passing.\n\n## Examples\n\n### Data Layer: Service and Repository\n\n```dart\n\u002F\u002F 1. Service (Raw API interaction)\nclass ApiClient {\n  Future\u003CUserApiModel> fetchUser(String id) async {\n    \u002F\u002F HTTP GET implementation...\n  }\n}\n\n\u002F\u002F 2. Repository (Single source of truth, returns Domain Model)\nclass UserRepository {\n  UserRepository({required ApiClient apiClient}) : _apiClient = apiClient;\n  \n  final ApiClient _apiClient;\n  User? _cachedUser;\n\n  Future\u003CUser> getUser(String id) async {\n    if (_cachedUser != null) return _cachedUser!;\n    \n    final apiModel = await _apiClient.fetchUser(id);\n    _cachedUser = User(id: apiModel.id, name: apiModel.fullName); \u002F\u002F Transform to Domain Model\n    return _cachedUser!;\n  }\n}\n```\n\n### UI Layer: ViewModel and View\n\n```dart\n\u002F\u002F 3. ViewModel (State management and presentation logic)\nclass ProfileViewModel extends ChangeNotifier {\n  ProfileViewModel({required UserRepository userRepository}) \n      : _userRepository = userRepository;\n\n  final UserRepository _userRepository;\n\n  User? _user;\n  User? get user => _user;\n\n  bool _isLoading = false;\n  bool get isLoading => _isLoading;\n\n  Future\u003Cvoid> loadProfile(String id) async {\n    _isLoading = true;\n    notifyListeners();\n\n    try {\n      _user = await _userRepository.getUser(id);\n    } finally {\n      _isLoading = false;\n      notifyListeners();\n    }\n  }\n}\n\n\u002F\u002F 4. View (Dumb UI component)\nclass ProfileView extends StatelessWidget {\n  const ProfileView({super.key, required this.viewModel});\n\n  final ProfileViewModel viewModel;\n\n  @override\n  Widget build(BuildContext context) {\n    return ListenableBuilder(\n      listenable: viewModel,\n      builder: (context, _) {\n        if (viewModel.isLoading) {\n          return const Center(child: CircularProgressIndicator());\n        }\n        \n        final user = viewModel.user;\n        if (user == null) {\n          return const Center(child: Text('User not found'));\n        }\n\n        return Column(\n          children: [\n            Text(user.name),\n            ElevatedButton(\n              onPressed: () => viewModel.loadProfile(user.id),\n              child: const Text('Refresh'),\n            ),\n          ],\n        );\n      },\n    );\n  }\n}\n```\n",{"data":32,"body":36},{"name":4,"description":6,"metadata":33},{"model":34,"last_modified":35},"models\u002Fgemini-3.1-pro-preview","Tue, 21 Apr 2026 20:11:20 GMT",{"type":37,"children":38},"root",[39,48,55,97,102,108,115,120,161,167,172,203,209,222,227,232,244,249,254,260,478,483,489,695,701,1203],{"type":40,"tag":41,"props":42,"children":44},"element","h1",{"id":43},"architecting-flutter-applications",[45],{"type":46,"value":47},"text","Architecting Flutter Applications",{"type":40,"tag":49,"props":50,"children":52},"h2",{"id":51},"contents",[53],{"type":46,"value":54},"Contents",{"type":40,"tag":56,"props":57,"children":58},"ul",{},[59,70,79,88],{"type":40,"tag":60,"props":61,"children":62},"li",{},[63],{"type":40,"tag":64,"props":65,"children":67},"a",{"href":66},"#architectural-layers",[68],{"type":46,"value":69},"Architectural Layers",{"type":40,"tag":60,"props":71,"children":72},{},[73],{"type":40,"tag":64,"props":74,"children":76},{"href":75},"#project-structure",[77],{"type":46,"value":78},"Project Structure",{"type":40,"tag":60,"props":80,"children":81},{},[82],{"type":40,"tag":64,"props":83,"children":85},{"href":84},"#workflow-implementing-a-new-feature",[86],{"type":46,"value":87},"Workflow: Implementing a New Feature",{"type":40,"tag":60,"props":89,"children":90},{},[91],{"type":40,"tag":64,"props":92,"children":94},{"href":93},"#examples",[95],{"type":46,"value":96},"Examples",{"type":40,"tag":49,"props":98,"children":100},{"id":99},"architectural-layers",[101],{"type":46,"value":69},{"type":40,"tag":103,"props":104,"children":105},"p",{},[106],{"type":46,"value":107},"Enforce strict Separation of Concerns by dividing the application into distinct layers. Never mix UI rendering with business logic or data fetching.",{"type":40,"tag":109,"props":110,"children":112},"h3",{"id":111},"ui-layer-presentation",[113],{"type":46,"value":114},"UI Layer (Presentation)",{"type":40,"tag":103,"props":116,"children":117},{},[118],{"type":46,"value":119},"Implement the MVVM (Model-View-ViewModel) pattern to manage UI state and logic.",{"type":40,"tag":56,"props":121,"children":122},{},[123,134],{"type":40,"tag":60,"props":124,"children":125},{},[126,132],{"type":40,"tag":127,"props":128,"children":129},"strong",{},[130],{"type":46,"value":131},"Views:",{"type":46,"value":133}," Write reusable, lean widgets. Restrict logic in Views to UI-specific operations (e.g., animations, layout constraints, simple routing). Pass all required data from the ViewModel.",{"type":40,"tag":60,"props":135,"children":136},{},[137,142,144,151,153,159],{"type":40,"tag":127,"props":138,"children":139},{},[140],{"type":46,"value":141},"ViewModels:",{"type":46,"value":143}," Manage UI state and handle user interactions. Extend ",{"type":40,"tag":145,"props":146,"children":148},"code",{"className":147},[],[149],{"type":46,"value":150},"ChangeNotifier",{"type":46,"value":152}," (or use ",{"type":40,"tag":145,"props":154,"children":156},{"className":155},[],[157],{"type":46,"value":158},"Listenable",{"type":46,"value":160},") to expose state. Expose immutable state snapshots to the View. Inject Repositories into ViewModels via the constructor.",{"type":40,"tag":109,"props":162,"children":164},{"id":163},"data-layer",[165],{"type":46,"value":166},"Data Layer",{"type":40,"tag":103,"props":168,"children":169},{},[170],{"type":46,"value":171},"Implement the Repository pattern to isolate data access logic and create a single source of truth.",{"type":40,"tag":56,"props":173,"children":174},{},[175,193],{"type":40,"tag":60,"props":176,"children":177},{},[178,183,185,191],{"type":40,"tag":127,"props":179,"children":180},{},[181],{"type":46,"value":182},"Services:",{"type":46,"value":184}," Create stateless classes to wrap external APIs (HTTP clients, local databases, platform plugins). Return raw API models or ",{"type":40,"tag":145,"props":186,"children":188},{"className":187},[],[189],{"type":46,"value":190},"Result",{"type":46,"value":192}," wrappers.",{"type":40,"tag":60,"props":194,"children":195},{},[196,201],{"type":40,"tag":127,"props":197,"children":198},{},[199],{"type":46,"value":200},"Repositories:",{"type":46,"value":202}," Consume one or more Services. Transform raw API models into clean Domain Models. Handle caching, offline synchronization, and retry logic. Expose Domain Models to ViewModels.",{"type":40,"tag":109,"props":204,"children":206},{"id":205},"logic-layer-domain-optional",[207],{"type":46,"value":208},"Logic Layer (Domain - Optional)",{"type":40,"tag":56,"props":210,"children":211},{},[212],{"type":40,"tag":60,"props":213,"children":214},{},[215,220],{"type":40,"tag":127,"props":216,"children":217},{},[218],{"type":46,"value":219},"Use Cases:",{"type":46,"value":221}," Implement this layer only if the application contains complex business logic that clutters the ViewModel, or if logic must be reused across multiple ViewModels. Extract this logic into dedicated Use Case (interactor) classes that sit between ViewModels and Repositories.",{"type":40,"tag":49,"props":223,"children":225},{"id":224},"project-structure",[226],{"type":46,"value":78},{"type":40,"tag":103,"props":228,"children":229},{},[230],{"type":46,"value":231},"Organize the codebase using a hybrid approach: group UI components by feature, and group Data\u002FDomain components by type.",{"type":40,"tag":233,"props":234,"children":239},"pre",{"className":235,"code":237,"language":46,"meta":238},[236],"language-text","lib\u002F\n├── data\u002F\n│   ├── models\u002F         # API models\n│   ├── repositories\u002F   # Repository implementations\n│   └── services\u002F       # API clients, local storage wrappers\n├── domain\u002F\n│   ├── models\u002F         # Clean domain models\n│   └── use_cases\u002F      # Optional business logic classes\n└── ui\u002F\n    ├── core\u002F           # Shared widgets, themes, typography\n    └── features\u002F\n        └── [feature_name]\u002F\n            ├── view_models\u002F\n            └── views\u002F\n","",[240],{"type":40,"tag":145,"props":241,"children":242},{"__ignoreMap":238},[243],{"type":46,"value":237},{"type":40,"tag":49,"props":245,"children":247},{"id":246},"workflow-implementing-a-new-feature",[248],{"type":46,"value":87},{"type":40,"tag":103,"props":250,"children":251},{},[252],{"type":46,"value":253},"Follow this sequential workflow when adding a new feature to the application. Copy the checklist to track progress.",{"type":40,"tag":109,"props":255,"children":257},{"id":256},"task-progress",[258],{"type":46,"value":259},"Task Progress",{"type":40,"tag":56,"props":261,"children":264},{"className":262},[263],"contains-task-list",[265,301,316,331,368,390,420,450],{"type":40,"tag":60,"props":266,"children":269},{"className":267},[268],"task-list-item",[270,276,278,283,285,291,293,299],{"type":40,"tag":271,"props":272,"children":275},"input",{"disabled":273,"type":274},true,"checkbox",[],{"type":46,"value":277}," ",{"type":40,"tag":127,"props":279,"children":280},{},[281],{"type":46,"value":282},"Step 1: Define Domain Models.",{"type":46,"value":284}," Create immutable data classes for the feature using ",{"type":40,"tag":145,"props":286,"children":288},{"className":287},[],[289],{"type":46,"value":290},"freezed",{"type":46,"value":292}," or ",{"type":40,"tag":145,"props":294,"children":296},{"className":295},[],[297],{"type":46,"value":298},"built_value",{"type":46,"value":300},".",{"type":40,"tag":60,"props":302,"children":304},{"className":303},[268],[305,308,309,314],{"type":40,"tag":271,"props":306,"children":307},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":310,"children":311},{},[312],{"type":46,"value":313},"Step 2: Implement Services.",{"type":46,"value":315}," Create or update Service classes to handle external API communication.",{"type":40,"tag":60,"props":317,"children":319},{"className":318},[268],[320,323,324,329],{"type":40,"tag":271,"props":321,"children":322},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":325,"children":326},{},[327],{"type":46,"value":328},"Step 3: Implement Repositories.",{"type":46,"value":330}," Create the Repository to consume Services and return Domain Models.",{"type":40,"tag":60,"props":332,"children":334},{"className":333},[268],[335,338,339,344],{"type":40,"tag":271,"props":336,"children":337},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":340,"children":341},{},[342],{"type":46,"value":343},"Step 4: Apply Conditional Logic (Domain Layer).",{"type":40,"tag":56,"props":345,"children":346},{},[347,358],{"type":40,"tag":60,"props":348,"children":349},{},[350,356],{"type":40,"tag":351,"props":352,"children":353},"em",{},[354],{"type":46,"value":355},"If the feature requires complex data transformation or cross-repository logic:",{"type":46,"value":357}," Create a Use Case class.",{"type":40,"tag":60,"props":359,"children":360},{},[361,366],{"type":40,"tag":351,"props":362,"children":363},{},[364],{"type":46,"value":365},"If the feature is a simple CRUD operation:",{"type":46,"value":367}," Skip to Step 5.",{"type":40,"tag":60,"props":369,"children":371},{"className":370},[268],[372,375,376,381,383,388],{"type":40,"tag":271,"props":373,"children":374},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":377,"children":378},{},[379],{"type":46,"value":380},"Step 5: Implement the ViewModel.",{"type":46,"value":382}," Create the ViewModel extending ",{"type":40,"tag":145,"props":384,"children":386},{"className":385},[],[387],{"type":46,"value":150},{"type":46,"value":389},". Inject required Repositories\u002FUse Cases. Expose immutable state and command methods.",{"type":40,"tag":60,"props":391,"children":393},{"className":392},[268],[394,397,398,403,405,411,412,418],{"type":40,"tag":271,"props":395,"children":396},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":399,"children":400},{},[401],{"type":46,"value":402},"Step 6: Implement the View.",{"type":46,"value":404}," Create the UI widget. Use ",{"type":40,"tag":145,"props":406,"children":408},{"className":407},[],[409],{"type":46,"value":410},"ListenableBuilder",{"type":46,"value":292},{"type":40,"tag":145,"props":413,"children":415},{"className":414},[],[416],{"type":46,"value":417},"AnimatedBuilder",{"type":46,"value":419}," to listen to ViewModel changes.",{"type":40,"tag":60,"props":421,"children":423},{"className":422},[268],[424,427,428,433,435,441,442,448],{"type":40,"tag":271,"props":425,"children":426},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":429,"children":430},{},[431],{"type":46,"value":432},"Step 7: Inject Dependencies.",{"type":46,"value":434}," Register the new Service, Repository, and ViewModel in the dependency injection container (e.g., ",{"type":40,"tag":145,"props":436,"children":438},{"className":437},[],[439],{"type":46,"value":440},"provider",{"type":46,"value":292},{"type":40,"tag":145,"props":443,"children":445},{"className":444},[],[446],{"type":46,"value":447},"get_it",{"type":46,"value":449},").",{"type":40,"tag":60,"props":451,"children":453},{"className":452},[268],[454,457,458,463,465],{"type":40,"tag":271,"props":455,"children":456},{"disabled":273,"type":274},[],{"type":46,"value":277},{"type":40,"tag":127,"props":459,"children":460},{},[461],{"type":46,"value":462},"Step 8: Run Validator.",{"type":46,"value":464}," Execute unit tests for the ViewModel and Repository.\n",{"type":40,"tag":56,"props":466,"children":467},{},[468],{"type":40,"tag":60,"props":469,"children":470},{},[471,476],{"type":40,"tag":351,"props":472,"children":473},{},[474],{"type":46,"value":475},"Feedback Loop:",{"type":46,"value":477}," Run tests -> Review failures -> Fix logic -> Re-run until passing.",{"type":40,"tag":49,"props":479,"children":481},{"id":480},"examples",[482],{"type":46,"value":96},{"type":40,"tag":109,"props":484,"children":486},{"id":485},"data-layer-service-and-repository",[487],{"type":46,"value":488},"Data Layer: Service and Repository",{"type":40,"tag":233,"props":490,"children":494},{"className":491,"code":492,"language":493,"meta":238,"style":238},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F 1. Service (Raw API interaction)\nclass ApiClient {\n  Future\u003CUserApiModel> fetchUser(String id) async {\n    \u002F\u002F HTTP GET implementation...\n  }\n}\n\n\u002F\u002F 2. Repository (Single source of truth, returns Domain Model)\nclass UserRepository {\n  UserRepository({required ApiClient apiClient}) : _apiClient = apiClient;\n  \n  final ApiClient _apiClient;\n  User? _cachedUser;\n\n  Future\u003CUser> getUser(String id) async {\n    if (_cachedUser != null) return _cachedUser!;\n    \n    final apiModel = await _apiClient.fetchUser(id);\n    _cachedUser = User(id: apiModel.id, name: apiModel.fullName); \u002F\u002F Transform to Domain Model\n    return _cachedUser!;\n  }\n}\n","dart",[495],{"type":40,"tag":145,"props":496,"children":497},{"__ignoreMap":238},[498,509,518,527,536,545,554,563,572,581,590,599,608,617,625,634,643,652,661,670,679,687],{"type":40,"tag":499,"props":500,"children":503},"span",{"class":501,"line":502},"line",1,[504],{"type":40,"tag":499,"props":505,"children":506},{},[507],{"type":46,"value":508},"\u002F\u002F 1. Service (Raw API interaction)\n",{"type":40,"tag":499,"props":510,"children":512},{"class":501,"line":511},2,[513],{"type":40,"tag":499,"props":514,"children":515},{},[516],{"type":46,"value":517},"class ApiClient {\n",{"type":40,"tag":499,"props":519,"children":521},{"class":501,"line":520},3,[522],{"type":40,"tag":499,"props":523,"children":524},{},[525],{"type":46,"value":526},"  Future\u003CUserApiModel> fetchUser(String id) async {\n",{"type":40,"tag":499,"props":528,"children":530},{"class":501,"line":529},4,[531],{"type":40,"tag":499,"props":532,"children":533},{},[534],{"type":46,"value":535},"    \u002F\u002F HTTP GET implementation...\n",{"type":40,"tag":499,"props":537,"children":539},{"class":501,"line":538},5,[540],{"type":40,"tag":499,"props":541,"children":542},{},[543],{"type":46,"value":544},"  }\n",{"type":40,"tag":499,"props":546,"children":548},{"class":501,"line":547},6,[549],{"type":40,"tag":499,"props":550,"children":551},{},[552],{"type":46,"value":553},"}\n",{"type":40,"tag":499,"props":555,"children":557},{"class":501,"line":556},7,[558],{"type":40,"tag":499,"props":559,"children":560},{"emptyLinePlaceholder":273},[561],{"type":46,"value":562},"\n",{"type":40,"tag":499,"props":564,"children":566},{"class":501,"line":565},8,[567],{"type":40,"tag":499,"props":568,"children":569},{},[570],{"type":46,"value":571},"\u002F\u002F 2. Repository (Single source of truth, returns Domain Model)\n",{"type":40,"tag":499,"props":573,"children":575},{"class":501,"line":574},9,[576],{"type":40,"tag":499,"props":577,"children":578},{},[579],{"type":46,"value":580},"class UserRepository {\n",{"type":40,"tag":499,"props":582,"children":584},{"class":501,"line":583},10,[585],{"type":40,"tag":499,"props":586,"children":587},{},[588],{"type":46,"value":589},"  UserRepository({required ApiClient apiClient}) : _apiClient = apiClient;\n",{"type":40,"tag":499,"props":591,"children":593},{"class":501,"line":592},11,[594],{"type":40,"tag":499,"props":595,"children":596},{},[597],{"type":46,"value":598},"  \n",{"type":40,"tag":499,"props":600,"children":602},{"class":501,"line":601},12,[603],{"type":40,"tag":499,"props":604,"children":605},{},[606],{"type":46,"value":607},"  final ApiClient _apiClient;\n",{"type":40,"tag":499,"props":609,"children":611},{"class":501,"line":610},13,[612],{"type":40,"tag":499,"props":613,"children":614},{},[615],{"type":46,"value":616},"  User? _cachedUser;\n",{"type":40,"tag":499,"props":618,"children":620},{"class":501,"line":619},14,[621],{"type":40,"tag":499,"props":622,"children":623},{"emptyLinePlaceholder":273},[624],{"type":46,"value":562},{"type":40,"tag":499,"props":626,"children":628},{"class":501,"line":627},15,[629],{"type":40,"tag":499,"props":630,"children":631},{},[632],{"type":46,"value":633},"  Future\u003CUser> getUser(String id) async {\n",{"type":40,"tag":499,"props":635,"children":637},{"class":501,"line":636},16,[638],{"type":40,"tag":499,"props":639,"children":640},{},[641],{"type":46,"value":642},"    if (_cachedUser != null) return _cachedUser!;\n",{"type":40,"tag":499,"props":644,"children":646},{"class":501,"line":645},17,[647],{"type":40,"tag":499,"props":648,"children":649},{},[650],{"type":46,"value":651},"    \n",{"type":40,"tag":499,"props":653,"children":655},{"class":501,"line":654},18,[656],{"type":40,"tag":499,"props":657,"children":658},{},[659],{"type":46,"value":660},"    final apiModel = await _apiClient.fetchUser(id);\n",{"type":40,"tag":499,"props":662,"children":664},{"class":501,"line":663},19,[665],{"type":40,"tag":499,"props":666,"children":667},{},[668],{"type":46,"value":669},"    _cachedUser = User(id: apiModel.id, name: apiModel.fullName); \u002F\u002F Transform to Domain Model\n",{"type":40,"tag":499,"props":671,"children":673},{"class":501,"line":672},20,[674],{"type":40,"tag":499,"props":675,"children":676},{},[677],{"type":46,"value":678},"    return _cachedUser!;\n",{"type":40,"tag":499,"props":680,"children":682},{"class":501,"line":681},21,[683],{"type":40,"tag":499,"props":684,"children":685},{},[686],{"type":46,"value":544},{"type":40,"tag":499,"props":688,"children":690},{"class":501,"line":689},22,[691],{"type":40,"tag":499,"props":692,"children":693},{},[694],{"type":46,"value":553},{"type":40,"tag":109,"props":696,"children":698},{"id":697},"ui-layer-viewmodel-and-view",[699],{"type":46,"value":700},"UI Layer: ViewModel and View",{"type":40,"tag":233,"props":702,"children":704},{"className":491,"code":703,"language":493,"meta":238,"style":238},"\u002F\u002F 3. ViewModel (State management and presentation logic)\nclass ProfileViewModel extends ChangeNotifier {\n  ProfileViewModel({required UserRepository userRepository}) \n      : _userRepository = userRepository;\n\n  final UserRepository _userRepository;\n\n  User? _user;\n  User? get user => _user;\n\n  bool _isLoading = false;\n  bool get isLoading => _isLoading;\n\n  Future\u003Cvoid> loadProfile(String id) async {\n    _isLoading = true;\n    notifyListeners();\n\n    try {\n      _user = await _userRepository.getUser(id);\n    } finally {\n      _isLoading = false;\n      notifyListeners();\n    }\n  }\n}\n\n\u002F\u002F 4. View (Dumb UI component)\nclass ProfileView extends StatelessWidget {\n  const ProfileView({super.key, required this.viewModel});\n\n  final ProfileViewModel viewModel;\n\n  @override\n  Widget build(BuildContext context) {\n    return ListenableBuilder(\n      listenable: viewModel,\n      builder: (context, _) {\n        if (viewModel.isLoading) {\n          return const Center(child: CircularProgressIndicator());\n        }\n        \n        final user = viewModel.user;\n        if (user == null) {\n          return const Center(child: Text('User not found'));\n        }\n\n        return Column(\n          children: [\n            Text(user.name),\n            ElevatedButton(\n              onPressed: () => viewModel.loadProfile(user.id),\n              child: const Text('Refresh'),\n            ),\n          ],\n        );\n      },\n    );\n  }\n}\n",[705],{"type":40,"tag":145,"props":706,"children":707},{"__ignoreMap":238},[708,716,724,732,740,747,755,762,770,778,785,793,801,808,816,824,832,839,847,855,863,871,879,888,896,904,912,921,930,939,947,956,964,973,982,991,1000,1009,1018,1027,1036,1045,1054,1063,1072,1080,1088,1097,1106,1115,1124,1133,1142,1151,1160,1169,1178,1187,1195],{"type":40,"tag":499,"props":709,"children":710},{"class":501,"line":502},[711],{"type":40,"tag":499,"props":712,"children":713},{},[714],{"type":46,"value":715},"\u002F\u002F 3. ViewModel (State management and presentation logic)\n",{"type":40,"tag":499,"props":717,"children":718},{"class":501,"line":511},[719],{"type":40,"tag":499,"props":720,"children":721},{},[722],{"type":46,"value":723},"class ProfileViewModel extends ChangeNotifier {\n",{"type":40,"tag":499,"props":725,"children":726},{"class":501,"line":520},[727],{"type":40,"tag":499,"props":728,"children":729},{},[730],{"type":46,"value":731},"  ProfileViewModel({required UserRepository userRepository}) \n",{"type":40,"tag":499,"props":733,"children":734},{"class":501,"line":529},[735],{"type":40,"tag":499,"props":736,"children":737},{},[738],{"type":46,"value":739},"      : _userRepository = userRepository;\n",{"type":40,"tag":499,"props":741,"children":742},{"class":501,"line":538},[743],{"type":40,"tag":499,"props":744,"children":745},{"emptyLinePlaceholder":273},[746],{"type":46,"value":562},{"type":40,"tag":499,"props":748,"children":749},{"class":501,"line":547},[750],{"type":40,"tag":499,"props":751,"children":752},{},[753],{"type":46,"value":754},"  final UserRepository _userRepository;\n",{"type":40,"tag":499,"props":756,"children":757},{"class":501,"line":556},[758],{"type":40,"tag":499,"props":759,"children":760},{"emptyLinePlaceholder":273},[761],{"type":46,"value":562},{"type":40,"tag":499,"props":763,"children":764},{"class":501,"line":565},[765],{"type":40,"tag":499,"props":766,"children":767},{},[768],{"type":46,"value":769},"  User? _user;\n",{"type":40,"tag":499,"props":771,"children":772},{"class":501,"line":574},[773],{"type":40,"tag":499,"props":774,"children":775},{},[776],{"type":46,"value":777},"  User? get user => _user;\n",{"type":40,"tag":499,"props":779,"children":780},{"class":501,"line":583},[781],{"type":40,"tag":499,"props":782,"children":783},{"emptyLinePlaceholder":273},[784],{"type":46,"value":562},{"type":40,"tag":499,"props":786,"children":787},{"class":501,"line":592},[788],{"type":40,"tag":499,"props":789,"children":790},{},[791],{"type":46,"value":792},"  bool _isLoading = false;\n",{"type":40,"tag":499,"props":794,"children":795},{"class":501,"line":601},[796],{"type":40,"tag":499,"props":797,"children":798},{},[799],{"type":46,"value":800},"  bool get isLoading => _isLoading;\n",{"type":40,"tag":499,"props":802,"children":803},{"class":501,"line":610},[804],{"type":40,"tag":499,"props":805,"children":806},{"emptyLinePlaceholder":273},[807],{"type":46,"value":562},{"type":40,"tag":499,"props":809,"children":810},{"class":501,"line":619},[811],{"type":40,"tag":499,"props":812,"children":813},{},[814],{"type":46,"value":815},"  Future\u003Cvoid> loadProfile(String id) async {\n",{"type":40,"tag":499,"props":817,"children":818},{"class":501,"line":627},[819],{"type":40,"tag":499,"props":820,"children":821},{},[822],{"type":46,"value":823},"    _isLoading = true;\n",{"type":40,"tag":499,"props":825,"children":826},{"class":501,"line":636},[827],{"type":40,"tag":499,"props":828,"children":829},{},[830],{"type":46,"value":831},"    notifyListeners();\n",{"type":40,"tag":499,"props":833,"children":834},{"class":501,"line":645},[835],{"type":40,"tag":499,"props":836,"children":837},{"emptyLinePlaceholder":273},[838],{"type":46,"value":562},{"type":40,"tag":499,"props":840,"children":841},{"class":501,"line":654},[842],{"type":40,"tag":499,"props":843,"children":844},{},[845],{"type":46,"value":846},"    try {\n",{"type":40,"tag":499,"props":848,"children":849},{"class":501,"line":663},[850],{"type":40,"tag":499,"props":851,"children":852},{},[853],{"type":46,"value":854},"      _user = await _userRepository.getUser(id);\n",{"type":40,"tag":499,"props":856,"children":857},{"class":501,"line":672},[858],{"type":40,"tag":499,"props":859,"children":860},{},[861],{"type":46,"value":862},"    } finally {\n",{"type":40,"tag":499,"props":864,"children":865},{"class":501,"line":681},[866],{"type":40,"tag":499,"props":867,"children":868},{},[869],{"type":46,"value":870},"      _isLoading = false;\n",{"type":40,"tag":499,"props":872,"children":873},{"class":501,"line":689},[874],{"type":40,"tag":499,"props":875,"children":876},{},[877],{"type":46,"value":878},"      notifyListeners();\n",{"type":40,"tag":499,"props":880,"children":882},{"class":501,"line":881},23,[883],{"type":40,"tag":499,"props":884,"children":885},{},[886],{"type":46,"value":887},"    }\n",{"type":40,"tag":499,"props":889,"children":891},{"class":501,"line":890},24,[892],{"type":40,"tag":499,"props":893,"children":894},{},[895],{"type":46,"value":544},{"type":40,"tag":499,"props":897,"children":899},{"class":501,"line":898},25,[900],{"type":40,"tag":499,"props":901,"children":902},{},[903],{"type":46,"value":553},{"type":40,"tag":499,"props":905,"children":907},{"class":501,"line":906},26,[908],{"type":40,"tag":499,"props":909,"children":910},{"emptyLinePlaceholder":273},[911],{"type":46,"value":562},{"type":40,"tag":499,"props":913,"children":915},{"class":501,"line":914},27,[916],{"type":40,"tag":499,"props":917,"children":918},{},[919],{"type":46,"value":920},"\u002F\u002F 4. View (Dumb UI component)\n",{"type":40,"tag":499,"props":922,"children":924},{"class":501,"line":923},28,[925],{"type":40,"tag":499,"props":926,"children":927},{},[928],{"type":46,"value":929},"class ProfileView extends StatelessWidget {\n",{"type":40,"tag":499,"props":931,"children":933},{"class":501,"line":932},29,[934],{"type":40,"tag":499,"props":935,"children":936},{},[937],{"type":46,"value":938},"  const ProfileView({super.key, required this.viewModel});\n",{"type":40,"tag":499,"props":940,"children":942},{"class":501,"line":941},30,[943],{"type":40,"tag":499,"props":944,"children":945},{"emptyLinePlaceholder":273},[946],{"type":46,"value":562},{"type":40,"tag":499,"props":948,"children":950},{"class":501,"line":949},31,[951],{"type":40,"tag":499,"props":952,"children":953},{},[954],{"type":46,"value":955},"  final ProfileViewModel viewModel;\n",{"type":40,"tag":499,"props":957,"children":959},{"class":501,"line":958},32,[960],{"type":40,"tag":499,"props":961,"children":962},{"emptyLinePlaceholder":273},[963],{"type":46,"value":562},{"type":40,"tag":499,"props":965,"children":967},{"class":501,"line":966},33,[968],{"type":40,"tag":499,"props":969,"children":970},{},[971],{"type":46,"value":972},"  @override\n",{"type":40,"tag":499,"props":974,"children":976},{"class":501,"line":975},34,[977],{"type":40,"tag":499,"props":978,"children":979},{},[980],{"type":46,"value":981},"  Widget build(BuildContext context) {\n",{"type":40,"tag":499,"props":983,"children":985},{"class":501,"line":984},35,[986],{"type":40,"tag":499,"props":987,"children":988},{},[989],{"type":46,"value":990},"    return ListenableBuilder(\n",{"type":40,"tag":499,"props":992,"children":994},{"class":501,"line":993},36,[995],{"type":40,"tag":499,"props":996,"children":997},{},[998],{"type":46,"value":999},"      listenable: viewModel,\n",{"type":40,"tag":499,"props":1001,"children":1003},{"class":501,"line":1002},37,[1004],{"type":40,"tag":499,"props":1005,"children":1006},{},[1007],{"type":46,"value":1008},"      builder: (context, _) {\n",{"type":40,"tag":499,"props":1010,"children":1012},{"class":501,"line":1011},38,[1013],{"type":40,"tag":499,"props":1014,"children":1015},{},[1016],{"type":46,"value":1017},"        if (viewModel.isLoading) {\n",{"type":40,"tag":499,"props":1019,"children":1021},{"class":501,"line":1020},39,[1022],{"type":40,"tag":499,"props":1023,"children":1024},{},[1025],{"type":46,"value":1026},"          return const Center(child: CircularProgressIndicator());\n",{"type":40,"tag":499,"props":1028,"children":1030},{"class":501,"line":1029},40,[1031],{"type":40,"tag":499,"props":1032,"children":1033},{},[1034],{"type":46,"value":1035},"        }\n",{"type":40,"tag":499,"props":1037,"children":1039},{"class":501,"line":1038},41,[1040],{"type":40,"tag":499,"props":1041,"children":1042},{},[1043],{"type":46,"value":1044},"        \n",{"type":40,"tag":499,"props":1046,"children":1048},{"class":501,"line":1047},42,[1049],{"type":40,"tag":499,"props":1050,"children":1051},{},[1052],{"type":46,"value":1053},"        final user = viewModel.user;\n",{"type":40,"tag":499,"props":1055,"children":1057},{"class":501,"line":1056},43,[1058],{"type":40,"tag":499,"props":1059,"children":1060},{},[1061],{"type":46,"value":1062},"        if (user == null) {\n",{"type":40,"tag":499,"props":1064,"children":1066},{"class":501,"line":1065},44,[1067],{"type":40,"tag":499,"props":1068,"children":1069},{},[1070],{"type":46,"value":1071},"          return const Center(child: Text('User not found'));\n",{"type":40,"tag":499,"props":1073,"children":1075},{"class":501,"line":1074},45,[1076],{"type":40,"tag":499,"props":1077,"children":1078},{},[1079],{"type":46,"value":1035},{"type":40,"tag":499,"props":1081,"children":1083},{"class":501,"line":1082},46,[1084],{"type":40,"tag":499,"props":1085,"children":1086},{"emptyLinePlaceholder":273},[1087],{"type":46,"value":562},{"type":40,"tag":499,"props":1089,"children":1091},{"class":501,"line":1090},47,[1092],{"type":40,"tag":499,"props":1093,"children":1094},{},[1095],{"type":46,"value":1096},"        return Column(\n",{"type":40,"tag":499,"props":1098,"children":1100},{"class":501,"line":1099},48,[1101],{"type":40,"tag":499,"props":1102,"children":1103},{},[1104],{"type":46,"value":1105},"          children: [\n",{"type":40,"tag":499,"props":1107,"children":1109},{"class":501,"line":1108},49,[1110],{"type":40,"tag":499,"props":1111,"children":1112},{},[1113],{"type":46,"value":1114},"            Text(user.name),\n",{"type":40,"tag":499,"props":1116,"children":1118},{"class":501,"line":1117},50,[1119],{"type":40,"tag":499,"props":1120,"children":1121},{},[1122],{"type":46,"value":1123},"            ElevatedButton(\n",{"type":40,"tag":499,"props":1125,"children":1127},{"class":501,"line":1126},51,[1128],{"type":40,"tag":499,"props":1129,"children":1130},{},[1131],{"type":46,"value":1132},"              onPressed: () => viewModel.loadProfile(user.id),\n",{"type":40,"tag":499,"props":1134,"children":1136},{"class":501,"line":1135},52,[1137],{"type":40,"tag":499,"props":1138,"children":1139},{},[1140],{"type":46,"value":1141},"              child: const Text('Refresh'),\n",{"type":40,"tag":499,"props":1143,"children":1145},{"class":501,"line":1144},53,[1146],{"type":40,"tag":499,"props":1147,"children":1148},{},[1149],{"type":46,"value":1150},"            ),\n",{"type":40,"tag":499,"props":1152,"children":1154},{"class":501,"line":1153},54,[1155],{"type":40,"tag":499,"props":1156,"children":1157},{},[1158],{"type":46,"value":1159},"          ],\n",{"type":40,"tag":499,"props":1161,"children":1163},{"class":501,"line":1162},55,[1164],{"type":40,"tag":499,"props":1165,"children":1166},{},[1167],{"type":46,"value":1168},"        );\n",{"type":40,"tag":499,"props":1170,"children":1172},{"class":501,"line":1171},56,[1173],{"type":40,"tag":499,"props":1174,"children":1175},{},[1176],{"type":46,"value":1177},"      },\n",{"type":40,"tag":499,"props":1179,"children":1181},{"class":501,"line":1180},57,[1182],{"type":40,"tag":499,"props":1183,"children":1184},{},[1185],{"type":46,"value":1186},"    );\n",{"type":40,"tag":499,"props":1188,"children":1190},{"class":501,"line":1189},58,[1191],{"type":40,"tag":499,"props":1192,"children":1193},{},[1194],{"type":46,"value":544},{"type":40,"tag":499,"props":1196,"children":1198},{"class":501,"line":1197},59,[1199],{"type":40,"tag":499,"props":1200,"children":1201},{},[1202],{"type":46,"value":553},{"type":40,"tag":1204,"props":1205,"children":1206},"style",{},[1207],{"type":46,"value":1208},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1210,"total":890},[1211,1223,1234,1246,1257,1266,1278],{"slug":1212,"name":1212,"fn":1213,"description":1214,"org":1215,"tags":1216,"stars":21,"repoUrl":22,"updatedAt":1222},"dart-add-unit-test","write unit tests for Dart code","Write and organize unit tests for functions, methods, and classes using `package:test`. Use when creating new logic or fixing bugs to ensure code remains correct and regression-free.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1217,1219],{"name":1218,"slug":493,"type":14},"Dart",{"name":1220,"slug":1221,"type":14},"Testing","testing","2026-07-15T05:22:40.104823",{"slug":1224,"name":1224,"fn":1225,"description":1226,"org":1227,"tags":1228,"stars":21,"repoUrl":22,"updatedAt":1233},"dart-build-cli-app","build Dart command line applications","Entrypoint structure, exit codes, cross-platform scripts. Use when building command line utilities, scripts, or applications.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1229,1232],{"name":1230,"slug":1231,"type":14},"CLI","cli",{"name":1218,"slug":493,"type":14},"2026-07-15T05:22:18.863572",{"slug":1235,"name":1235,"fn":1236,"description":1237,"org":1238,"tags":1239,"stars":21,"repoUrl":22,"updatedAt":1245},"dart-collect-coverage","collect Dart test coverage reports","Collect coverage using the coverage packge and create an LCOV report",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1240,1241,1244],{"name":1218,"slug":493,"type":14},{"name":1242,"slug":1243,"type":14},"Reporting","reporting",{"name":1220,"slug":1221,"type":14},"2026-07-15T05:22:21.38636",{"slug":1247,"name":1247,"fn":1248,"description":1249,"org":1250,"tags":1251,"stars":21,"repoUrl":22,"updatedAt":1256},"dart-fix-runtime-errors","debug and fix Dart runtime errors","Uses get_runtime_errors and lsp to fetch an active stack trace, locate the failing line, apply a fix, and verify resolution via hot_reload.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1252,1253],{"name":1218,"slug":493,"type":14},{"name":1254,"slug":1255,"type":14},"Debugging","debugging","2026-07-15T05:22:22.622501",{"slug":1258,"name":1258,"fn":1259,"description":1260,"org":1261,"tags":1262,"stars":21,"repoUrl":22,"updatedAt":1265},"dart-generate-test-mocks","generate mock objects for Dart tests","Define and generate mock objects for external dependencies using `package:mockito` and `build_runner`. Use when unit testing classes that depend on complex external services like APIs or databases.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1263,1264],{"name":1218,"slug":493,"type":14},{"name":1220,"slug":1221,"type":14},"2026-07-15T05:22:42.607449",{"slug":1267,"name":1267,"fn":1268,"description":1269,"org":1270,"tags":1271,"stars":21,"repoUrl":22,"updatedAt":1277},"dart-migrate-to-checks-package","migrate test matchers to checks package","Replace the usage of `expect` and similar functions from `package:matcher`\nto `package:checks` equivalents.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1272,1273,1276],{"name":1218,"slug":493,"type":14},{"name":1274,"slug":1275,"type":14},"Migration","migration",{"name":1220,"slug":1221,"type":14},"2026-07-15T05:22:31.276564",{"slug":1279,"name":1279,"fn":1280,"description":1281,"org":1282,"tags":1283,"stars":21,"repoUrl":22,"updatedAt":1287},"dart-resolve-package-conflicts","resolve Dart package version conflicts","Workflow for fixing package version conflicts. Use this when `pub get` fails due to incompatible package versions.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1284,1285,1286],{"name":1218,"slug":493,"type":14},{"name":1254,"slug":1255,"type":14},{"name":19,"slug":20,"type":14},"2026-07-15T05:22:30.059335",{"items":1289,"total":914},[1290,1295,1300,1306,1311,1316,1322,1328,1340,1352,1366,1376],{"slug":1212,"name":1212,"fn":1213,"description":1214,"org":1291,"tags":1292,"stars":21,"repoUrl":22,"updatedAt":1222},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1293,1294],{"name":1218,"slug":493,"type":14},{"name":1220,"slug":1221,"type":14},{"slug":1224,"name":1224,"fn":1225,"description":1226,"org":1296,"tags":1297,"stars":21,"repoUrl":22,"updatedAt":1233},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1298,1299],{"name":1230,"slug":1231,"type":14},{"name":1218,"slug":493,"type":14},{"slug":1235,"name":1235,"fn":1236,"description":1237,"org":1301,"tags":1302,"stars":21,"repoUrl":22,"updatedAt":1245},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1303,1304,1305],{"name":1218,"slug":493,"type":14},{"name":1242,"slug":1243,"type":14},{"name":1220,"slug":1221,"type":14},{"slug":1247,"name":1247,"fn":1248,"description":1249,"org":1307,"tags":1308,"stars":21,"repoUrl":22,"updatedAt":1256},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1309,1310],{"name":1218,"slug":493,"type":14},{"name":1254,"slug":1255,"type":14},{"slug":1258,"name":1258,"fn":1259,"description":1260,"org":1312,"tags":1313,"stars":21,"repoUrl":22,"updatedAt":1265},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1314,1315],{"name":1218,"slug":493,"type":14},{"name":1220,"slug":1221,"type":14},{"slug":1267,"name":1267,"fn":1268,"description":1269,"org":1317,"tags":1318,"stars":21,"repoUrl":22,"updatedAt":1277},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1319,1320,1321],{"name":1218,"slug":493,"type":14},{"name":1274,"slug":1275,"type":14},{"name":1220,"slug":1221,"type":14},{"slug":1279,"name":1279,"fn":1280,"description":1281,"org":1323,"tags":1324,"stars":21,"repoUrl":22,"updatedAt":1287},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1325,1326,1327],{"name":1218,"slug":493,"type":14},{"name":1254,"slug":1255,"type":14},{"name":19,"slug":20,"type":14},{"slug":1329,"name":1329,"fn":1330,"description":1331,"org":1332,"tags":1333,"stars":21,"repoUrl":22,"updatedAt":1339},"dart-run-static-analysis","run static analysis and apply fixes","Execute `dart analyze` to identify warnings and errors, and use `dart fix --apply` to automatically resolve mechanical lint issues. Use during development to ensure code quality and before committing changes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1334,1337,1338],{"name":1335,"slug":1336,"type":14},"Code Analysis","code-analysis",{"name":1218,"slug":493,"type":14},{"name":1254,"slug":1255,"type":14},"2026-07-15T05:22:23.861119",{"slug":1341,"name":1341,"fn":1342,"description":1343,"org":1344,"tags":1345,"stars":21,"repoUrl":22,"updatedAt":1351},"dart-setup-ffi-assets","package C\u002FC++ assets for Dart","Guides agents in compiling and packaging C\u002FC++ source code into dynamic or static libraries (Code Assets) using Dart's Native Assets hook system (via hook\u002Fbuild.dart and hook\u002Flink.dart utilizing package:hooks and package:native_toolchain_c). Use when a user asks to: 'setup native assets', 'compile C\u002FC++ source code', 'bundle dynamic libraries', 'build native C code', 'link native assets', 'implement build.dart or link.dart hooks', or 'integrate C\u002FC++ interop in Dart\u002FFlutter'. Helps agents avoid manual toolchain orchestration and configures secure hash-validated binary downloads or advanced linker tree-shaking with package:record_use mapping.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1346,1347,1350],{"name":1218,"slug":493,"type":14},{"name":1348,"slug":1349,"type":14},"Deployment","deployment",{"name":19,"slug":20,"type":14},"2026-07-15T05:22:20.138636",{"slug":1353,"name":1353,"fn":1354,"description":1355,"org":1356,"tags":1357,"stars":21,"repoUrl":22,"updatedAt":1365},"dart-skills-lint-setup","configure dart_skills_lint for Dart projects","Use this skill when you need to set up validation for AI agent skills in a Dart project for the first time.\nAdds the linter as a dev_dependency, creates a configuration file, and generates a baseline for legacy repos.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1358,1359,1362],{"name":1218,"slug":493,"type":14},{"name":1360,"slug":1361,"type":14},"Plugin Development","plugin-development",{"name":1363,"slug":1364,"type":14},"QA","qa","2026-07-15T05:22:47.488998",{"slug":1367,"name":1367,"fn":1368,"description":1369,"org":1370,"tags":1371,"stars":21,"repoUrl":22,"updatedAt":1375},"dart-skills-lint-validation","validate agent skills with dart_skills_lint","Use this skill when you need to validate AI agent skills with dart_skills_lint — running the linter, interpreting failures, fixing violations, and authoring custom rules.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1372,1373,1374],{"name":1218,"slug":493,"type":14},{"name":1360,"slug":1361,"type":14},{"name":1363,"slug":1364,"type":14},"2026-07-21T05:38:34.451024",{"slug":1377,"name":1377,"fn":1378,"description":1379,"org":1380,"tags":1381,"stars":21,"repoUrl":22,"updatedAt":1384},"dart-use-ffigen","generate FFI bindings with ffigen","Guide agents to use `package:ffigen` to automatically generate FFI bindings instead of writing them manually. Use this skill when a task involves writing new FFI bindings, extending C\u002FObjective-C\u002FSwift integrations, or replacing hand-crafted `dart:ffi` setups.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1382,1383],{"name":1218,"slug":493,"type":14},{"name":19,"slug":20,"type":14},"2026-07-15T05:22:17.592351"]