[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-flutter-integrate-genui-firebase":3,"mdc-kr08zl-key":31,"related-org-flutter-integrate-genui-firebase":1178,"related-repo-flutter-integrate-genui-firebase":1319},{"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},"integrate-genui-firebase","integrate Flutter genui with Firebase AI Logic","Use this skill when the user asks to integrate the genui package and get a simple conversation going with Firebase AI Logic.",{"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},"Mobile","mobile",{"name":19,"slug":20,"type":14},"Firebase","firebase",1703,"https:\u002F\u002Fgithub.com\u002Fflutter\u002Fgenui","2026-04-16T05:04:52.392424",null,159,[],{"repoUrl":22,"stars":21,"forks":25,"topics":28,"description":24},[],"https:\u002F\u002Fgithub.com\u002Fflutter\u002Fgenui\u002Ftree\u002FHEAD\u002Fpackages\u002Fgenui\u002Fskills\u002Fintegrate-genui-firebase","---\nname: integrate-genui-firebase\ndescription: Use this skill when the user asks to integrate the genui package and get a simple conversation going with Firebase AI Logic.\n---\n\n# Integrate GenUI with Firebase AI Logic\n\n## Goal\nTo successfully integrate the `genui` package into a Flutter app and set up a basic conversational agent using Firebase AI Logic. This skill assumes Firebase AI Logic is already set up and working in the project.\n\n## Instructions\nWhen tasked with integrating `genui` and starting a simple conversation, follow these steps:\n\n1. **Verify Firebase Setup:**\n   Ensure `firebase_core` and `firebase_ai` are available in `pubspec.yaml`.\n   Verify that `Firebase.initializeApp` is called in the `main()` function:\n   ```dart\n   WidgetsFlutterBinding.ensureInitialized();\n   await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);\n   ```\n\n2. **Add GenUI Package:**\n   Add `genui` to the `pubspec.yaml` dependencies.\n\n3. **Import Required Libraries:**\n   Import `genui` and hide `TextPart` so it doesn't conflict with other packages, then import it again with an alias:\n   ```dart\n   import 'package:genui\u002Fgenui.dart' hide TextPart;\n   import 'package:genui\u002Fgenui.dart' as genui;\n   ```\n\n4. **Configure Basic Logging:**\n   At the beginning of the `main()` function, configure GenUI logging:\n   ```dart\n   configureLogging(\n     logCallback: (level, msg) => debugPrint('GenUI $level: $msg'),\n   );\n   ```\n\n5. **Create Model and Chat Session:**\n   Initialize the generative model and start a chat session.\n   ```dart\n   final model = FirebaseAI.googleAI().generativeModel(\n     model: 'gemini-3-flash-preview',\n   );\n   final _chatSession = model.startChat();\n   ```\n\n6. **Identify Target StatefulWidget:**\n   **STOP AND ASK THE USER IF UNCLEAR:** This integration requires a `StatefulWidget` to hold the references to GenUI controllers (`SurfaceController`, `A2uiTransportAdapter`, and `Conversation`). Identify which `StatefulWidget` to use in the application. If you are unsure which widget should hold this state, ask the user before proceeding.\n\n7. **Wire up GenUI Controllers inside State:**\n   Inside your identified `State` class, instantiate `SurfaceController`, `A2uiTransportAdapter`, and `Conversation`:\n   ```dart\n   final catalog = BasicCatalogItems.asCatalog(); \u002F\u002F Optionally inject custom CatalogItems\n   final _controller = SurfaceController(catalogs: [catalog]);\n   final _transport = A2uiTransportAdapter(onSend: _sendAndReceive);\n   final _conversation = Conversation(\n     controller: _controller,\n     transport: _transport,\n   );\n   ```\n\n8. **Implement the `_sendAndReceive` Method:**\n   Create a method to take messages from the transport adapter, send them to Firebase, and feed the AI's response back to the transport.\n   ```dart\n   Future\u003Cvoid> _sendAndReceive(ChatMessage msg) async {\n     final buffer = StringBuffer();\n\n     for (final part in msg.parts) {\n       if (part.isUiInteractionPart) {\n         buffer.write(part.asUiInteractionPart!.interaction);\n       } else if (part is genui.TextPart) {\n         buffer.write(part.text);\n       }\n     }\n\n     if (buffer.isEmpty) return;\n\n     final text = buffer.toString();\n     final response = await _chatSession.sendMessage(Content.text(text));\n\n     if (response.text?.isNotEmpty ?? false) {\n       _transport.addChunk(response.text!);\n     }\n   }\n   ```\n\n9. **Listen to Conversation Events:**\n   Create stubbed-out methods in your State class for each event type, including DartDoc comments explaining their required behavior. Depending on the interface design, new surfaces and text coming from the agent will be handled in different ways. A conversational interface might add everything to a list that's display in a `ListView`, for example, while an interface featuring UI components in specific locations (such as headers, footers, etc.) might rely on specific surface IDs given to the agent in the system instruction to know which surfaces to display in which locations.\n   ```dart\n   \u002F\u002F\u002F Updates state to include the new [surfaceId] so a new `Surface` widget can be built.\n   void _onSurfaceAdded(String surfaceId) {\n     \u002F\u002F TODO: Implement state update to add surfaceId\n   }\n\n   \u002F\u002F\u002F Updates state to remove the [surfaceId] so its `Surface` widget is no longer built.\n   void _onSurfaceRemoved(String surfaceId) {\n     \u002F\u002F TODO: Implement state update to remove surfaceId\n   }\n\n   \u002F\u002F\u002F Handles displaying raw text content received from the AI to the user.\n   void _onContentReceived(String text) {\n     \u002F\u002F TODO: Implement displaying the received text\n   }\n\n   \u002F\u002F\u002F Handles errors that occur during the conversation appropriately.\n   void _onError(Object error) {\n     \u002F\u002F TODO: Implement error handling\n   }\n   ```\n\n   Subscribe to `_conversation.events` to track when UI surfaces or chat messages arrive, dispatching them to the appropriate stubbed out methods:\n   ```dart\n   _conversation.events.listen((event) {\n     switch (event) {\n       case ConversationSurfaceAdded added:\n         _onSurfaceAdded(added.surfaceId);\n       case ConversationSurfaceRemoved removed:\n         _onSurfaceRemoved(removed.surfaceId);\n       case ConversationContentReceived content:\n         _onContentReceived(content.text);\n       case ConversationError error:\n         _onError(error.error);\n       default:\n     }\n   });\n   ```\n\n10. **Initialize System Prompt:**\n    Use `PromptBuilder` to give the AI basic instructions, then send it as a system message.\n    ```dart\n    final promptBuilder = PromptBuilder.chat(\n      catalog: catalog,\n      instructions: 'You are a helpful assistant. Respond to messages in a chatty way.',\n    );\n    _conversation.sendRequest(ChatMessage.system(promptBuilder.systemPrompt));\n    ```\n\n11. **Display Surfaces:**\n    In your Flutter `build()` method, use the `Surface` widget wherever you need to render GenUI widgets using the `surfaceIds` you collected in step 9.\n    ```dart\n    Surface(surfaceContext: _controller.contextFor(surfaceId));\n    ```\n\n12. **Ask User for Input Preferences:**\n    **STOP AND ASK THE USER:** Ask the user for clarification on what UI elements should be used for user input. Explain that a `TextField` and `ElevatedButton` are good defaults, but you should not assume they want those exact widgets unless they clarify.\n\n## Constraints\n- Do not make assumptions about user input UI elements; see step 12.\n- Make sure to properly clean up GenUI controllers (`_transport.dispose()`, `_controller.dispose()`) inside the widget's `dispose()` method.\n",{"data":32,"body":33},{"name":4,"description":6},{"type":34,"children":35},"root",[36,45,52,67,73,85,1129,1135,1172],{"type":37,"tag":38,"props":39,"children":41},"element","h1",{"id":40},"integrate-genui-with-firebase-ai-logic",[42],{"type":43,"value":44},"text","Integrate GenUI with Firebase AI Logic",{"type":37,"tag":46,"props":47,"children":49},"h2",{"id":48},"goal",[50],{"type":43,"value":51},"Goal",{"type":37,"tag":53,"props":54,"children":55},"p",{},[56,58,65],{"type":43,"value":57},"To successfully integrate the ",{"type":37,"tag":59,"props":60,"children":62},"code",{"className":61},[],[63],{"type":43,"value":64},"genui",{"type":43,"value":66}," package into a Flutter app and set up a basic conversational agent using Firebase AI Logic. This skill assumes Firebase AI Logic is already set up and working in the project.",{"type":37,"tag":46,"props":68,"children":70},{"id":69},"instructions",[71],{"type":43,"value":72},"Instructions",{"type":37,"tag":53,"props":74,"children":75},{},[76,78,83],{"type":43,"value":77},"When tasked with integrating ",{"type":37,"tag":59,"props":79,"children":81},{"className":80},[],[82],{"type":43,"value":64},{"type":43,"value":84}," and starting a simple conversation, follow these steps:",{"type":37,"tag":86,"props":87,"children":88},"ol",{},[89,172,196,244,293,342,396,498,693,987,1051,1099],{"type":37,"tag":90,"props":91,"children":92},"li",{},[93,99,101,107,109,115,117,123,125,131,133,139,141],{"type":37,"tag":94,"props":95,"children":96},"strong",{},[97],{"type":43,"value":98},"Verify Firebase Setup:",{"type":43,"value":100},"\nEnsure ",{"type":37,"tag":59,"props":102,"children":104},{"className":103},[],[105],{"type":43,"value":106},"firebase_core",{"type":43,"value":108}," and ",{"type":37,"tag":59,"props":110,"children":112},{"className":111},[],[113],{"type":43,"value":114},"firebase_ai",{"type":43,"value":116}," are available in ",{"type":37,"tag":59,"props":118,"children":120},{"className":119},[],[121],{"type":43,"value":122},"pubspec.yaml",{"type":43,"value":124},".\nVerify that ",{"type":37,"tag":59,"props":126,"children":128},{"className":127},[],[129],{"type":43,"value":130},"Firebase.initializeApp",{"type":43,"value":132}," is called in the ",{"type":37,"tag":59,"props":134,"children":136},{"className":135},[],[137],{"type":43,"value":138},"main()",{"type":43,"value":140}," function:",{"type":37,"tag":142,"props":143,"children":148},"pre",{"className":144,"code":145,"language":146,"meta":147,"style":147},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","WidgetsFlutterBinding.ensureInitialized();\nawait Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);\n","dart","",[149],{"type":37,"tag":59,"props":150,"children":151},{"__ignoreMap":147},[152,163],{"type":37,"tag":153,"props":154,"children":157},"span",{"class":155,"line":156},"line",1,[158],{"type":37,"tag":153,"props":159,"children":160},{},[161],{"type":43,"value":162},"WidgetsFlutterBinding.ensureInitialized();\n",{"type":37,"tag":153,"props":164,"children":166},{"class":155,"line":165},2,[167],{"type":37,"tag":153,"props":168,"children":169},{},[170],{"type":43,"value":171},"await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);\n",{"type":37,"tag":90,"props":173,"children":174},{},[175,180,182,187,189,194],{"type":37,"tag":94,"props":176,"children":177},{},[178],{"type":43,"value":179},"Add GenUI Package:",{"type":43,"value":181},"\nAdd ",{"type":37,"tag":59,"props":183,"children":185},{"className":184},[],[186],{"type":43,"value":64},{"type":43,"value":188}," to the ",{"type":37,"tag":59,"props":190,"children":192},{"className":191},[],[193],{"type":43,"value":122},{"type":43,"value":195}," dependencies.",{"type":37,"tag":90,"props":197,"children":198},{},[199,204,206,211,213,219,221],{"type":37,"tag":94,"props":200,"children":201},{},[202],{"type":43,"value":203},"Import Required Libraries:",{"type":43,"value":205},"\nImport ",{"type":37,"tag":59,"props":207,"children":209},{"className":208},[],[210],{"type":43,"value":64},{"type":43,"value":212}," and hide ",{"type":37,"tag":59,"props":214,"children":216},{"className":215},[],[217],{"type":43,"value":218},"TextPart",{"type":43,"value":220}," so it doesn't conflict with other packages, then import it again with an alias:",{"type":37,"tag":142,"props":222,"children":224},{"className":144,"code":223,"language":146,"meta":147,"style":147},"import 'package:genui\u002Fgenui.dart' hide TextPart;\nimport 'package:genui\u002Fgenui.dart' as genui;\n",[225],{"type":37,"tag":59,"props":226,"children":227},{"__ignoreMap":147},[228,236],{"type":37,"tag":153,"props":229,"children":230},{"class":155,"line":156},[231],{"type":37,"tag":153,"props":232,"children":233},{},[234],{"type":43,"value":235},"import 'package:genui\u002Fgenui.dart' hide TextPart;\n",{"type":37,"tag":153,"props":237,"children":238},{"class":155,"line":165},[239],{"type":37,"tag":153,"props":240,"children":241},{},[242],{"type":43,"value":243},"import 'package:genui\u002Fgenui.dart' as genui;\n",{"type":37,"tag":90,"props":245,"children":246},{},[247,252,254,259,261],{"type":37,"tag":94,"props":248,"children":249},{},[250],{"type":43,"value":251},"Configure Basic Logging:",{"type":43,"value":253},"\nAt the beginning of the ",{"type":37,"tag":59,"props":255,"children":257},{"className":256},[],[258],{"type":43,"value":138},{"type":43,"value":260}," function, configure GenUI logging:",{"type":37,"tag":142,"props":262,"children":264},{"className":144,"code":263,"language":146,"meta":147,"style":147},"configureLogging(\n  logCallback: (level, msg) => debugPrint('GenUI $level: $msg'),\n);\n",[265],{"type":37,"tag":59,"props":266,"children":267},{"__ignoreMap":147},[268,276,284],{"type":37,"tag":153,"props":269,"children":270},{"class":155,"line":156},[271],{"type":37,"tag":153,"props":272,"children":273},{},[274],{"type":43,"value":275},"configureLogging(\n",{"type":37,"tag":153,"props":277,"children":278},{"class":155,"line":165},[279],{"type":37,"tag":153,"props":280,"children":281},{},[282],{"type":43,"value":283},"  logCallback: (level, msg) => debugPrint('GenUI $level: $msg'),\n",{"type":37,"tag":153,"props":285,"children":287},{"class":155,"line":286},3,[288],{"type":37,"tag":153,"props":289,"children":290},{},[291],{"type":43,"value":292},");\n",{"type":37,"tag":90,"props":294,"children":295},{},[296,301,303],{"type":37,"tag":94,"props":297,"children":298},{},[299],{"type":43,"value":300},"Create Model and Chat Session:",{"type":43,"value":302},"\nInitialize the generative model and start a chat session.",{"type":37,"tag":142,"props":304,"children":306},{"className":144,"code":305,"language":146,"meta":147,"style":147},"final model = FirebaseAI.googleAI().generativeModel(\n  model: 'gemini-3-flash-preview',\n);\nfinal _chatSession = model.startChat();\n",[307],{"type":37,"tag":59,"props":308,"children":309},{"__ignoreMap":147},[310,318,326,333],{"type":37,"tag":153,"props":311,"children":312},{"class":155,"line":156},[313],{"type":37,"tag":153,"props":314,"children":315},{},[316],{"type":43,"value":317},"final model = FirebaseAI.googleAI().generativeModel(\n",{"type":37,"tag":153,"props":319,"children":320},{"class":155,"line":165},[321],{"type":37,"tag":153,"props":322,"children":323},{},[324],{"type":43,"value":325},"  model: 'gemini-3-flash-preview',\n",{"type":37,"tag":153,"props":327,"children":328},{"class":155,"line":286},[329],{"type":37,"tag":153,"props":330,"children":331},{},[332],{"type":43,"value":292},{"type":37,"tag":153,"props":334,"children":336},{"class":155,"line":335},4,[337],{"type":37,"tag":153,"props":338,"children":339},{},[340],{"type":43,"value":341},"final _chatSession = model.startChat();\n",{"type":37,"tag":90,"props":343,"children":344},{},[345,350,355,357,363,365,371,373,379,381,387,389,394],{"type":37,"tag":94,"props":346,"children":347},{},[348],{"type":43,"value":349},"Identify Target StatefulWidget:",{"type":37,"tag":94,"props":351,"children":352},{},[353],{"type":43,"value":354},"STOP AND ASK THE USER IF UNCLEAR:",{"type":43,"value":356}," This integration requires a ",{"type":37,"tag":59,"props":358,"children":360},{"className":359},[],[361],{"type":43,"value":362},"StatefulWidget",{"type":43,"value":364}," to hold the references to GenUI controllers (",{"type":37,"tag":59,"props":366,"children":368},{"className":367},[],[369],{"type":43,"value":370},"SurfaceController",{"type":43,"value":372},", ",{"type":37,"tag":59,"props":374,"children":376},{"className":375},[],[377],{"type":43,"value":378},"A2uiTransportAdapter",{"type":43,"value":380},", and ",{"type":37,"tag":59,"props":382,"children":384},{"className":383},[],[385],{"type":43,"value":386},"Conversation",{"type":43,"value":388},"). Identify which ",{"type":37,"tag":59,"props":390,"children":392},{"className":391},[],[393],{"type":43,"value":362},{"type":43,"value":395}," to use in the application. If you are unsure which widget should hold this state, ask the user before proceeding.",{"type":37,"tag":90,"props":397,"children":398},{},[399,404,406,412,414,419,420,425,426,431,433],{"type":37,"tag":94,"props":400,"children":401},{},[402],{"type":43,"value":403},"Wire up GenUI Controllers inside State:",{"type":43,"value":405},"\nInside your identified ",{"type":37,"tag":59,"props":407,"children":409},{"className":408},[],[410],{"type":43,"value":411},"State",{"type":43,"value":413}," class, instantiate ",{"type":37,"tag":59,"props":415,"children":417},{"className":416},[],[418],{"type":43,"value":370},{"type":43,"value":372},{"type":37,"tag":59,"props":421,"children":423},{"className":422},[],[424],{"type":43,"value":378},{"type":43,"value":380},{"type":37,"tag":59,"props":427,"children":429},{"className":428},[],[430],{"type":43,"value":386},{"type":43,"value":432},":",{"type":37,"tag":142,"props":434,"children":436},{"className":144,"code":435,"language":146,"meta":147,"style":147},"final catalog = BasicCatalogItems.asCatalog(); \u002F\u002F Optionally inject custom CatalogItems\nfinal _controller = SurfaceController(catalogs: [catalog]);\nfinal _transport = A2uiTransportAdapter(onSend: _sendAndReceive);\nfinal _conversation = Conversation(\n  controller: _controller,\n  transport: _transport,\n);\n",[437],{"type":37,"tag":59,"props":438,"children":439},{"__ignoreMap":147},[440,448,456,464,472,481,490],{"type":37,"tag":153,"props":441,"children":442},{"class":155,"line":156},[443],{"type":37,"tag":153,"props":444,"children":445},{},[446],{"type":43,"value":447},"final catalog = BasicCatalogItems.asCatalog(); \u002F\u002F Optionally inject custom CatalogItems\n",{"type":37,"tag":153,"props":449,"children":450},{"class":155,"line":165},[451],{"type":37,"tag":153,"props":452,"children":453},{},[454],{"type":43,"value":455},"final _controller = SurfaceController(catalogs: [catalog]);\n",{"type":37,"tag":153,"props":457,"children":458},{"class":155,"line":286},[459],{"type":37,"tag":153,"props":460,"children":461},{},[462],{"type":43,"value":463},"final _transport = A2uiTransportAdapter(onSend: _sendAndReceive);\n",{"type":37,"tag":153,"props":465,"children":466},{"class":155,"line":335},[467],{"type":37,"tag":153,"props":468,"children":469},{},[470],{"type":43,"value":471},"final _conversation = Conversation(\n",{"type":37,"tag":153,"props":473,"children":475},{"class":155,"line":474},5,[476],{"type":37,"tag":153,"props":477,"children":478},{},[479],{"type":43,"value":480},"  controller: _controller,\n",{"type":37,"tag":153,"props":482,"children":484},{"class":155,"line":483},6,[485],{"type":37,"tag":153,"props":486,"children":487},{},[488],{"type":43,"value":489},"  transport: _transport,\n",{"type":37,"tag":153,"props":491,"children":493},{"class":155,"line":492},7,[494],{"type":37,"tag":153,"props":495,"children":496},{},[497],{"type":43,"value":292},{"type":37,"tag":90,"props":499,"children":500},{},[501,514,516],{"type":37,"tag":94,"props":502,"children":503},{},[504,506,512],{"type":43,"value":505},"Implement the ",{"type":37,"tag":59,"props":507,"children":509},{"className":508},[],[510],{"type":43,"value":511},"_sendAndReceive",{"type":43,"value":513}," Method:",{"type":43,"value":515},"\nCreate a method to take messages from the transport adapter, send them to Firebase, and feed the AI's response back to the transport.",{"type":37,"tag":142,"props":517,"children":519},{"className":144,"code":518,"language":146,"meta":147,"style":147},"Future\u003Cvoid> _sendAndReceive(ChatMessage msg) async {\n  final buffer = StringBuffer();\n\n  for (final part in msg.parts) {\n    if (part.isUiInteractionPart) {\n      buffer.write(part.asUiInteractionPart!.interaction);\n    } else if (part is genui.TextPart) {\n      buffer.write(part.text);\n    }\n  }\n\n  if (buffer.isEmpty) return;\n\n  final text = buffer.toString();\n  final response = await _chatSession.sendMessage(Content.text(text));\n\n  if (response.text?.isNotEmpty ?? false) {\n    _transport.addChunk(response.text!);\n  }\n}\n",[520],{"type":37,"tag":59,"props":521,"children":522},{"__ignoreMap":147},[523,531,539,548,556,564,572,580,589,598,607,615,624,632,641,650,658,667,676,684],{"type":37,"tag":153,"props":524,"children":525},{"class":155,"line":156},[526],{"type":37,"tag":153,"props":527,"children":528},{},[529],{"type":43,"value":530},"Future\u003Cvoid> _sendAndReceive(ChatMessage msg) async {\n",{"type":37,"tag":153,"props":532,"children":533},{"class":155,"line":165},[534],{"type":37,"tag":153,"props":535,"children":536},{},[537],{"type":43,"value":538},"  final buffer = StringBuffer();\n",{"type":37,"tag":153,"props":540,"children":541},{"class":155,"line":286},[542],{"type":37,"tag":153,"props":543,"children":545},{"emptyLinePlaceholder":544},true,[546],{"type":43,"value":547},"\n",{"type":37,"tag":153,"props":549,"children":550},{"class":155,"line":335},[551],{"type":37,"tag":153,"props":552,"children":553},{},[554],{"type":43,"value":555},"  for (final part in msg.parts) {\n",{"type":37,"tag":153,"props":557,"children":558},{"class":155,"line":474},[559],{"type":37,"tag":153,"props":560,"children":561},{},[562],{"type":43,"value":563},"    if (part.isUiInteractionPart) {\n",{"type":37,"tag":153,"props":565,"children":566},{"class":155,"line":483},[567],{"type":37,"tag":153,"props":568,"children":569},{},[570],{"type":43,"value":571},"      buffer.write(part.asUiInteractionPart!.interaction);\n",{"type":37,"tag":153,"props":573,"children":574},{"class":155,"line":492},[575],{"type":37,"tag":153,"props":576,"children":577},{},[578],{"type":43,"value":579},"    } else if (part is genui.TextPart) {\n",{"type":37,"tag":153,"props":581,"children":583},{"class":155,"line":582},8,[584],{"type":37,"tag":153,"props":585,"children":586},{},[587],{"type":43,"value":588},"      buffer.write(part.text);\n",{"type":37,"tag":153,"props":590,"children":592},{"class":155,"line":591},9,[593],{"type":37,"tag":153,"props":594,"children":595},{},[596],{"type":43,"value":597},"    }\n",{"type":37,"tag":153,"props":599,"children":601},{"class":155,"line":600},10,[602],{"type":37,"tag":153,"props":603,"children":604},{},[605],{"type":43,"value":606},"  }\n",{"type":37,"tag":153,"props":608,"children":610},{"class":155,"line":609},11,[611],{"type":37,"tag":153,"props":612,"children":613},{"emptyLinePlaceholder":544},[614],{"type":43,"value":547},{"type":37,"tag":153,"props":616,"children":618},{"class":155,"line":617},12,[619],{"type":37,"tag":153,"props":620,"children":621},{},[622],{"type":43,"value":623},"  if (buffer.isEmpty) return;\n",{"type":37,"tag":153,"props":625,"children":627},{"class":155,"line":626},13,[628],{"type":37,"tag":153,"props":629,"children":630},{"emptyLinePlaceholder":544},[631],{"type":43,"value":547},{"type":37,"tag":153,"props":633,"children":635},{"class":155,"line":634},14,[636],{"type":37,"tag":153,"props":637,"children":638},{},[639],{"type":43,"value":640},"  final text = buffer.toString();\n",{"type":37,"tag":153,"props":642,"children":644},{"class":155,"line":643},15,[645],{"type":37,"tag":153,"props":646,"children":647},{},[648],{"type":43,"value":649},"  final response = await _chatSession.sendMessage(Content.text(text));\n",{"type":37,"tag":153,"props":651,"children":653},{"class":155,"line":652},16,[654],{"type":37,"tag":153,"props":655,"children":656},{"emptyLinePlaceholder":544},[657],{"type":43,"value":547},{"type":37,"tag":153,"props":659,"children":661},{"class":155,"line":660},17,[662],{"type":37,"tag":153,"props":663,"children":664},{},[665],{"type":43,"value":666},"  if (response.text?.isNotEmpty ?? false) {\n",{"type":37,"tag":153,"props":668,"children":670},{"class":155,"line":669},18,[671],{"type":37,"tag":153,"props":672,"children":673},{},[674],{"type":43,"value":675},"    _transport.addChunk(response.text!);\n",{"type":37,"tag":153,"props":677,"children":679},{"class":155,"line":678},19,[680],{"type":37,"tag":153,"props":681,"children":682},{},[683],{"type":43,"value":606},{"type":37,"tag":153,"props":685,"children":687},{"class":155,"line":686},20,[688],{"type":37,"tag":153,"props":689,"children":690},{},[691],{"type":43,"value":692},"}\n",{"type":37,"tag":90,"props":694,"children":695},{},[696,701,703,709,711,863,867,869,875,877],{"type":37,"tag":94,"props":697,"children":698},{},[699],{"type":43,"value":700},"Listen to Conversation Events:",{"type":43,"value":702},"\nCreate stubbed-out methods in your State class for each event type, including DartDoc comments explaining their required behavior. Depending on the interface design, new surfaces and text coming from the agent will be handled in different ways. A conversational interface might add everything to a list that's display in a ",{"type":37,"tag":59,"props":704,"children":706},{"className":705},[],[707],{"type":43,"value":708},"ListView",{"type":43,"value":710},", for example, while an interface featuring UI components in specific locations (such as headers, footers, etc.) might rely on specific surface IDs given to the agent in the system instruction to know which surfaces to display in which locations.",{"type":37,"tag":142,"props":712,"children":714},{"className":144,"code":713,"language":146,"meta":147,"style":147},"\u002F\u002F\u002F Updates state to include the new [surfaceId] so a new `Surface` widget can be built.\nvoid _onSurfaceAdded(String surfaceId) {\n  \u002F\u002F TODO: Implement state update to add surfaceId\n}\n\n\u002F\u002F\u002F Updates state to remove the [surfaceId] so its `Surface` widget is no longer built.\nvoid _onSurfaceRemoved(String surfaceId) {\n  \u002F\u002F TODO: Implement state update to remove surfaceId\n}\n\n\u002F\u002F\u002F Handles displaying raw text content received from the AI to the user.\nvoid _onContentReceived(String text) {\n  \u002F\u002F TODO: Implement displaying the received text\n}\n\n\u002F\u002F\u002F Handles errors that occur during the conversation appropriately.\nvoid _onError(Object error) {\n  \u002F\u002F TODO: Implement error handling\n}\n",[715],{"type":37,"tag":59,"props":716,"children":717},{"__ignoreMap":147},[718,726,734,742,749,756,764,772,780,787,794,802,810,818,825,832,840,848,856],{"type":37,"tag":153,"props":719,"children":720},{"class":155,"line":156},[721],{"type":37,"tag":153,"props":722,"children":723},{},[724],{"type":43,"value":725},"\u002F\u002F\u002F Updates state to include the new [surfaceId] so a new `Surface` widget can be built.\n",{"type":37,"tag":153,"props":727,"children":728},{"class":155,"line":165},[729],{"type":37,"tag":153,"props":730,"children":731},{},[732],{"type":43,"value":733},"void _onSurfaceAdded(String surfaceId) {\n",{"type":37,"tag":153,"props":735,"children":736},{"class":155,"line":286},[737],{"type":37,"tag":153,"props":738,"children":739},{},[740],{"type":43,"value":741},"  \u002F\u002F TODO: Implement state update to add surfaceId\n",{"type":37,"tag":153,"props":743,"children":744},{"class":155,"line":335},[745],{"type":37,"tag":153,"props":746,"children":747},{},[748],{"type":43,"value":692},{"type":37,"tag":153,"props":750,"children":751},{"class":155,"line":474},[752],{"type":37,"tag":153,"props":753,"children":754},{"emptyLinePlaceholder":544},[755],{"type":43,"value":547},{"type":37,"tag":153,"props":757,"children":758},{"class":155,"line":483},[759],{"type":37,"tag":153,"props":760,"children":761},{},[762],{"type":43,"value":763},"\u002F\u002F\u002F Updates state to remove the [surfaceId] so its `Surface` widget is no longer built.\n",{"type":37,"tag":153,"props":765,"children":766},{"class":155,"line":492},[767],{"type":37,"tag":153,"props":768,"children":769},{},[770],{"type":43,"value":771},"void _onSurfaceRemoved(String surfaceId) {\n",{"type":37,"tag":153,"props":773,"children":774},{"class":155,"line":582},[775],{"type":37,"tag":153,"props":776,"children":777},{},[778],{"type":43,"value":779},"  \u002F\u002F TODO: Implement state update to remove surfaceId\n",{"type":37,"tag":153,"props":781,"children":782},{"class":155,"line":591},[783],{"type":37,"tag":153,"props":784,"children":785},{},[786],{"type":43,"value":692},{"type":37,"tag":153,"props":788,"children":789},{"class":155,"line":600},[790],{"type":37,"tag":153,"props":791,"children":792},{"emptyLinePlaceholder":544},[793],{"type":43,"value":547},{"type":37,"tag":153,"props":795,"children":796},{"class":155,"line":609},[797],{"type":37,"tag":153,"props":798,"children":799},{},[800],{"type":43,"value":801},"\u002F\u002F\u002F Handles displaying raw text content received from the AI to the user.\n",{"type":37,"tag":153,"props":803,"children":804},{"class":155,"line":617},[805],{"type":37,"tag":153,"props":806,"children":807},{},[808],{"type":43,"value":809},"void _onContentReceived(String text) {\n",{"type":37,"tag":153,"props":811,"children":812},{"class":155,"line":626},[813],{"type":37,"tag":153,"props":814,"children":815},{},[816],{"type":43,"value":817},"  \u002F\u002F TODO: Implement displaying the received text\n",{"type":37,"tag":153,"props":819,"children":820},{"class":155,"line":634},[821],{"type":37,"tag":153,"props":822,"children":823},{},[824],{"type":43,"value":692},{"type":37,"tag":153,"props":826,"children":827},{"class":155,"line":643},[828],{"type":37,"tag":153,"props":829,"children":830},{"emptyLinePlaceholder":544},[831],{"type":43,"value":547},{"type":37,"tag":153,"props":833,"children":834},{"class":155,"line":652},[835],{"type":37,"tag":153,"props":836,"children":837},{},[838],{"type":43,"value":839},"\u002F\u002F\u002F Handles errors that occur during the conversation appropriately.\n",{"type":37,"tag":153,"props":841,"children":842},{"class":155,"line":660},[843],{"type":37,"tag":153,"props":844,"children":845},{},[846],{"type":43,"value":847},"void _onError(Object error) {\n",{"type":37,"tag":153,"props":849,"children":850},{"class":155,"line":669},[851],{"type":37,"tag":153,"props":852,"children":853},{},[854],{"type":43,"value":855},"  \u002F\u002F TODO: Implement error handling\n",{"type":37,"tag":153,"props":857,"children":858},{"class":155,"line":678},[859],{"type":37,"tag":153,"props":860,"children":861},{},[862],{"type":43,"value":692},{"type":37,"tag":864,"props":865,"children":866},"br",{},[],{"type":43,"value":868},"Subscribe to ",{"type":37,"tag":59,"props":870,"children":872},{"className":871},[],[873],{"type":43,"value":874},"_conversation.events",{"type":43,"value":876}," to track when UI surfaces or chat messages arrive, dispatching them to the appropriate stubbed out methods:",{"type":37,"tag":142,"props":878,"children":880},{"className":144,"code":879,"language":146,"meta":147,"style":147},"_conversation.events.listen((event) {\n  switch (event) {\n    case ConversationSurfaceAdded added:\n      _onSurfaceAdded(added.surfaceId);\n    case ConversationSurfaceRemoved removed:\n      _onSurfaceRemoved(removed.surfaceId);\n    case ConversationContentReceived content:\n      _onContentReceived(content.text);\n    case ConversationError error:\n      _onError(error.error);\n    default:\n  }\n});\n",[881],{"type":37,"tag":59,"props":882,"children":883},{"__ignoreMap":147},[884,892,900,908,916,924,932,940,948,956,964,972,979],{"type":37,"tag":153,"props":885,"children":886},{"class":155,"line":156},[887],{"type":37,"tag":153,"props":888,"children":889},{},[890],{"type":43,"value":891},"_conversation.events.listen((event) {\n",{"type":37,"tag":153,"props":893,"children":894},{"class":155,"line":165},[895],{"type":37,"tag":153,"props":896,"children":897},{},[898],{"type":43,"value":899},"  switch (event) {\n",{"type":37,"tag":153,"props":901,"children":902},{"class":155,"line":286},[903],{"type":37,"tag":153,"props":904,"children":905},{},[906],{"type":43,"value":907},"    case ConversationSurfaceAdded added:\n",{"type":37,"tag":153,"props":909,"children":910},{"class":155,"line":335},[911],{"type":37,"tag":153,"props":912,"children":913},{},[914],{"type":43,"value":915},"      _onSurfaceAdded(added.surfaceId);\n",{"type":37,"tag":153,"props":917,"children":918},{"class":155,"line":474},[919],{"type":37,"tag":153,"props":920,"children":921},{},[922],{"type":43,"value":923},"    case ConversationSurfaceRemoved removed:\n",{"type":37,"tag":153,"props":925,"children":926},{"class":155,"line":483},[927],{"type":37,"tag":153,"props":928,"children":929},{},[930],{"type":43,"value":931},"      _onSurfaceRemoved(removed.surfaceId);\n",{"type":37,"tag":153,"props":933,"children":934},{"class":155,"line":492},[935],{"type":37,"tag":153,"props":936,"children":937},{},[938],{"type":43,"value":939},"    case ConversationContentReceived content:\n",{"type":37,"tag":153,"props":941,"children":942},{"class":155,"line":582},[943],{"type":37,"tag":153,"props":944,"children":945},{},[946],{"type":43,"value":947},"      _onContentReceived(content.text);\n",{"type":37,"tag":153,"props":949,"children":950},{"class":155,"line":591},[951],{"type":37,"tag":153,"props":952,"children":953},{},[954],{"type":43,"value":955},"    case ConversationError error:\n",{"type":37,"tag":153,"props":957,"children":958},{"class":155,"line":600},[959],{"type":37,"tag":153,"props":960,"children":961},{},[962],{"type":43,"value":963},"      _onError(error.error);\n",{"type":37,"tag":153,"props":965,"children":966},{"class":155,"line":609},[967],{"type":37,"tag":153,"props":968,"children":969},{},[970],{"type":43,"value":971},"    default:\n",{"type":37,"tag":153,"props":973,"children":974},{"class":155,"line":617},[975],{"type":37,"tag":153,"props":976,"children":977},{},[978],{"type":43,"value":606},{"type":37,"tag":153,"props":980,"children":981},{"class":155,"line":626},[982],{"type":37,"tag":153,"props":983,"children":984},{},[985],{"type":43,"value":986},"});\n",{"type":37,"tag":90,"props":988,"children":989},{},[990,995,997,1003,1005],{"type":37,"tag":94,"props":991,"children":992},{},[993],{"type":43,"value":994},"Initialize System Prompt:",{"type":43,"value":996},"\nUse ",{"type":37,"tag":59,"props":998,"children":1000},{"className":999},[],[1001],{"type":43,"value":1002},"PromptBuilder",{"type":43,"value":1004}," to give the AI basic instructions, then send it as a system message.",{"type":37,"tag":142,"props":1006,"children":1008},{"className":144,"code":1007,"language":146,"meta":147,"style":147},"final promptBuilder = PromptBuilder.chat(\n  catalog: catalog,\n  instructions: 'You are a helpful assistant. Respond to messages in a chatty way.',\n);\n_conversation.sendRequest(ChatMessage.system(promptBuilder.systemPrompt));\n",[1009],{"type":37,"tag":59,"props":1010,"children":1011},{"__ignoreMap":147},[1012,1020,1028,1036,1043],{"type":37,"tag":153,"props":1013,"children":1014},{"class":155,"line":156},[1015],{"type":37,"tag":153,"props":1016,"children":1017},{},[1018],{"type":43,"value":1019},"final promptBuilder = PromptBuilder.chat(\n",{"type":37,"tag":153,"props":1021,"children":1022},{"class":155,"line":165},[1023],{"type":37,"tag":153,"props":1024,"children":1025},{},[1026],{"type":43,"value":1027},"  catalog: catalog,\n",{"type":37,"tag":153,"props":1029,"children":1030},{"class":155,"line":286},[1031],{"type":37,"tag":153,"props":1032,"children":1033},{},[1034],{"type":43,"value":1035},"  instructions: 'You are a helpful assistant. Respond to messages in a chatty way.',\n",{"type":37,"tag":153,"props":1037,"children":1038},{"class":155,"line":335},[1039],{"type":37,"tag":153,"props":1040,"children":1041},{},[1042],{"type":43,"value":292},{"type":37,"tag":153,"props":1044,"children":1045},{"class":155,"line":474},[1046],{"type":37,"tag":153,"props":1047,"children":1048},{},[1049],{"type":43,"value":1050},"_conversation.sendRequest(ChatMessage.system(promptBuilder.systemPrompt));\n",{"type":37,"tag":90,"props":1052,"children":1053},{},[1054,1059,1061,1067,1069,1075,1077,1083,1085],{"type":37,"tag":94,"props":1055,"children":1056},{},[1057],{"type":43,"value":1058},"Display Surfaces:",{"type":43,"value":1060},"\nIn your Flutter ",{"type":37,"tag":59,"props":1062,"children":1064},{"className":1063},[],[1065],{"type":43,"value":1066},"build()",{"type":43,"value":1068}," method, use the ",{"type":37,"tag":59,"props":1070,"children":1072},{"className":1071},[],[1073],{"type":43,"value":1074},"Surface",{"type":43,"value":1076}," widget wherever you need to render GenUI widgets using the ",{"type":37,"tag":59,"props":1078,"children":1080},{"className":1079},[],[1081],{"type":43,"value":1082},"surfaceIds",{"type":43,"value":1084}," you collected in step 9.",{"type":37,"tag":142,"props":1086,"children":1088},{"className":144,"code":1087,"language":146,"meta":147,"style":147},"Surface(surfaceContext: _controller.contextFor(surfaceId));\n",[1089],{"type":37,"tag":59,"props":1090,"children":1091},{"__ignoreMap":147},[1092],{"type":37,"tag":153,"props":1093,"children":1094},{"class":155,"line":156},[1095],{"type":37,"tag":153,"props":1096,"children":1097},{},[1098],{"type":43,"value":1087},{"type":37,"tag":90,"props":1100,"children":1101},{},[1102,1107,1112,1114,1120,1121,1127],{"type":37,"tag":94,"props":1103,"children":1104},{},[1105],{"type":43,"value":1106},"Ask User for Input Preferences:",{"type":37,"tag":94,"props":1108,"children":1109},{},[1110],{"type":43,"value":1111},"STOP AND ASK THE USER:",{"type":43,"value":1113}," Ask the user for clarification on what UI elements should be used for user input. Explain that a ",{"type":37,"tag":59,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":43,"value":1119},"TextField",{"type":43,"value":108},{"type":37,"tag":59,"props":1122,"children":1124},{"className":1123},[],[1125],{"type":43,"value":1126},"ElevatedButton",{"type":43,"value":1128}," are good defaults, but you should not assume they want those exact widgets unless they clarify.",{"type":37,"tag":46,"props":1130,"children":1132},{"id":1131},"constraints",[1133],{"type":43,"value":1134},"Constraints",{"type":37,"tag":1136,"props":1137,"children":1138},"ul",{},[1139,1144],{"type":37,"tag":90,"props":1140,"children":1141},{},[1142],{"type":43,"value":1143},"Do not make assumptions about user input UI elements; see step 12.",{"type":37,"tag":90,"props":1145,"children":1146},{},[1147,1149,1155,1156,1162,1164,1170],{"type":43,"value":1148},"Make sure to properly clean up GenUI controllers (",{"type":37,"tag":59,"props":1150,"children":1152},{"className":1151},[],[1153],{"type":43,"value":1154},"_transport.dispose()",{"type":43,"value":372},{"type":37,"tag":59,"props":1157,"children":1159},{"className":1158},[],[1160],{"type":43,"value":1161},"_controller.dispose()",{"type":43,"value":1163},") inside the widget's ",{"type":37,"tag":59,"props":1165,"children":1167},{"className":1166},[],[1168],{"type":43,"value":1169},"dispose()",{"type":43,"value":1171}," method.",{"type":37,"tag":1173,"props":1174,"children":1175},"style",{},[1176],{"type":43,"value":1177},"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":1179,"total":1318},[1180,1194,1205,1217,1228,1237,1249,1261,1273,1285,1299,1309],{"slug":1181,"name":1181,"fn":1182,"description":1183,"org":1184,"tags":1185,"stars":1191,"repoUrl":1192,"updatedAt":1193},"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},[1186,1188],{"name":1187,"slug":146,"type":14},"Dart",{"name":1189,"slug":1190,"type":14},"Testing","testing",2664,"https:\u002F\u002Fgithub.com\u002Fflutter\u002Fagent-plugins","2026-07-15T05:22:40.104823",{"slug":1195,"name":1195,"fn":1196,"description":1197,"org":1198,"tags":1199,"stars":1191,"repoUrl":1192,"updatedAt":1204},"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},[1200,1203],{"name":1201,"slug":1202,"type":14},"CLI","cli",{"name":1187,"slug":146,"type":14},"2026-07-15T05:22:18.863572",{"slug":1206,"name":1206,"fn":1207,"description":1208,"org":1209,"tags":1210,"stars":1191,"repoUrl":1192,"updatedAt":1216},"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},[1211,1212,1215],{"name":1187,"slug":146,"type":14},{"name":1213,"slug":1214,"type":14},"Reporting","reporting",{"name":1189,"slug":1190,"type":14},"2026-07-15T05:22:21.38636",{"slug":1218,"name":1218,"fn":1219,"description":1220,"org":1221,"tags":1222,"stars":1191,"repoUrl":1192,"updatedAt":1227},"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},[1223,1224],{"name":1187,"slug":146,"type":14},{"name":1225,"slug":1226,"type":14},"Debugging","debugging","2026-07-15T05:22:22.622501",{"slug":1229,"name":1229,"fn":1230,"description":1231,"org":1232,"tags":1233,"stars":1191,"repoUrl":1192,"updatedAt":1236},"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},[1234,1235],{"name":1187,"slug":146,"type":14},{"name":1189,"slug":1190,"type":14},"2026-07-15T05:22:42.607449",{"slug":1238,"name":1238,"fn":1239,"description":1240,"org":1241,"tags":1242,"stars":1191,"repoUrl":1192,"updatedAt":1248},"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},[1243,1244,1247],{"name":1187,"slug":146,"type":14},{"name":1245,"slug":1246,"type":14},"Migration","migration",{"name":1189,"slug":1190,"type":14},"2026-07-15T05:22:31.276564",{"slug":1250,"name":1250,"fn":1251,"description":1252,"org":1253,"tags":1254,"stars":1191,"repoUrl":1192,"updatedAt":1260},"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},[1255,1256,1257],{"name":1187,"slug":146,"type":14},{"name":1225,"slug":1226,"type":14},{"name":1258,"slug":1259,"type":14},"Engineering","engineering","2026-07-15T05:22:30.059335",{"slug":1262,"name":1262,"fn":1263,"description":1264,"org":1265,"tags":1266,"stars":1191,"repoUrl":1192,"updatedAt":1272},"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},[1267,1270,1271],{"name":1268,"slug":1269,"type":14},"Code Analysis","code-analysis",{"name":1187,"slug":146,"type":14},{"name":1225,"slug":1226,"type":14},"2026-07-15T05:22:23.861119",{"slug":1274,"name":1274,"fn":1275,"description":1276,"org":1277,"tags":1278,"stars":1191,"repoUrl":1192,"updatedAt":1284},"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},[1279,1280,1283],{"name":1187,"slug":146,"type":14},{"name":1281,"slug":1282,"type":14},"Deployment","deployment",{"name":1258,"slug":1259,"type":14},"2026-07-15T05:22:20.138636",{"slug":1286,"name":1286,"fn":1287,"description":1288,"org":1289,"tags":1290,"stars":1191,"repoUrl":1192,"updatedAt":1298},"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},[1291,1292,1295],{"name":1187,"slug":146,"type":14},{"name":1293,"slug":1294,"type":14},"Plugin Development","plugin-development",{"name":1296,"slug":1297,"type":14},"QA","qa","2026-07-15T05:22:47.488998",{"slug":1300,"name":1300,"fn":1301,"description":1302,"org":1303,"tags":1304,"stars":1191,"repoUrl":1192,"updatedAt":1308},"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},[1305,1306,1307],{"name":1187,"slug":146,"type":14},{"name":1293,"slug":1294,"type":14},{"name":1296,"slug":1297,"type":14},"2026-07-21T05:38:34.451024",{"slug":1310,"name":1310,"fn":1311,"description":1312,"org":1313,"tags":1314,"stars":1191,"repoUrl":1192,"updatedAt":1317},"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},[1315,1316],{"name":1187,"slug":146,"type":14},{"name":1258,"slug":1259,"type":14},"2026-07-15T05:22:17.592351",27,{"items":1320,"total":165},[1321,1336],{"slug":1322,"name":1322,"fn":1323,"description":1324,"org":1325,"tags":1326,"stars":21,"repoUrl":22,"updatedAt":1335},"create-catalog-item","create Flutter UI components from JSON Schema","Use this skill when the user asks to create a new CatalogItem, data class, and\u002For widget class based on a JSON Schema definition in an application that uses Flutter's `genui` package.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1327,1328,1329,1332],{"name":1187,"slug":146,"type":14},{"name":13,"slug":8,"type":14},{"name":1330,"slug":1331,"type":14},"Frontend","frontend",{"name":1333,"slug":1334,"type":14},"UI Components","ui-components","2026-04-16T05:04:51.027381",{"slug":4,"name":4,"fn":5,"description":6,"org":1337,"tags":1338,"stars":21,"repoUrl":22,"updatedAt":23},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1339,1340,1341],{"name":19,"slug":20,"type":14},{"name":13,"slug":8,"type":14},{"name":16,"slug":17,"type":14}]