---
title: "flutter/agent-plugins"
description: "Agent Skills from flutter/agent-plugins."
source: https://github.com/flutter/agent-plugins
ref: main
license: BSD-3-Clause
licenseName: "BSD 3-Clause \"New\" or \"Revised\" License"
canonical: https://skillsdocs.com/flutter/agent-plugins
base: https://github.com/flutter/agent-plugins/blob/main/
provenance: mixed
chapters: 31
inlined: 31
withheld: 0
words: 18466
updated: 2026-09-17T16:30:32Z
generator: "Skills Docs"
---

> **flutter/agent-plugins** — every Agent Skill in this repository, inlined verbatim.
>
> Canonical HTML: https://skillsdocs.com/flutter/agent-plugins
> Per-skill Markdown: https://skillsdocs.com/flutter/agent-plugins/<skill>.md
> Machine manifest: https://skillsdocs.com/flutter/agent-plugins/.well-known/agent-skills/index.json
> JSON: https://skillsdocs.com/api/v1/books/flutter/agent-plugins
> Install: `npx skills add flutter/agent-plugins`
> Upstream: https://github.com/flutter/agent-plugins @ `main`
> Licence: BSD-3-Clause
>
> Content is mirrored from GitHub and © its authors, served unmodified. Takedown: https://github.com/DreambaseAI/skillsdocs/issues/new?labels=takedown&title=Takedown+request

# flutter/agent-plugins


- **Skills:** 31
- **Authorship:** mixed — 6 of 31 are credited — skills in use here, not published from here
- **Inlined:** 31 (licence detected)
- **Words:** 18,466
- **Reading time:** 85 min
- **Stars:** 2,991

## Table of contents

1. [dart-add-unit-test](https://skillsdocs.com/flutter/agent-plugins/dart-add-unit-test.md) — 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 corre…
2. [dart-build-cli-app](https://skillsdocs.com/flutter/agent-plugins/dart-build-cli-app.md) — Architectural patterns, entrypoint structure, exit codes, stream routing, and subprocess spawning for Dart command-line interface (CLI) applications. Use when…
3. [dart-collect-coverage](https://skillsdocs.com/flutter/agent-plugins/dart-collect-coverage.md) — Collect coverage using the coverage packge and create an LCOV report
4. [dart-fix-runtime-errors](https://skillsdocs.com/flutter/agent-plugins/dart-fix-runtime-errors.md) — 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.
5. [dart-generate-test-mocks](https://skillsdocs.com/flutter/agent-plugins/dart-generate-test-mocks.md) — Define and generate mock objects for external dependencies using `package:mockito` and `build_runner`. Use when unit testing classes that depend on complex ext…
6. [dart-migrate-to-checks-package](https://skillsdocs.com/flutter/agent-plugins/dart-migrate-to-checks-package.md) — Replace the usage of `expect` and similar functions from `package:matcher` to `package:checks` equivalents.
7. [dart-resolve-package-conflicts](https://skillsdocs.com/flutter/agent-plugins/dart-resolve-package-conflicts.md) — Workflow for fixing package version conflicts. Use this when `pub get` fails due to incompatible package versions.
8. [dart-run-static-analysis](https://skillsdocs.com/flutter/agent-plugins/dart-run-static-analysis.md) — Execute `dart analyze` to identify warnings and errors, and use `dart fix --apply` to automatically resolve mechanical lint issues. Use during development to e…
9. [dart-setup-ffi-assets](https://skillsdocs.com/flutter/agent-plugins/dart-setup-ffi-assets.md) — Guides agents in compiling and packaging C/C++ source code into dynamic or static libraries (Code Assets) using Dart's Native Assets hook system (via hook/buil…
10. [dart-use-doc-examples](https://skillsdocs.com/flutter/agent-plugins/dart-use-doc-examples.md) — How to inject external code examples into Dartdoc using the {@example} directive, and how to filter those files using #hide, #region, and #endregion tags.
11. [dart-use-ffigen](https://skillsdocs.com/flutter/agent-plugins/dart-use-ffigen.md) — 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 F…
12. [dart-use-path-package](https://skillsdocs.com/flutter/agent-plugins/dart-use-path-package.md) — Cross-platform file and directory path manipulation, segment splitting, extension extraction, and context conversion using `package:path` and `package:file`. U…
13. [dart-use-pattern-matching](https://skillsdocs.com/flutter/agent-plugins/dart-use-pattern-matching.md) — Applies Dart 3 pattern matching, switch expressions, and destructuring idiomatically to validate data schemas, handle algebraic data types, and decompose contr…
14. [dart-use-primary-constructors](https://skillsdocs.com/flutter/agent-plugins/dart-use-primary-constructors.md) — Help users write syntactically and semantically correct primary constructors in Dart, and migrate/use the new constructor syntax, empty-body semicolon syntax,…
15. [dart-write-documentation](https://skillsdocs.com/flutter/agent-plugins/dart-write-documentation.md) — Rules and formatting guidelines for writing Dart /// API documentation and doc comments. Use when documenting Dart code, writing doc comments for any Dart decl…
16. [flutter-add-integration-test](https://skillsdocs.com/flutter/agent-plugins/flutter-add-integration-test.md) — Configures Flutter Driver for app interaction and converts MCP actions into permanent integration tests. Use when adding integration testing to a project, expl…
17. [flutter-add-widget-preview](https://skillsdocs.com/flutter/agent-plugins/flutter-add-widget-preview.md) — Adds interactive widget previews to the project using the previews.dart system. Use when creating new UI components or updating existing screens to ensure cons…
18. [flutter-add-widget-test](https://skillsdocs.com/flutter/agent-plugins/flutter-add-widget-test.md) — Implement a component-level test using `WidgetTester` to verify UI rendering and user interactions (tapping, scrolling, entering text). Use when validating tha…
19. [flutter-apply-architecture-best-practices](https://skillsdocs.com/flutter/agent-plugins/flutter-apply-architecture-best-practices.md) — Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability.
20. [flutter-build-responsive-layout](https://skillsdocs.com/flutter/agent-plugins/flutter-build-responsive-layout.md) — Use `LayoutBuilder`, `MediaQuery`, or `Expanded/Flexible` to create a layout that adapts to different screen sizes. Use when you need the UI to look good on bo…
21. [flutter-fix-layout-issues](https://skillsdocs.com/flutter/agent-plugins/flutter-fix-layout-issues.md) — Fixes Flutter layout errors (overflows, unbounded constraints) using Dart and Flutter MCP tools. Use when addressing "RenderFlex overflowed", "Vertical viewpor…
22. [flutter-implement-json-serialization](https://skillsdocs.com/flutter/agent-plugins/flutter-implement-json-serialization.md) — Create model classes with `fromJson` and `toJson` methods using `dart:convert`. Use when manually mapping JSON keys to class properties for simple data structu…
23. [flutter-setup-declarative-routing](https://skillsdocs.com/flutter/agent-plugins/flutter-setup-declarative-routing.md) — Configure `MaterialApp.router` using a package like `go_router` for advanced URL-based navigation. Use when developing web applications or mobile apps that req…
24. [flutter-setup-localization](https://skillsdocs.com/flutter/agent-plugins/flutter-setup-localization.md) — Add `flutter_localizations` and `intl` dependencies, enable "generate true" in `pubspec.yaml`, and create an `l10n.yaml` configuration file. Use when initializ…
25. [flutter-use-http-package](https://skillsdocs.com/flutter/agent-plugins/flutter-use-http-package.md) — Use the `http` package to execute GET, POST, PUT, or DELETE requests. Use when you need to fetch from or send data to a REST API.
26. [api-review](https://skillsdocs.com/flutter/agent-plugins/api-review.md) — Reviews the specified code against the canonical API Design guidelines. Use this skill when the user asks for an API review or to check code against API design…
27. [code-documentation](https://skillsdocs.com/flutter/agent-plugins/code-documentation.md) — Guide for writing effective code documentation, including docstrings, JSDoc, dartdoc, and implementation comments. Use this skill when writing new code, adding…
28. [code-review](https://skillsdocs.com/flutter/agent-plugins/code-review.md) — Performs a comprehensive, multi-step code review of pull requests or local code changes, using iterative refinement (generation, critique, synthesis) to ensure…
29. [grill-with-docs](https://skillsdocs.com/flutter/agent-plugins/grill-with-docs.md) — Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as deci…
30. [natural-writing](https://skillsdocs.com/flutter/agent-plugins/natural-writing.md) — Contains well-defined rules for creating natural, accurate, and readable writing. Use whenever authoring longer text, like analysis documents, PR or CL descrip…
31. [unix-cli-best-practices](https://skillsdocs.com/flutter/agent-plugins/unix-cli-best-practices.md) — Safe, portable, and efficient command-line patterns for macOS/BSD Unix tools (grep, find, sed, awk, xargs, mdfind, pbcopy, open) and modern alternatives (ripgr…


## Front matter

_The repository README, verbatim except that relative links are resolved against https://github.com/flutter/agent-plugins/blob/main/._

# Flutter Agent Plugins

Agent plugins for Flutter, maintained by the Flutter team.

A collection of plugins designed to extend AI agent capabilities for Flutter development. These plugins bundle together skills, MCP server configuration, and rules to provide tailored workflows and instructions for happy path Flutter development. By giving the agent domain expertise and repeatable workflows, you drastically reduce mistakes and ensure agents reliably complete tasks following best practices.

Plugins can package various customizations together. A key component of these plugins is **Agent Skills**, which are simple folders of files that can be seen as complementary to MCP: where MCP gives an agent access to specialized tools, a Skill teaches the agent “how” to use tools for a specific task.

You can also install the [Dart skills](https://github.com/dart-lang/skills) for Dart tasks.

## Installation

Refer to [Get started developing with AI](https://docs.flutter.dev/ai/get-started) for detailed instructions on how to install the plugins for your preferred agent.

## Available Skills

| Skill | Description | Example prompt |
|---|---|---|
| [flutter-add-integration-test](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-integration-test/SKILL.md) | Configures Flutter Driver for app interaction and converts MCP actions into permanent integration tests. Use when adding integration testing to a project, exploring UI components via MCP, or automating user flows with the integration_test package. | Add an integration test that validates the checkout experience |
| [flutter-add-widget-preview](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-widget-preview/SKILL.md) | Adds interactive widget previews to the project using the previews.dart system. Use when creating new UI components or updating existing screens to ensure consistent design and interactive testing. | Create a preview for the ProductCard widget with different price states |
| [flutter-add-widget-test](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-widget-test/SKILL.md) | Implement a component-level test using `WidgetTester` to verify UI rendering and user interactions (tapping, scrolling, entering text). Use when validating that a specific widget displays correct data and responds to events as expected. | Add a widget test for the CustomButton to verify the onTap callback is called |
| [flutter-apply-architecture-best-practices](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-apply-architecture-best-practices/SKILL.md) | Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability. | Refactor the authentication flow to follow the recommended layered architecture |
| [flutter-build-responsive-layout](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-build-responsive-layout/SKILL.md) | Use `LayoutBuilder`, `MediaQuery`, or `Expanded/Flexible` to create a layout that adapts to different screen sizes. Use when you need the UI to look good on both mobile and tablet/desktop form factors. | Make the home screen responsive so it displays a grid on tablets and a list on phones |
| [flutter-fix-layout-issues](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-fix-layout-issues/SKILL.md) | Fixes Flutter layout errors (overflows, unbounded constraints) using Dart and Flutter MCP tools. Use when addressing "RenderFlex overflowed", "Vertical viewport was given unbounded height", or similar layout issues. | Fix the overflow error on the profile page when the keyboard is visible |
| [flutter-implement-json-serialization](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-implement-json-serialization/SKILL.md) | Create model classes with `fromJson` and `toJson` methods using `dart:convert`. Use when manually mapping JSON keys to class properties for simple data structures. | Implement JSON serialization for the User model class |
| [flutter-setup-declarative-routing](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-setup-declarative-routing/SKILL.md) | Configure `MaterialApp.router` using a package like `go_router` for advanced URL-based navigation. Use when developing web applications or mobile apps that require specific deep linking and browser history support. | Set up GoRouter with paths for home, details, and settings |
| [flutter-setup-localization](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-setup-localization/SKILL.md) | Add `flutter_localizations` and `intl` dependencies, enable "generate true" in `pubspec.yaml`, and create an `l10n.yaml` configuration file. Use when initializing localization support for a new Flutter project. | Setup localization and add English and Spanish translations |
| [flutter-use-http-package](https://github.com/flutter/agent-plugins/blob/main/skills/flutter-use-http-package/SKILL.md) | Use the `http` package to execute GET, POST, PUT, or DELETE requests. Use when you need to fetch from or send data to a REST API. | Use the http package to fetch the list of products from the API |
## Contributing

We aren't accepting pull requests at this time, but we would love to hear your feedback! 

Please see [CONTRIBUTING.md](https://github.com/flutter/agent-plugins/blob/main/CONTRIBUTING.md) for more information.

## Code of Conduct

Please see [CODE_OF_CONDUCT.md](https://github.com/flutter/agent-plugins/blob/main/CODE_OF_CONDUCT.md) for more information.

---

## Part: Skills

---

<!-- chapter:begin slug=dart-add-unit-test position=1 -->

## 1. dart-add-unit-test

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-add-unit-test/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-add-unit-test/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-add-unit-test.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-add-unit-test
description: 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.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Mon, 03 Aug 2026 21:51:24 GMT
---
# Testing Dart and Flutter Applications

## Contents
- [Structuring Test Files](#structuring-test-files)
- [Writing Tests](#writing-tests)
- [Executing Tests](#executing-tests)
- [Test Implementation Workflow](#test-implementation-workflow)
- [Examples](#examples)

## Structuring Test Files
Organize test files to mirror the `lib` directory structure to maintain predictability.

* Place all test code within the `test` directory at the root of the package.
* Append `_test.dart` to the end of all test file names (e.g., `lib/src/utils.dart` should be tested in `test/src/utils_test.dart`).
* If writing integration tests, place them in an `integration_test` directory at the root of the package.

## Writing Tests
Utilize `package:test` as the standard testing library for Dart applications.

* Import `package:test/test.dart` (or `package:flutter_test/flutter_test.dart` for Flutter).
* Group related tests using the `group()` function to provide shared context.
* Define individual test cases using the `test()` function.
* Validate outcomes using the `expect()` function alongside matchers (e.g., `equals()`, `isTrue`, `throwsA()`).
* Write asynchronous tests using standard `async`/`await` syntax. The test runner automatically waits for the `Future` to complete.
* Manage test setup and teardown using `setUp()` and `tearDown()` callbacks.
* If testing code that relies on dependency injection, use `package:mockito` alongside `package:test` to generate mock objects, configure fixed scenarios, and verify interactions.

## Executing Tests
Select the appropriate test runner based on the project type and test location.

* If working on a pure Dart project, execute tests using the `dart test` command.
* If working on a Flutter project, execute tests using the `flutter test` command.
* If running integration tests, explicitly specify the directory path, as the default runner ignores it: `dart test integration_test` or `flutter test integration_test`.

## Test Implementation Workflow

Follow this sequential workflow when implementing new test suites. Copy the checklist to track your progress.

### Task Progress
- [ ] 1. Create the test file in the `test/` directory, ensuring the `_test.dart` suffix.
- [ ] 2. Import `package:test/test.dart` and the target library.
- [ ] 3. Define a `main()` function.
- [ ] 4. Initialize shared resources or mocks using `setUp()`.
- [ ] 5. Write `test()` cases grouped by functionality using `group()`.
- [ ] 6. Execute the test suite using the appropriate CLI command.
- [ ] 7. **Feedback Loop**: Run test -> Review stack trace for failures -> Fix implementation or assertions -> Re-run until passing.

## Examples

### Standard Unit Test Suite
Demonstrates grouping, setup, synchronous, and asynchronous testing.

```dart
import 'package:test/test.dart';
import 'package:my_package/calculator.dart';

void main() {
  group('Calculator', () {
    late Calculator calc;

    setUp(() {
      calc = Calculator();
    });

    test('adds two numbers correctly', () {
      expect(calc.add(2, 3), equals(5));
    });

    test('handles asynchronous operations', () async {
      final result = await calc.fetchRemoteValue();
      expect(result, isNotNull);
      expect(result, greaterThan(0));
    });
  });
}
```

### Mocking with Mockito
Demonstrates configuring a mock object for dependency injection testing.

```dart
import 'package:test/test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:my_package/api_client.dart';
import 'package:my_package/data_service.dart';

// Generate the mock using build_runner: dart run build_runner build
@GenerateNiceMocks([MockSpec<ApiClient>()])
import 'data_service_test.mocks.dart';

void main() {
  group('DataService', () {
    late MockApiClient mockApiClient;
    late DataService dataService;

    setUp(() {
      mockApiClient = MockApiClient();
      dataService = DataService(apiClient: mockApiClient);
    });

    test('returns parsed data on successful API call', () async {
      // Configure the mock
      when(mockApiClient.get('/data')).thenAnswer((_) async => '{"id": 1}');

      // Execute the system under test
      final result = await dataService.fetchData();

      // Verify outcomes and interactions
      expect(result.id, equals(1));
      verify(mockApiClient.get('/data')).called(1);
    });
  });
}
```

<!-- chapter:end slug=dart-add-unit-test -->

---

<!-- chapter:begin slug=dart-build-cli-app position=2 -->

## 2. dart-build-cli-app

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-build-cli-app/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-build-cli-app/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-build-cli-app.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (4), referenced from this skill's directory:
  - `examples/multi_command_runner.dart` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-build-cli-app/examples/multi_command_runner.dart
  - `examples/single_command_tool.dart` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-build-cli-app/examples/single_command_tool.dart
  - `references/aot_sdk_discovery.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-build-cli-app/references/aot_sdk_discovery.md
  - `references/signals_and_terminal.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-build-cli-app/references/signals_and_terminal.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-build-cli-app
description: >-
  Architectural patterns, entrypoint structure, exit codes, stream routing, and subprocess spawning for Dart command-line interface (CLI) applications. Use when building CLI tools, console utilities, scripts, argument parsing with `package:args` (ArgParser or CommandRunner), handling exit codes, configuring executables in pubspec.yaml, spawning Dart subprocesses, or compiling native CLI binaries. Don't use for Flutter UI widgets, web applications, or standalone HTTP backend servers.
---

# Building Dart CLI Applications

## Contents
* [1. Core Architecture & Process Lifecycle](#1-core-architecture--process-lifecycle)
* [2. Streams, Diagnostics & Formatting](#2-streams-diagnostics--formatting)
* [3. Project Configuration & Packaging](#3-project-configuration--packaging)
* [4. Argument Parsing & Command Routing](#4-argument-parsing--command-routing)
* [5. Native Async & Modern Stack Traces](#5-native-async--modern-stack-traces)
* [6. Subprocess Spawning & AOT Resilience](#6-subprocess-spawning--aot-resilience)
* [7. Signal Handling & Terminal Teardown](#7-signal-handling--terminal-teardown)
* [8. Testing CLI Applications](#8-testing-cli-applications)
* [9. Modern Compilation & Distribution](#9-modern-compilation--distribution)
* [10. Workflows & Audit Checklist](#10-workflows--audit-checklist)
* [References & Examples](#references--examples)

---

## 1. Core Architecture & Process Lifecycle

### Avoid Destructive Exits (`exit(N)`)
Calling `dart:io`'s `exit(int code)` invokes `Platform::Exit(code)` in the C++ runtime. It immediately terminates the OS process without unwinding the Dart stack:
* **Debugger Disconnect**: When launched with `--pause-isolates-on-exit`, the VM Service pauses isolates before shutdown to allow IDE inspection. `exit()` terminates the OS process before the VM Service can pause or inspect state.
* **Coverage Loss**: `package:coverage` queries execution lines over VM Service RPCs during the paused-on-exit state. `exit()` destroys the process before RPC extraction, yielding 0% coverage.
* **Buffer Truncation**: `stdout` and `stderr` are buffered asynchronous `IOSink` streams. `exit()` drops unflushed bytes.
* **Resource Leaks**: `finally` blocks (closing locks, deleting temp directories) are bypassed.

**Rule**: Avoid calling `exit(code)` directly during normal execution; set `exitCode = code` or return an integer exit code from `CommandRunner<int>` (from `package:args`) and allow the asynchronous `main()` function to return naturally. Do not call `exit()` on unhandled errors; throw an unhandled `Error` or exception so the runtime unwinds cleanly and exits with a non-zero status.

Standard POSIX exit codes (`/usr/include/sysexits.h`):
* `0`: Success (`EX_OK` / `ExitCode.success.code`)
* `64`: Command-line usage error (`EX_USAGE` / `ExitCode.usage.code`)
* `65`: Data format error (`EX_DATAERR` / `ExitCode.data.code`)
* `70`: Internal software crash (`EX_SOFTWARE` / `ExitCode.software.code`)
* `78`: Configuration error (`EX_CONFIG` / `ExitCode.config.code`)

*Note*: Prefer importing `package:io/io.dart` and using `ExitCode` constants
(e.g., `ExitCode.usage.code`, `ExitCode.software.code`) rather than magic
integer literals. For minimal standalone scripts without package dependencies,
standard POSIX integer literals (`0`, `64`, `70`) may be used.

```dart
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:io/io.dart' show ExitCode; // Provides standard POSIX ExitCode constants

Future<void> main(List<String> args) async {
  final runner = CommandRunner<int>('tool', 'CLI tool description.');
  try {
    final status = await runner.run(args);
    exitCode = status ?? ExitCode.success.code;
  } on UsageException catch (e) {
    stderr
      ..writeln(e.message)
      ..writeln(e.usage);
    exitCode = ExitCode.usage.code;
  }
}
```

### The Thin Entrypoint Pattern (`bin/` vs. `lib/src/`)
Keep `bin/*.dart` files strictly as minimal entrypoint trampolines (instantiate runner, pass `args`, await exit code). Place all command definitions, argument parsers, formatters, and business logic inside `lib/src/`.

* **Rationale**: Code in `bin/` cannot be cleanly imported via `package:` URIs. Moving logic into `lib/src/` allows the entire command runner, subcommand hierarchy, and business logic to be unit-tested in-memory in milliseconds (`< 2ms`) without spawning OS subprocesses.

```dart
// bin/my_cli.dart — Thin entrypoint trampoline
import 'dart:io';
import 'package:my_cli/src/cli.dart';

Future<void> main(List<String> args) async {
  exitCode = await runCli(args);
}
```

---

## 2. Output, Diagnostics & Formatting

* **Data vs. Diagnostics**: Write intended program results and machine-readable data exclusively to `stdout`. Write warnings, error messages, and debug logs exclusively to `stderr`.
* **The Error Usage Rule**: When an argument parsing or mandatory option error
  occurs (`FormatException`, `UsageException`, or `ArgumentError` thrown when
  accessing a missing `mandatory: true` option via `results.option(...)`), **both
  the error message and the usage text must write to `stderr`**, and exit code
  `64` (`EX_USAGE` / `ExitCode.usage.code`) must be returned. `stdout` should
  ONLY receive usage help when the user explicitly requests it via `--help` or
  `-h`.
* **No `print()` in Error Handlers**: `print()` routes to `stdout`. Use `stderr.writeln()` for all failure notifications. For standard output, prefer `stdout.writeln()` over `print()` to comply with the [`avoid_print`](https://dart.dev/tools/linter-rules/avoid_print) lint rule (unless `analysis_options.yaml` explicitly configures `avoid_print: false`).
* **Terminal Capability Detection & `NO_COLOR`**: Verify `stdout.hasTerminal`, `stdout.supportsAnsiEscapes`, and `!Platform.environment.containsKey('NO_COLOR')` before emitting ANSI color or cursor escape codes:
  ```dart
  bool get useAnsi =>
      stdout.hasTerminal &&
      stdout.supportsAnsiEscapes &&
      !Platform.environment.containsKey('NO_COLOR');
  ```
* **Machine-Readable Modes**: When `--json` or `--machine` flags are passed, format data as JSON to `stdout` and route logs to `stderr`.

---

## 3. Project Configuration & Packaging

### Scaffolding & Pubspec Executable Mapping (`executables:`)
Scaffold new command-line projects using `dart create -t console <package_name>`, which initializes the standard `bin/` and `lib/` layout. Always declare executables in `pubspec.yaml` under `executables:` to map command names to scripts in `bin/`, enabling clean invocation via `dart run <command>` (without specifying `bin/...dart`) and configuring global binary symlinks for `dart install`:

```yaml
name: my_cli
description: High-performance CLI tool.
version: 1.0.0

executables:
  my_cli: # Maps to bin/my_cli.dart
  secondary_cmd: helper # Maps to bin/helper.dart
```

### Single-Source Versioning (`package:build_version`)
Avoid hardcoding `--version` strings in `bin/*.dart` or manually synchronizing constant files. Use `package:build_version` to generate `lib/src/version.dart` containing `const packageVersion = 'x.y.z';` directly from `pubspec.yaml` during builds.

### Caching Conventions
Store transient cache files in `.dart_tool/<package_name>/`. Never write persistent cache files directly to the project root.

---

## 4. Argument Parsing & Command Routing

Import `package:args` to manage command-line arguments:

* **Simple Scripts**: Use `ArgParser` directly with `addFlag()` and `addOption()`.
* **Multi-Command Tools**: Implement `CommandRunner<int>` and extend `Command<int>` for each subcommand, returning POSIX exit codes directly.
* **Type-Safe Accessors**: Use `results.flag('name')`, `results.option('name')`, and `results.multiOption('name')` (available in `package:args` 2.5+) instead of map indexing `operator []` to eliminate manual type casts (`as bool`, `as String?`).
* **Complex Options Models**: For applications with extensive flags, use `package:build_cli` to generate strongly-typed options classes. Leverage named default overrides (e.g. `{String? hostDefaultOverride}`) to cleanly merge configuration files with CLI flags.

---

## 5. Native Async & Modern Stack Traces

* **Avoid `Chain.capture()`**: The Dart VM natively preserves asynchronous stack frames across `await` suspension points. `Chain.capture` wraps the event loop in custom Zones, incurring substantial allocation overhead and trapping errors across Zone boundaries.
* **Sanitize with `Trace.from(st).terse`**: Use static utilities from `package:stack_trace` on uncaught errors without capturing zones:

```dart
import 'dart:io';
import 'package:io/io.dart' show ExitCode;
import 'package:stack_trace/stack_trace.dart';

Future<void> runMain(List<String> args) async {
  try {
    await executeLogic(args);
    exitCode = ExitCode.success.code;
  } catch (e, st) {
    stderr.writeln('Fatal error: $e');
    if (args.contains('-v') || args.contains('--verbose')) {
      stderr.writeln(Trace.from(st).terse);
    }
    exitCode = ExitCode.software.code;
  }
}
```

---

## 6. Subprocess Spawning & AOT Resilience

When spawning Dart SDK subprocesses or executing other Dart tools (e.g., `dart format`, `dart test`, `build_runner`):

* **Do not assume `Platform.resolvedExecutable` or `Platform.executable` points to the `dart` command-line executable**: In standalone AOT-compiled binaries (`dart install` / `dart compile exe`), `resolvedExecutable` points to the compiled application binary itself, causing recursive self-invocation loops or flag rejection crashes.
* **Use `package:cli_util`**: Resolve the Dart SDK executable using `cli_util.dartExecutable` or `cli_util.sdkPath` instead of writing custom PATH or directory scrapers.
* See version requirements and detailed technical guide in [references/aot_sdk_discovery.md](references/aot_sdk_discovery.md).

---

## 7. Signal Handling & Terminal Teardown

If your CLI alters terminal modes, displays spinners, or opens listening sockets:

* **Windows Signal Guard**: On Windows, `ProcessSignal.sigterm.watch()` throws `UnsupportedError`. Guard `sigterm` with `if (!Platform.isWindows)`.
* **Echo & Line Mode Teardown**: If setting `stdin.echoMode = false` or `stdin.lineMode = false`, check `if (!stdin.hasTerminal) return;` first, and install a `SIGINT` listener and `finally` block to restore them so user keystrokes remain visible after exit.
* **Cursor Visibility**: If emitting ANSI hide-cursor (`\x1B[?25l`), always restore cursor visibility (`\x1B[?25h`) on exit or cancellation.
* **Socket Cleanup**: Explicitly close listening `HttpServer` or `ServerSocket` instances (`server.close(force: true)`) on termination signals to immediately release OS ports.
* See detailed patterns in [references/signals_and_terminal.md](references/signals_and_terminal.md).

---

## 8. Testing CLI Applications

Structure testing across two distinct layers:

1. **Unit Tests (In-Memory, `< 5ms`)**: Test command classes, option parsing, and business logic directly by importing `package:<pkg>/src/...` in `test/`.
2. **Integration Tests (Subprocesses)**: Use `package:test_process` and `package:test_descriptor` to verify end-to-end binary execution, process I/O streaming, and OS exit codes:

```dart
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:test_process/test_process.dart';

void main() {
  test('CLI processes input and exits cleanly', () async {
    await d.file('input.txt', 'hello').create();

    final process = await TestProcess.start('dart', [
      'run',
      'bin/my_cli.dart',
      '--input',
      d.path('input.txt'),
    ]);

    await expectLater(process.stdout, emitsThrough('Processing complete.'));
    await process.shouldExit(0);
  });
}
```

---

## 9. Modern Compilation & Distribution

Dart 3.12+ standardizes CLI distribution around `dart run` and `dart install` (moving away from `dart pub global activate`):

* **Ephemeral Execution (JIT)**: `dart run <package>@<version> [args]` downloads and runs the CLI on demand.
* **Global Installation (Native AOT)**: `dart install <package>` compiles the package entrypoint to a fast native standalone binary in `~/.dart/install/bin/`.
* **Local Development**: Use `dart run <command>` (resolves via `executables:` in `pubspec.yaml`) or `dart run bin/cli.dart`.
* **Bundling Dynamic Libraries & Code Assets**: Use `dart build cli`. Outputs bundle to `build/cli/_/bundle/`.
* **Standalone Executable Compilation**: Use `dart compile exe bin/cli.dart -o <output_path>`.

---

## 10. Workflows & Audit Checklist

### Implementation Workflow
- [ ] Declare entry points in `pubspec.yaml` under `executables:`.
- [ ] Keep `bin/*.dart` as a thin entrypoint; place command logic in `lib/src/`.
- [ ] Return integer exit codes or set `exitCode = N`; avoid raw `exit(N)`.
- [ ] Direct errors, warnings, and usage on parse failure to `stderr`.
- [ ] Use `results.flag()`, `results.option()`, and `results.multiOption()` for type safety.
- [ ] Validate `useAnsi` (checking `stdout.hasTerminal`, `supportsAnsiEscapes`, and `NO_COLOR`) before emitting ANSI codes.
- [ ] Spawn child tools using `cli_util.dartExecutable`, never `Platform.resolvedExecutable`.
- [ ] Unit-test command runners in-memory; test end-to-end binary execution with `test_process`.

---

## References & Examples

* **Single-Command Tool Template**: [examples/single_command_tool.dart](examples/single_command_tool.dart)
* **Multi-Command Runner Template**: [examples/multi_command_runner.dart](examples/multi_command_runner.dart)
* **AOT SDK Discovery & Subprocess Spawning**: [references/aot_sdk_discovery.md](references/aot_sdk_discovery.md)
* **Signal Handling & Terminal Teardown**: [references/signals_and_terminal.md](references/signals_and_terminal.md)

<!-- chapter:end slug=dart-build-cli-app -->

---

<!-- chapter:begin slug=dart-collect-coverage position=3 -->

## 3. dart-collect-coverage

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-collect-coverage/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-collect-coverage/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-collect-coverage.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-collect-coverage
description: Collect coverage using the coverage packge and create an LCOV report
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 24 Apr 2026 15:14:32 GMT
---
# Implementing Dart and Flutter Test Coverage

## Contents
- [Testing Fundamentals](#testing-fundamentals)
- [Coverage Directives](#coverage-directives)
- [Workflow: Configuring and Generating Coverage Reports](#workflow-configuring-and-generating-coverage-reports)
- [Workflow: Advanced Manual Coverage Collection](#workflow-advanced-manual-coverage-collection)
- [Examples](#examples)

## Testing Fundamentals

Structure your test suites using the standard Dart testing paradigms. Use `package:test` for Dart projects and `flutter_test` for Flutter projects.

- **Unit Tests:** Verify individual functions, methods, or classes.
- **Component/Widget Tests:** Verify component behavior, layout, and interaction using mock objects (`package:mockito`).
- **Integration Tests:** Verify entire app flows on simulated or real devices.

## Coverage Directives

Exclude specific lines, blocks, or entire files from coverage metrics using inline comments. Pass the `--check-ignore` flag during formatting to enforce these directives.

- Ignore a single line: `// coverage:ignore-line`
- Ignore a block of code: `// coverage:ignore-start` and `// coverage:ignore-end`
- Ignore an entire file: `// coverage:ignore-file`

## Workflow: Configuring and Generating Coverage Reports

Follow this sequential workflow to add the coverage package, execute tests, and generate an LCOV report.

**Task Progress Checklist:**
- [ ] 1. Add `coverage` as a `dev_dependency`.
- [ ] 2. Execute the automated coverage script.
- [ ] 3. Validate the LCOV output.

### 1. Add Dependencies
Add the `coverage` package as a `dev_dependency` to your project. Do not add it to standard dependencies.

If working in a standard Dart project:
```bash
dart pub add dev:coverage
```

If working in a Flutter project:
```bash
flutter pub add dev:coverage
```

### 2. Collect Coverage and Generate LCOV
Use the bundled `test_with_coverage` script. This script automatically runs all tests, collects the JSON coverage data from the Dart VM, and formats it into an LCOV report.

```bash
dart run coverage:test_with_coverage
```
*Note: If working within a Dart workspace (monorepo), specify the test directories explicitly (e.g., `dart run coverage:test_with_coverage -- pkgs/foo/test pkgs/bar/test`).*

### 3. Feedback Loop: Validate Output
**Run validator -> review errors -> fix:**
1. Verify that the `coverage/` directory was created in the project root.
2. Ensure `coverage/coverage.json` (raw data) and `coverage/lcov.info` (formatted report) exist.
3. If coverage is missing for specific files, ensure they are imported and executed by your test files, or add `// coverage:ignore-file` if they are intentionally excluded.

## Workflow: Advanced Manual Coverage Collection

If you require granular control over the VM service, isolate pausing, or need branch/function-level coverage, use the manual collection workflow.

**Task Progress Checklist:**
- [ ] 1. Run tests with VM service enabled.
- [ ] 2. Collect raw JSON coverage.
- [ ] 3. Format JSON to LCOV.

### 1. Run Tests with VM Service
Execute tests while pausing isolates on exit and exposing the VM service on a specific port (e.g., 8181).

```bash
dart run --pause-isolates-on-exit --disable-service-auth-codes --enable-vm-service=8181 test &
```

### 2. Collect Raw Coverage
Extract the coverage data from the running VM service and output it to a JSON file.

```bash
dart run coverage:collect_coverage --wait-paused --uri=http://127.0.0.1:8181/ -o coverage/coverage.json --resume-isolates
```
*Optional: Append `--function-coverage` and `--branch-coverage` to gather deeper metrics (requires Dart VM 2.17.0+).*

### 3. Format to LCOV
Convert the raw JSON data into the standard LCOV format.

```bash
dart run coverage:format_coverage --packages=.dart_tool/package_config.json --lcov -i coverage/coverage.json -o coverage/lcov.info --check-ignore
```

## Examples

### Example: `pubspec.yaml` Configuration
Ensure your `pubspec.yaml` reflects the `coverage` package strictly under `dev_dependencies`.

```yaml
name: my_dart_app
environment:
  sdk: ^3.0.0

dependencies:
  path: ^1.8.0

dev_dependencies:
  test: ^1.24.0
  coverage: ^1.15.0
```

### Example: Applying Ignore Directives
Use ignore directives to prevent generated code or untestable edge cases from lowering coverage scores.

```dart
// coverage:ignore-file
import 'package:meta/meta.dart';

class SystemConfig {
  final String env;

  SystemConfig(this.env);

  // coverage:ignore-start
  void legacyInit() {
    print('Deprecated initialization');
  }
  // coverage:ignore-end

  bool isProduction() {
    if (env == 'prod') return true;
    return false; // coverage:ignore-line
  }
}
```

<!-- chapter:end slug=dart-collect-coverage -->

---

<!-- chapter:begin slug=dart-fix-runtime-errors position=4 -->

## 4. dart-fix-runtime-errors

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-fix-runtime-errors/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-fix-runtime-errors/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-fix-runtime-errors.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-fix-runtime-errors
description: 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.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 24 Apr 2026 15:13:22 GMT
---
# Resolving Dart Static Analysis Errors

## Contents
- [Core Concepts & Guidelines](#core-concepts--guidelines)
  - [Type System & Soundness](#type-system--soundness)
  - [Null Safety](#null-safety)
  - [Error Handling](#error-handling)
- [Workflows](#workflows)
  - [Workflow: Static Analysis Resolution](#workflow-static-analysis-resolution)
- [Examples](#examples)

## Core Concepts & Guidelines

### Type System & Soundness
Enforce Dart's sound type system to prevent runtime invalid states.

*   **Method Overrides:** Maintain sound return types (covariant) and parameter types (contravariant). Never tighten a parameter type in a subclass unless explicitly marked with the `covariant` keyword.
*   **Generics & Collections:** Add explicit type annotations to generic classes (e.g., `List<T>`, `Map<K, V>`). Never assign a `List<dynamic>` to a typed list (e.g., `List<Cat>`).
*   **Downcasting:** Avoid implicit downcasts from `dynamic`. Use explicit casts (e.g., `as List<Cat>`) when necessary, but ensure the underlying runtime type matches to prevent `TypeError` exceptions.
*   **Strict Casts:** Enable `strict-casts: true` in `analysis_options.yaml` under `analyzer: language:` to force explicit casting and catch implicit downcast errors at compile time.

### Null Safety
Eliminate static errors related to null safety by correctly managing variable initialization and nullability.

*   **Modifiers:** Apply `?` for nullable types, `!` for null assertions, and `required` for named parameters that cannot be null.
*   **Late Initialization:** Use the `late` keyword for non-nullable variables guaranteed to be initialized before use. Apply this specifically to top-level or instance variables where Dart's control flow analysis cannot definitively prove initialization.
*   **Wildcards:** Use the `_` wildcard variable (Dart 3.7+) for non-binding local variables or parameters to avoid unused variable warnings.

### Error Handling
Distinguish between recoverable exceptions and unrecoverable errors.

*   **Catching:** Catch `Exception` subtypes for recoverable failures.
*   **Errors:** Never explicitly catch `Error` or its subtypes (e.g., `TypeError`, `ArgumentError`). Errors indicate programming bugs that must be fixed, not caught. Enforce this by enabling the `avoid_catching_errors` linter rule.
*   **Rethrowing:** Use `rethrow` inside a `catch` block to propagate an exception while preserving its original stack trace.

## Workflows

### Workflow: Static Analysis Resolution

Use this sequential workflow to identify, fix, and verify static analysis errors in a Dart project. Copy the checklist to track your progress.

**Task Progress:**
- [ ] 1. Run static analyzer.
- [ ] 2. Apply automated fixes.
- [ ] 3. Resolve remaining errors manually.
- [ ] 4. Verify fixes (Feedback Loop).

**1. Run static analyzer**
Execute the Dart analyzer to identify all static errors in the target directory or file.
```bash
dart analyze . --fatal-infos
```

**2. Apply automated fixes**
Use the `dart fix` tool to automatically resolve standard linting and analysis issues.
```bash
# Preview changes
dart fix --dry-run
# Apply changes
dart fix --apply
```

**3. Resolve remaining errors manually**
Review the remaining analyzer output and apply conditional logic based on the error type:

*   **If the error is a Null Safety issue (e.g., "Property cannot be accessed on a nullable receiver"):**
    *   Verify if the variable can logically be null.
    *   If yes, use optional chaining (`?.`) or provide a fallback (`??`).
    *   If no, and initialization is guaranteed elsewhere, mark the declaration with `late`.
*   **If the error is a Type Mismatch (e.g., "The argument type 'List<dynamic>' can't be assigned..."):**
    *   Trace the variable's initialization.
    *   Add explicit generic type annotations to the instantiation (e.g., `<int>[]` instead of `[]`).
*   **If the error is an Invalid Override (e.g., "The parameter type doesn't match the overridden method"):**
    *   Widen the parameter type to match the superclass, OR
    *   Add the `covariant` keyword to the parameter if tightening the type is intentionally required by the domain logic.

**4. Verify fixes (Feedback Loop)**
Run the validator. Review errors. Fix.
```bash
dart analyze .
dart test
```
*   **If `dart analyze` reports errors:** Return to Step 3.
*   **If `dart test` fails with a `TypeError`:** You have introduced an invalid explicit cast (`as T`) or accessed an uninitialized `late` variable. Locate the runtime failure and correct the type hierarchy or initialization order.

## Examples

### Example: Fixing Dynamic List Assignments
**Input (Fails Static Analysis):**
```dart
void printInts(List<int> a) => print(a);

void main() {
  final list = []; // Inferred as List<dynamic>
  list.add(1);
  list.add(2);
  printInts(list); // Error: List<dynamic> can't be assigned to List<int>
}
```

**Output (Passes Static Analysis):**
```dart
void printInts(List<int> a) => print(a);

void main() {
  final list = <int>[]; // Explicitly typed
  list.add(1);
  list.add(2);
  printInts(list);
}
```

### Example: Fixing Method Overrides (Contravariance)
**Input (Fails Static Analysis):**
```dart
class Animal {
  void chase(Animal a) {}
}

class Cat extends Animal {
  @override
  void chase(Mouse a) {} // Error: Tightening parameter type
}
```

**Output (Passes Static Analysis):**
```dart
class Animal {
  void chase(Animal a) {}
}

class Cat extends Animal {
  @override
  void chase(covariant Mouse a) {} // Explicitly marked covariant
}
```

### Example: Fixing Null Safety with `late`
**Input (Fails Static Analysis):**
```dart
class Thermometer {
  String temperature; // Error: Non-nullable instance field must be initialized

  void read() {
    temperature = '20C';
  }
}
```

**Output (Passes Static Analysis):**
```dart
class Thermometer {
  late String temperature; // Defers initialization check to runtime

  void read() {
    temperature = '20C';
  }
}
```

<!-- chapter:end slug=dart-fix-runtime-errors -->

---

<!-- chapter:begin slug=dart-generate-test-mocks position=5 -->

## 5. dart-generate-test-mocks

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-generate-test-mocks/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-generate-test-mocks/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-generate-test-mocks.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-generate-test-mocks
description: 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.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 24 Apr 2026 15:13:58 GMT
---
# Testing and Mocking Dart Applications

## Contents
- [Structuring Code for Testability](#structuring-code-for-testability)
- [Managing Dependencies](#managing-dependencies)
- [Generating Mocks](#generating-mocks)
- [Implementing Unit Tests](#implementing-unit-tests)
- [Workflow: Creating and Running Mocked Tests](#workflow-creating-and-running-mocked-tests)
- [Examples](#examples)

## Structuring Code for Testability
Design Dart classes to support dependency injection. Isolate complex external dependencies (like API clients or databases) so they can be replaced with mock objects during testing.

- Inject external services (e.g., `http.Client`) through class constructors.
- Represent URLs strictly as `Uri` objects using `Uri.parse(string)`.
- Utilize Dart's object-oriented features (classes, mixins) to define clear interfaces for external interactions.

## Managing Dependencies
Configure the `pubspec.yaml` file with the necessary testing and code generation packages.

- Add runtime dependencies (e.g., `package:http`) using `dart pub add http`.
- Add testing dependencies using `dart pub add dev:test dev:mockito dev:build_runner`.
- Import HTTP libraries with a prefix to avoid namespace collisions: `import 'package:http/http.dart' as http;`.

## Generating Mocks
Use `package:mockito` and `build_runner` to automatically generate mock classes for fixed scenarios and behavior verification.

- Always use the `@GenerateNiceMocks` annotation (preferable to `@GenerateMocks` to avoid missing stub exceptions).
- Place the annotation in the test file, passing a list of `MockSpec<Type>()` objects.
- Import the generated file using the `.mocks.dart` extension.
- Execute `build_runner` to generate the mock files: `dart run build_runner build`.

## Implementing Unit Tests
Isolate the system under test using the generated mock objects. Use `package:test` to structure the test suite.

- **Stubbing:** Configure mock behavior before interacting with the system under test.
  - Use `when(mock.method()).thenReturn(value)` for synchronous methods.
  - **CRITICAL:** Always use `thenAnswer((_) async => value)` for methods returning a `Future` or `Stream`. Never use `thenReturn` for asynchronous returns.
- **Verification:** Assert that the system under test interacted with the mock object correctly.
  - Use `verify(mock.method()).called(1)` to check exact invocation counts.
  - Use argument matchers like `any`, `anyNamed`, or `captureAny` for flexible verification.

## Workflow: Creating and Running Mocked Tests

Use the following checklist to implement and verify mocked unit tests.

### Task Progress
- [ ] 1. Identify the external dependency to mock (e.g., `http.Client`).
- [ ] 2. Inject the dependency into the target class constructor.
- [ ] 3. Create a test file (e.g., `target_test.dart`) and add `@GenerateNiceMocks([MockSpec<Dependency>()])`.
- [ ] 4. Add the `part` or `import` directive for the generated `.mocks.dart` file.
- [ ] 5. Run `dart run build_runner build` to generate the mock classes.
- [ ] 6. Write the test cases using `group()` and `test()`.
- [ ] 7. Stub required behaviors using `when()`.
- [ ] 8. Execute the target method.
- [ ] 9. Verify interactions using `verify()` and assert outcomes using `expect()`.
- [ ] 10. Run the test suite using `dart test`.

### Feedback Loop: Test Failures
If tests fail or `build_runner` encounters errors:
1. **Run validator:** Execute `dart test` or `dart run build_runner build`.
2. **Review errors:** Check for missing stubs, mismatched argument matchers, or syntax errors in the generated files.
3. **Fix:**
   - If a mock method throws an unexpected null error, ensure you used `@GenerateNiceMocks`.
   - If an async stub throws an `ArgumentError`, change `thenReturn` to `thenAnswer`.
   - If `build_runner` fails, ensure the `.mocks.dart` import matches the file name exactly.
4. Repeat until all tests pass.

## Examples

### High-Fidelity Mocking and Testing Example

**1. System Under Test (`lib/api_service.dart`)**
```dart
import 'dart:convert';
import 'package:http/http.dart' as http;

class ApiService {
  final http.Client client;

  ApiService(this.client);

  Future<String> fetchData(String urlString) async {
    final uri = Uri.parse(urlString);
    final response = await client.get(uri);

    if (response.statusCode == 200) {
      return jsonDecode(response.body)['data'];
    } else {
      throw Exception('Failed to load data');
    }
  }
}
```

**2. Test Implementation (`test/api_service_test.dart`)**
```dart
import 'package:test/test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:http/http.dart' as http;
import 'package:my_app/api_service.dart';

// Generate the mock class for http.Client
@GenerateNiceMocks([MockSpec<http.Client>()])
import 'api_service_test.mocks.dart';

void main() {
  group('ApiService', () {
    late ApiService apiService;
    late MockClient mockHttpClient;

    setUp(() {
      mockHttpClient = MockClient();
      apiService = ApiService(mockHttpClient);
    });

    test('returns data if the http call completes successfully', () async {
      // Arrange: Stub the async HTTP GET request using thenAnswer
      when(mockHttpClient.get(any)).thenAnswer(
        (_) async => http.Response('{"data": "Success"}', 200),
      );

      // Act
      final result = await apiService.fetchData('https://api.example.com/data');

      // Assert
      expect(result, 'Success');

      // Verify the mock was called with the correct Uri
      verify(mockHttpClient.get(Uri.parse('https://api.example.com/data'))).called(1);
    });

    test('throws an exception if the http call completes with an error', () {
      // Arrange
      when(mockHttpClient.get(any)).thenAnswer(
        (_) async => http.Response('Not Found', 404),
      );

      // Act & Assert
      expect(
        apiService.fetchData('https://api.example.com/data'),
        throwsException,
      );
    });
  });
}
```

<!-- chapter:end slug=dart-generate-test-mocks -->

---

<!-- chapter:begin slug=dart-migrate-to-checks-package position=6 -->

## 6. dart-migrate-to-checks-package

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-migrate-to-checks-package/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-migrate-to-checks-package/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-migrate-to-checks-package.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-migrate-to-checks-package
description: |-
  Replace the usage of `expect` and similar functions from `package:matcher`
  to `package:checks` equivalents.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 09 Jun 2026 19:30:00 GMT
---
# Migrating Dart Tests to Package Checks

Use this skill when you need to migrate a Dart test suite from the legacy
`package:matcher` (which is exported by default from `package:test/test.dart`)
to the modern, type-safe, and literate `package:checks` assertion library.

## Contents
- [When to Use This Skill](#when-to-use-this-skill)
- [How to Use This Skill (The Workflow)](#how-to-use-this-skill-the-workflow)
- [Key Syntax Differences and Pitfalls](#key-syntax-differences-and-pitfalls)
- [Matcher-to-Checks Mapping Table](#matcher-to-checks-mapping-table)
- [Matchers with No Direct Replacements](#matchers-with-no-direct-replacements)
- [Strategies for Discovery](#strategies-for-discovery)
- [Examples](#examples)

---

## When to Use This Skill
- When asked to "migrate tests to checks", "use package:checks", or
  "modernize test assertions".
- When updating legacy test suites where static type safety, better
  autocomplete in IDEs, and highly detailed failure diagnostics are desired.

---

## How to Use This Skill (The Workflow)

Follow this structured workflow to safely and systematically migrate a test suite:

### 1. Dependency Setup
- Add `package:checks` as a `dev_dependency` in `pubspec.yaml`:
  ```bash
  dart pub add dev:checks
  ```
- Remove `package:matcher` if it is explicitly listed under `dev_dependencies`
  (it is typically transitively included by `package:test`, which is fine).

### 2. Identify and Plan Target Files
- Use the grep patterns in [Strategies for Discovery](#strategies-for-discovery)
  to locate all test files containing legacy `expect` or `expectLater` calls.
- Decide whether to migrate files fully or incrementally.

### 3. Migrating a File (Incremental or Full)
For any target test file:
1. **Update Imports**:
   - Replace the generic `import 'package:test/test.dart';` with:
     ```dart
     import 'package:test/scaffolding.dart';
     import 'package:checks/checks.dart';
     ```
   - **For Incremental Migration**: If you only want to migrate some test cases
     in the file, or want to migrate one step at a time, add:
     ```dart
     import 'package:test/expect.dart'; // Temporarily allows legacy expect()
     ```
2. **Translate Assertions**: Rewrite legacy `expect` and `expectLater` calls
   to `check` syntax following the [Key Syntax Differences and
   Pitfalls](#key-syntax-differences-and-pitfalls) and the
   [Matcher-to-Checks Mapping Table](#matcher-to-checks-mapping-table).
3. **Verify via Compiler**: If migrating fully, remove the `import
   'package:test/expect.dart';` line. Any remaining un-migrated `expect`
   calls will immediately surface as compiler errors, making them easy to
   find and fix.

### 4. Verification and Feedback Loops
- **Static Analysis**: Run static analysis on the target package:
  ```bash
  dart analyze
  ```
  Pay close attention to generic type parameters on `.isA<Type>()` and
  ensure asynchronous expectations are properly awaited (check for
  `unawaited_futures` warnings).
- **Run Tests**: Execute the tests to verify both behavior and correct
  assertion runtime logic:
  ```bash
  dart test
  ```
  If a test fails, review the extremely detailed failure output of
  `package:checks` to diagnose if the test is genuinely failing or if the
  expectation was translated incorrectly.

---

## Key Syntax Differences and Pitfalls

> [!IMPORTANT]
> A line-for-line translation can sometimes introduce subtle bugs or false
> passes. Always review these key differences carefully:

### 1. Collection Equality Pitfall (`equals` vs `deepEquals`)
- **Legacy Matcher**: `expect(actual, expected)` or `expect(actual,
  equals(expected))` performed a **deep equality check** if the arguments
  were collections (Lists, Maps, Sets).
- **Package Checks**: `.equals(expected)` corresponds strictly to
  `operator ==`. Since Dart collections do not override `operator ==` for
  element-wise comparison, using `.equals` on a collection will check for
  *identity* and almost certainly fail at runtime.
- **Remediation**: You **must** replace collection equality assertions with
  `.deepEquals(expected)`.
  ```dart
  // BEFORE (Matcher)
  expect(myList, [1, 2, 3]);

  // AFTER (Checks)
  check(myList).deepEquals([1, 2, 3]);
  ```

### 2. The `reason` Parameter is now `because`
- **Legacy Matcher**: The explanation was passed as a trailing named
  argument `reason` to `expect`:
  ```dart
  expect(actual, expectation, reason: 'Explanation');
  ```
- **Package Checks**: The explanation is passed as the named argument
  `because` to the `check` function *before* the actual subject:
  ```dart
  check(because: 'Explanation', actual).expectation();
  ```

### 3. Regular Expression Matching (`matches` vs `matchesPattern`)
- **Legacy Matcher**: The `matches(pattern)` matcher automatically converted
  a `String` argument into a `RegExp` (e.g., `matches(r'\d')` matched `'1'`).
- **Package Checks**: `.matchesPattern(pattern)` treats a `String` argument
  as a literal string pattern.
- **Remediation**: To match using a regular expression, you must explicitly
  pass a `RegExp` object:
  ```dart
  // BEFORE (Matcher)
  expect(someString, matches(r'\d+'));

  // AFTER (Checks)
  check(someString).matchesPattern(RegExp(r'\d+'));
  ```

### 4. Property Extraction (`TypeMatcher.having` vs `.has`)
- **Legacy Matcher**: Chained field/property expectations used
  `TypeMatcher.having(feature, description, matcher)`:
  ```dart
  expect(actual, isA<Person>().having((p) => p.name, 'name', startsWith('A')));
  ```
- **Package Checks**: The `.has(feature, description)` extension is
  available on all `Subject`s, takes one fewer argument, and returns a new
  `Subject` representing that property. You chain expectations directly off
  it:
  ```dart
  check(actual).isA<Person>().has((p) => p.name, 'name').startsWith('A');
  ```

### 5. Synchronous vs. Asynchronous `throws`
- **Legacy Matcher**: In `package:matcher`, `throwsA` behaved similarly for both
  synchronous closures and asynchronous futures when wrapped in `expect` or
  `expectLater`.
- **Package Checks**: The `.throws<E>()` expectation behaves differently and
  has different return types depending on whether the subject is synchronous or
  asynchronous:
  - **Synchronous** (`Subject<T Function()>`): `.throws<E>()` returns a
    `Subject<E>` synchronously. This **does not** accept a callback argument!
    You chain or cascade expectations directly off the returned `Subject<E>`:
    ```dart
    // YES (Synchronous chaining)
    check(() => triggerSyncError()).throws<ArgumentError>()
      ..has((e) => e.message, 'message').equals('invalid input');

    // NO (Passing a callback to sync throws will cause a compiler error!)
    check(() => triggerSync").throws<ArgumentError>((it) => ...); // ERROR!
    ```
  - **Asynchronous** (`Subject<Future<T>>`): `.throws<E>()` returns
    `Future<void>`. Because you cannot chain directly off a `Future<void>`, this
    **requires** an inspection callback:
    ```dart
    // YES (Asynchronous callback)
    await check(triggerAsyncError()).throws<ArgumentError>((it) => it
      ..has((e) => e.message, 'message').equals('invalid input'));
    ```
  - **Crucial Pitfall**: Trying to chain expectations directly after an awaited
    asynchronous `.throws<E>()` (e.g.,
    `await check(future).throws<E>().equals(...)`) will fail to compile
    because it returns `Future<void>`.

### 6. RegExp / Pattern Equality
- **Legacy Matcher**: In `package:matcher`, `expect(myPattern,`
  `equals(RegExp('Hello')))` worked because the matcher comparison rules
  handled RegExp instances.
- **Package Checks**: `.equals()` uses strict Dart `==` equality. Since separate
  `RegExp` instances do not satisfy `==`, using `.equals()` will fail at runtime.
- **Remediation**: Use `.isA<RegExp>()` type refinement along with cascades to
  assert on the properties of the `RegExp` object explicitly:
  ```dart
  check(myPattern).isA<RegExp>()
    ..has((r) => r.pattern, 'pattern').equals('Hello')
    ..has((r) => r.isMultiLine, 'isMultiLine').isTrue();
  ```

### 7. Strict Nullable Boolean Safety (`bool?` fields)
- **Legacy Matcher**: Statically, `isTrue` and `isFalse` performed loose
  dynamic checks at runtime, which silently accepted nullable booleans (`bool?`).
- **Package Checks**: `.isTrue()` and `.isFalse()` are defined strictly on
  `Subject<bool>` (non-nullable). They are **not** available on `Subject<bool?>`.
- **Remediation**: For fields declared as `bool?`, you must either refine the
  subject (e.g., `.isNotNull().isTrue()`) or simply use `.equals(true)` and
  `.equals(false)` which are generic and work on all types:
  ```dart
  // If options.flagOutdated is a bool?
  check(options.flagOutdated).equals(true);
  check(options.flagOutdated).equals(false);
  ```

### 8. Map Key Containment (`containsKey` vs `contains`)
- **Legacy Matcher**: In `package:matcher`, `contains(key)` was used to assert
  that a `Map` contained a specific key.
- **Package Checks**: Calling `.contains(...)` on a `Subject<Map>` is not
  defined and will fail compilation.
- **Remediation**: Use the map-specific `.containsKey(key)` matcher instead:
  ```dart
  // BEFORE (Matcher)
  expect(myMap, contains('my_key'));

  // AFTER (Checks)
  check(myMap).containsKey('my_key');
  ```

### 9. Explicit Generic Parameters for Extension Types
- **Legacy Matcher**: `expect(extensionTypeConst, 3)` compiled because of loose
  dynamic equality.
- **Package Checks**: If `QrEciValue` is an extension type representation of `int`
  (e.g., `extension type const QrEciValue(int value) implements int`), calling
  `.equals(3)` on a `Subject<QrEciValue>` fails because `3` (an `int`) is not
  assignable to `QrEciValue`. Casting with `as int` will trigger an
  "Unnecessary cast" static analysis warning because `QrEciValue` statically
  implements `int`.
- **Remediation**: Explicitly specify the generic type parameter on the `check`
  function to force checks to treat it as the primitive type:
  ```dart
  // YES (Type-safe and warning-free)
  check<int>(QrEciValue.iso8859_1).equals(3);
  ```

### 10. Dynamic Map / JSON Lookup Casting
- **Legacy Matcher**: Loose dynamic typing allowed comparing nested json lookups
  statically typed as `dynamic` directly against lists or maps.
- **Package Checks**: Strict type safety rejects the implicit assignment of
  `dynamic` to `Iterable<Object?>` in `.deepEquals(...)`.
- **Remediation**: Statically cast the dynamic lookup result to a `List` or `Map`:
  ```dart
  // YES (Explicit cast to List)
  check(myIterable).deepEquals(json['data']['items'] as List);
  ```

---

## Matcher-to-Checks Mapping Table

Use this table as a quick reference for direct matcher replacements:

| Legacy Matcher | Package Checks Equivalent | Notes |
| :--- | :--- | :--- |
| `expect(actual, expected)` | `check(actual).equals(expected)` | Use `.deepEquals` for collections! |
| `expect(actual, equals(expected))` | `check(actual).equals(expected)` | Use `.deepEquals` for collections! |
| `isA<T>()` | `check(actual).isA<T>()` | Chaining is supported directly |
| `same(expected)` | `check(actual).identicalTo(expected)` | Verifies identity |
| `anyElement(matcher)` | `check(iterable).any(conditionCallback)` | E.g. `check(list).any((e) => e.equals(1))` |
| `everyElement(matcher)` | `check(iterable).every(conditionCallback)` | E.g. `check(list).every((e) => e.isGreaterThan(0))` |
| `hasLength(expected)` | `check(actual).length.equals(expected)` | Works on String, Map, Iterable, etc. |
| `isNot(matcher)` | `check(actual).not(conditionCallback)` | E.g. `check(val).not((it) => it.equals(5))` |
| `contains(element)` | `check(actual).contains(element)` | Works on String, Iterable (use `containsKey` for Map!) |
| `contains(key)` (on a Map) | `check(map).containsKey(key)` | Map key containment |
| `startsWith(prefix)` | `check(string).startsWith(prefix)` | String only |
| `endsWith(suffix)` | `check(string).endsWith(suffix)` | String only |
| `isEmpty` | `check(actual).isEmpty()` | Works on String, Map, Iterable |
| `isNotEmpty` | `check(actual).isNotEmpty()` | Works on String, Map, Iterable |
| `isNull` | `check(actual).isNull()` | |
| `isNotNull` | `check(actual).isNotNull()` | |
| `isTrue` / `true` | `check(actual).isTrue()` | Works on non-nullable `bool` only |
| `isFalse` / `false` | `check(actual).isFalse()` | Works on non-nullable `bool` only |
| `completion(matcher)` | `await check(future).completes(conditionCallback)` | Must be awaited! |
| `throwsA(matcher)` | `await check(future).throws<Type>()` | Must be awaited! |
| `emits(value)` | `await check(streamQueue).emits(conditionCallback)` | Must be awaited! |
| `emitsThrough(value)` | `await check(streamQueue).emitsThrough(conditionCallback)` | Must be awaited! |
| `stringContainsInOrder(list)` | `check(string).containsInOrder(list)` | String only |
| `pairwiseCompare(...)` | `check(actual).pairwiseMatches(...)` | |

---

## Matchers with No Direct Replacements

Some legacy matchers do not have a one-to-one equivalent in `package:checks`
due to API cleanup. Use these standard workarounds:

### 1. Specific Error Matchers
- **Legacy**: `throwsArgumentError`, `throwsStateError`,
  `throwsUnsupportedError`, etc.
- **Checks**: Use `.throws<T>()` with the specific error type:
  ```dart
  await check(triggerError()).throws<ArgumentError>();
  ```

### 2. The `anything` Matcher
- **Legacy**: `expect(actual, anything)`
- **Checks**: Pass an empty condition callback `(_) {}` when a condition is
  syntactically required:
  ```dart
  await check(someFuture).completes((_) {});
  ```

### 3. Specific Numeric Toggles
- **Legacy**: `isPositive`, `isNegative`, `isZero`, `isNonPositive`,
  `isNonNegative`, `isNonZero`
- **Checks**: Use explicit comparative expectations:
  - `isPositive` $\rightarrow$ `isGreaterThan(0)`
  - `isNegative` $\rightarrow$ `isLessThan(0)`
  - `isZero` $\rightarrow$ `equals(0)`
  - `isNonNegative` $\rightarrow$ `isGreaterOrEqual(0)`

### 4. Numeric Ranges
- **Legacy**: `inClosedOpenRange(min, max)`, `inInclusiveRange(min, max)`,
  etc.
- **Checks**: Chain the boundaries using the cascade operator (`..`):
  ```dart
  check(actualValue)
    ..isGreaterOrEqual(min)
    ..isLessThan(max);
  ```

---

## Writing Custom Expectations (Replacing Custom Matchers)

When migrating from a legacy codebase, you may encounter custom `Matcher`
subclasses. In `package:checks`, custom assertions are implemented as
`extension` methods on `Subject<T>`.

To write custom expectations, you must import the checks context API:
```dart
import 'package:checks/context.dart';
```

### 1. Simple Custom Expectations (using `expect`)
Use `context.expect` to check a property and return a `Rejection` on failure:
```dart
extension CustomPersonChecks on Subject<Person> {
  void isAdult() {
    context.expect(
      () => ['is an adult (age >= 18)'],
      (actual) {
        if (actual.age >= 18) return null; // Pass
        return Rejection(
          which: ['is only ${actual.age} years old'],
        );
      },
    );
  }
}
```

### 2. Nested Property Extraction (using `nest` or `has`)
To extract a property and allow further chained checks, use `nest` or the
simpler `has` helper:
- **Using `has` (Recommended for simple, non-failing field access)**:
  ```dart
  extension CustomPersonChecks on Subject<Person> {
    Subject<Address> get address => has((p) => p.address, 'address');
  }
  ```
- **Using `nest` (For property extraction that can fail or reject)**:
  ```dart
  extension CustomPersonChecks on Subject<Person> {
    Subject<String> get ssn => context.nest(
      'has a valid SSN',
      (actual) {
        final ssnValue = actual.ssn;
        if (ssnValue == null) {
          return Extracted.rejection(which: ['has no SSN']);
        }
        return Extracted.value(ssnValue);
      },
    );
  }
  ```

### 3. Asynchronous Custom Expectations
If the expectation is asynchronous (e.g. checking a Future or Stream), use
`context.expectAsync` or `context.nestAsync` and return the resulting `Future`:
```dart
extension CustomFutureChecks<T> on Subject<Future<T>> {
  Future<void> completesNormally() {
    return context.expectAsync(
      () => ['completes without throwing'],
      (actual) async {
        try {
          await actual;
          return null; // Pass
        } catch (e) {
          return Rejection(which: ['threw $e']);
        }
      },
    );
  }
}
```

---

## Strategies for Discovery

Execute these commands in the terminal to identify legacy matchers and files
requiring migration:

```bash
# 1. Find all test files containing legacy expect() or expectLater()
grep -rn "expect(" test/
grep -rn "expectLater(" test/

# 2. Find potential collection equality pitfalls (literal lists or maps)
grep -rn "expect(.*, \[" test/
grep -rn "expect(.*, {" test/

# 3. Find matches() calls (need conversion to RegExp + matchesPattern)
grep -rn "matches(" test/

# 4. Find legacy TypeMatcher.having() calls (which need conversion to .has())
grep -rn "having(" test/
```

---

## Examples

### Basic Assertions
**Before (Matcher):**
```dart
expect(someValue, isNotNull);
expect(result, isTrue, reason: 'should be successful');
expect(myString, startsWith('hello'));
```

**After (Checks):**
```dart
check(someValue).isNotNull();
check(because: 'should be successful', result).isTrue();
check(myString).startsWith('hello');
```

### Collection and Deep Equality
**Before (Matcher):**
```dart
expect(items, [1, 2, 3]);
expect(configMap, equals({'port': 8080}));
```

**After (Checks):**
```dart
check(items).deepEquals([1, 2, 3]);
check(configMap).deepEquals({'port': 8080});
```

### Chaining and Cascades
**Before (Matcher):**
```dart
expect(someString, allOf([
  startsWith('a'),
  contains('b'),
  endsWith('c'),
]));
```

**After (Checks):**
```dart
check(someString)
  ..startsWith('a')
  ..contains('b')
  ..endsWith('c');
```

### Complex Property Matching (has)
**Before (Matcher):**
```dart
expect(response, isA<Response>()
    .having((r) => r.statusCode, 'statusCode', 200)
    .having((r) => r.body, 'body', contains('success')));
```

**After (Checks):**
```dart
check(response).isA<Response>()
  ..has((r) => r.statusCode, 'statusCode').equals(200)
  ..has((r) => r.body, 'body').contains('success');
```

### Asynchronous Futures
**Before (Matcher):**
```dart
expect(fetchData(), completes);
expect(fetchData(), completion(equals('data')));
expect(failingCall(), throwsA(isA<StateError>()));
```

**After (Checks):**
```dart
await check(fetchData()).completes();
await check(fetchData()).completes((it) => it.equals('data'));
await check(failingCall()).throws<StateError>();
```

### Asynchronous Streams
**Before (Matcher):**
```dart
var queue = StreamQueue(Stream.fromIterable([1, 2, 3]));
await expectLater(queue, emitsInOrder([1, 2, 3]));
```

**After (Checks):**
```dart
var queue = StreamQueue(Stream.fromIterable([1, 2, 3]));
await check(queue).inOrder([
  (s) => s.emits((e) => e.equals(1)),
  (s) => s.emits((e) => e.equals(2)),
  (s) => s.emits((e) => e.equals(3)),
]);
```

<!-- chapter:end slug=dart-migrate-to-checks-package -->

---

<!-- chapter:begin slug=dart-resolve-package-conflicts position=7 -->

## 7. dart-resolve-package-conflicts

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-resolve-package-conflicts/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-resolve-package-conflicts/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-resolve-package-conflicts.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-resolve-package-conflicts
description: Workflow for fixing package version conflicts. Use this when `pub get` fails due to incompatible package versions.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 24 Apr 2026 15:11:14 GMT
---
# Managing Dart Dependencies

## Contents
- [Core Concepts](#core-concepts)
- [Version Constraints](#version-constraints)
- [Workflow: Auditing Dependencies](#workflow-auditing-dependencies)
- [Workflow: Upgrading Dependencies](#workflow-upgrading-dependencies)
- [Workflow: Resolving Version Conflicts](#workflow-resolving-version-conflicts)
- [Examples](#examples)

## Core Concepts

Dart enforces a strict single-version rule for dependencies: a project and all its transitive dependencies must resolve to a single, shared version of any given package. This prevents runtime type mismatches but introduces the risk of "version lock."

To mitigate version lock, Dart relies on version constraints rather than pinned versions in the `pubspec.yaml`. The `pubspec.lock` file maintains the exact resolved versions for reproducible builds.

Understand the output columns of `dart pub outdated`:
*   **Current:** The version currently recorded in `pubspec.lock`.
*   **Upgradable:** The latest version allowed by the constraints in `pubspec.yaml`. `dart pub upgrade` resolves to this.
*   **Resolvable:** The absolute latest version that can be resolved when factoring in all other dependencies in the project.
*   **Latest:** The latest published version of the package (excluding prereleases).

## Version Constraints

*   **Use Caret Syntax:** Always use caret syntax (e.g., `^1.2.3`) for dependencies in `pubspec.yaml`. This allows `pub` to select newer, non-breaking versions (up to, but not including, the next major version) during resolution.
*   **Tighten Dev Dependencies:** Set the lower bound of `dev_dependencies` to the exact version currently used. This reduces resolution complexity and prevents older, incompatible dev tools from being selected.
*   **Enforce Lockfiles in CI:** Use `dart pub get --enforce-lockfile` in CI/CD pipelines to ensure the exact versions tested locally are used in production.

## Workflow: Auditing Dependencies

Run this workflow periodically to identify stale packages that may impact stability or performance.

**Task Progress:**
- [ ] Run `dart pub outdated`.
- [ ] Review the **Upgradable** column to identify packages that can be updated without modifying `pubspec.yaml`.
- [ ] Review the **Resolvable** column to identify packages that require constraint modifications in `pubspec.yaml` to update.
- [ ] Identify any packages marked as retracted or discontinued.

## Workflow: Upgrading Dependencies

Use conditional logic based on the audit results to upgrade dependencies.

**Task Progress:**
- [ ] **If updating to "Upgradable" versions:**
  - [ ] Run `dart pub upgrade`.
  - [ ] Run `dart pub upgrade --tighten` to automatically update the lower bounds in `pubspec.yaml` to match the newly resolved versions.
- [ ] **If updating to "Resolvable" versions (Major updates):**
  - [ ] Manually edit `pubspec.yaml` to bump the version constraint to match the "Resolvable" column (e.g., change `^0.11.0` to `^0.12.1`).
  - [ ] Run `dart pub upgrade` to resolve the new constraints and update `pubspec.lock`.
- [ ] **Feedback Loop:**
  - [ ] Run `dart analyze` -> review errors -> fix breaking API changes.
  - [ ] Run `dart test` -> review failures -> fix regressions.

## Workflow: Resolving Version Conflicts

When `pub` cannot find a set of concrete versions that satisfy all constraints, or when dealing with a retracted package version, manipulate the lockfile surgically.

**NEVER** delete the entire `pubspec.lock` file and run `dart pub get`. This causes uncontrolled upgrades across the entire dependency graph.

**Task Progress:**
- [ ] Open `pubspec.lock`.
- [ ] Locate the specific YAML block for the conflicting or retracted package.
- [ ] Delete ONLY that package's entry from the lockfile.
- [ ] Run `dart pub get` to fetch the newest compatible, non-retracted version for that specific package.
- [ ] **Feedback Loop:**
  - [ ] Run `dart pub deps` -> verify the dependency graph resolves correctly.
  - [ ] If resolution fails, identify the transitive dependency causing the lock, update its constraint in `pubspec.yaml`, and retry.

## Examples

### Tightening Constraints
When `dart pub outdated` shows a package is resolvable to a higher minor/patch version, use the `--tighten` flag to update the `pubspec.yaml` automatically.

**Input (`pubspec.yaml`):**
```yaml
dependencies:
  http: ^0.13.0
```

**Command:**
```bash
dart pub upgrade --tighten http
```

**Output (`pubspec.yaml`):**
```yaml
dependencies:
  http: ^0.13.5
```

### Surgical Lockfile Removal
If `package_a` is retracted or locked in a conflict, remove only its block from `pubspec.lock`.

**Before (`pubspec.lock`):**
```yaml
packages:
  package_a:
    dependency: "direct main"
    description:
      name: package_a
      url: "https://pub.dev"
    source: hosted
    version: "1.0.0" # Retracted version
  package_b:
    dependency: "direct main"
    # ...
```

**Action:** Delete the `package_a` block entirely. Leave `package_b` untouched. Run `dart pub get`.

<!-- chapter:end slug=dart-resolve-package-conflicts -->

---

<!-- chapter:begin slug=dart-run-static-analysis position=8 -->

## 8. dart-run-static-analysis

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-run-static-analysis/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-run-static-analysis/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-run-static-analysis.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-run-static-analysis
description: 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.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 24 Apr 2026 15:09:34 GMT
---
# Analyzing and Fixing Dart Code

## Contents
- [Analysis Configuration](#analysis-configuration)
- [Diagnostic Suppression](#diagnostic-suppression)
- [Workflow: Executing Static Analysis](#workflow-executing-static-analysis)
- [Workflow: Applying Automated Fixes](#workflow-applying-automated-fixes)
- [Examples](#examples)

## Analysis Configuration

Configure the Dart analyzer using the `analysis_options.yaml` file located at the package root.

- **Base Configuration:** Always include a standard rule set (e.g., `package:lints/recommended.yaml` or `package:flutter_lints/flutter.yaml`) using the `include:` directive.
- **Strict Type Checks:** Enable strict type checks under the `analyzer: language:` node to prevent implicit downcasts and dynamic inferences. Set `strict-casts: true`, `strict-inference: true`, and `strict-raw-types: true`.
- **Linter Rules:** Explicitly enable or disable specific rules under the `linter: rules:` node. Use a key-value map (`rule_name: true/false`) when overriding included rules, or a list (`- rule_name`) when defining a fresh set. Do not mix list and map syntax in the same `rules` block.
- **Formatter Configuration:** Configure `dart format` behavior under the `formatter:` node. Set `page_width` (default 80) and `trailing_commas` (`automate` or `preserve`).
- **Analyzer Plugins:** Enable custom diagnostics by adding plugins under the `analyzer: plugins:` node. Ensure the plugin package is added as a `dev_dependency` in `pubspec.yaml`.

## Diagnostic Suppression

When a diagnostic (lint or warning) yields a false positive or applies to generated code, suppress it explicitly.

- **File-level Exclusion:** Use the `analyzer: exclude:` node in `analysis_options.yaml` to exclude entire files or directories (e.g., `**/*.g.dart`) using glob patterns.
- **File-level Suppression:** Add `// ignore_for_file: <diagnostic_code>` at the top of a Dart file to suppress specific diagnostics for the entire file. Use `// ignore_for_file: type=lint` to suppress all linter rules.
- **Line-level Suppression:** Add `// ignore: <diagnostic_code>` on the line directly above the offending code, or appended to the end of the offending line.
- **Pubspec Suppression:** Add `# ignore: <diagnostic_code>` above the offending line in `pubspec.yaml` files (e.g., `# ignore: sort_pub_dependencies`).
- **Plugin Diagnostics:** Prefix the diagnostic code with the plugin name when suppressing plugin-specific issues (e.g., `// ignore: some_plugin/some_code`).

## Workflow: Executing Static Analysis

Use this workflow to identify type-related bugs, style violations, and potential runtime errors.

**Task Progress:**
- [ ] 1. Verify `analysis_options.yaml` exists at the project root.
- [ ] 2. Run the analyzer using the `analyze_files` MCP tool (if available) or the CLI command `dart analyze <target_directory>`.
- [ ] 3. Review the diagnostic output.
- [ ] 4. If info-level issues must be treated as failures, append the `--fatal-infos` flag.
- [ ] 5. Resolve reported errors manually or proceed to the Automated Fixes workflow.

## Workflow: Applying Automated Fixes

Use this workflow to resolve outdated API usages, apply quick fixes, and migrate code (e.g., Dart 3 migrations).

**Task Progress:**
- [ ] 1. Execute a dry run to preview proposed changes using the `dart_fix` MCP tool or CLI command `dart fix --dry-run`.
- [ ] 2. Review the proposed fixes to ensure they align with the intended architecture.
- [ ] 3. If additional fixes are required, verify that the corresponding linter rules are enabled in `analysis_options.yaml`.
- [ ] 4. Apply the fixes using the `dart_fix` MCP tool or CLI command `dart fix --apply`.
- [ ] 5. Format the modified code using the `dart_format` MCP tool or CLI command `dart format .`.
- [ ] 6. Run the static analysis workflow to verify all diagnostics are resolved.

## Examples

### Comprehensive `analysis_options.yaml`

```yaml
include: package:flutter_lints/recommended.yaml

analyzer:
  exclude:
    - "**/*.g.dart"
    - "lib/generated/**"
  language:
    strict-casts: true
    strict-inference: true
    strict-raw-types: true
  errors:
    todo: ignore
    invalid_assignment: warning
    missing_return: error

linter:
  rules:
    avoid_shadowing_type_parameters: false
    await_only_futures: true
    use_super_parameters: true

formatter:
  page_width: 100
  trailing_commas: preserve
```

### Inline Diagnostic Suppression

```dart
// Suppress for the entire file
// ignore_for_file: unused_local_variable, dead_code

void processData() {
  // Suppress for a specific line
  // ignore: invalid_assignment
  int x = '';
  
  const y = 10; // ignore: constant_identifier_names
}
```

<!-- chapter:end slug=dart-run-static-analysis -->

---

<!-- chapter:begin slug=dart-setup-ffi-assets position=9 -->

## 9. dart-setup-ffi-assets

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-setup-ffi-assets/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-setup-ffi-assets/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-setup-ffi-assets.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-setup-ffi-assets
description: "Guides agents in compiling and packaging C/C++ source code into dynamic or static libraries (Code Assets) using Dart's Native Assets hook system (via hook/build.dart and hook/link.dart utilizing package:hooks and package:native_toolchain_c). Use when a user asks to: 'setup native assets', 'compile C/C++ source code', 'bundle dynamic libraries', 'build native C code', 'link native assets', 'implement build.dart or link.dart hooks', or 'integrate C/C++ interop in Dart/Flutter'. Helps agents avoid manual toolchain orchestration and configures secure hash-validated binary downloads or advanced linker tree-shaking with package:record_use mapping."
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Fri, 29 May 2026 09:10:00 GMT
---
# Compiling C Code into Code Assets with Native Assets Hooks

Integrate and automate the compilation and packaging of native C/C++ source code into **Code Assets** under Dart's overarching **Native Assets** feature using build and link hooks.

## Contents
- [Introduction](#introduction)
- [Constraints](#constraints)
- [Native Interop Packages](#native-interop-packages)
- [Step-by-Step Workflow](#step-by-step-workflow)
- [Choosing an Integration Approach](#choosing-an-integration-approach)
- [Method 1: Local Compilation with Linker Tree-Shaking (Recommended)](#method-1-local-compilation-with-linker-tree-shaking-recommended)
  - [Prerequisite Host Compiler Toolchains](#prerequisite-host-compiler-toolchains)
  - [C Source and Bindings Setup](#c-source-and-bindings-setup)
  - [Defining the C Library Build Spec](#defining-the-c-library-build-spec)
  - [Implementing hook/build.dart](#implementing-hookbuilddart)
  - [Implementing hook/link.dart](#implementing-hooklinkdart)
- [Method 2: Downloading Precompiled Dynamic Libraries](#method-2-downloading-precompiled-dynamic-libraries)
  - [Why Download Precompiled Binaries?](#why-download-precompiled-binaries)
  - [Implementing Precompiled Dynamic Downloads](#implementing-precompiled-dynamic-downloads)
- [Verification Checklist](#verification-checklist)
  - [1. Local Execution Sandbox](#1-local-execution-sandbox)
  - [2. Verify Target Outputs](#2-verify-target-outputs)
  - [3. Verify Tree-Shaking Stripping](#3-verify-tree-shaking-stripping)
  - [4. Verify Offline Compliance (User Defines)](#4-verify-offline-compliance-user-defines)

---

## Introduction

Under Dart's **Native Assets** feature, packages can package native code (like C/C++ libraries) as **Code Assets** and bundle them automatically during standard development cycles (e.g., `dart run`, `dart test`, `dart build`, and `flutter run`). The packaging of **Code Assets** is driven by two programmatic hook scripts placed inside a package's `hook/` folder:

1.  `hook/build.dart`: Compiles local C sources to machine code or bundles prebuilt native binaries as code assets for a specific host/target architecture.
2.  `hook/link.dart`: Links built code assets, applying advanced tree-shaking optimizations to strip unused native symbols and compress the runtime binary size.

---

## Constraints

> [!IMPORTANT]
> Keep all file resolving platform-independent. Never hardcode absolute target paths, shell scripts, or system command variables. Always use `Platform.script.resolve()` or `Uri`-based resolution to ensure scripts are fully portable.

*   **Hook Locations**: Compiling and packaging hooks must reside strictly inside the `hook/` directory at the package's root:
    *   `hook/build.dart` (Build execution phase)
    *   `hook/link.dart` (Optional packaging/linking/tree-shaking phase)
*   **Compile Toolchain Standard**: Use the programmatic APIs from `package:native_toolchain_c` (e.g. `CBuilder` and `CLibrary`) to run compile toolchains. Never invoke raw `gcc`, `clang`, or `msvc` via shell commands.
*   **Preamble & License Headers**: Every handcrafted and generated source file (including bindings, helpers, and hooks) must strictly contain the target package's copyright and licensing header.
*   **Tree Shaking Mapping**: If utilizing compiler tree-shaking, you must map the target Dart method names (e.g. `Method.name`) back to their raw native C symbol names using a record use mapping generated by FFIgen. The mapping file must reside under `lib/src/third_party/` and strictly use the `.g.dart` extension (e.g., `sqlite3.record_use_mapping.g.dart`).
*   **Integrity Safeguards for Precompiled Libraries**: If adopting the dynamic download pattern:
    *   **Cryptographic Verification**: Downloaded prebuilt binaries must be checked against preconfigured lookup tables containing MD5 or SHA-256 hashes to guarantee binary integrity and prevent tampering.
    *   **Graceful Recovery**: Support offline developers by providing fallbacks (such as local compiler execution via flags like `local_build`).

---

## Native Interop Packages

Programmatic build and link hooks for **Code Assets** leverage three specialized native interop packages:

| Dependency | Purpose | Key API Abstractions |
| :--- | :--- | :--- |
| **`package:hooks`** | Main orchestrator defining execution bounds. | `build(args, callback)`, `link(args, callback)` |
| **`package:native_toolchain_c`** | Detects local compilers (MSVC, Xcode/Clang, GCC) and executes build toolchains. | `CLibrary`, `CBuilder`, `LinkerOptions.treeshake` |
| **`package:code_assets`** | Models code metadata records passed to dynamic loaders. | `CodeAsset`, `DynamicLoadingBundled` |

---

## Step-by-Step Workflow

### Step 1: Add Dependencies
Add Code Assets hook and toolchain dependencies to your package. You must fetch these dependencies directly from **pub.dev**.

You can add it automatically using the CLI:
```bash
dart pub add code_assets hooks native_toolchain_c record_use dev:ffigen
```

Or manually declare them in your target package's `pubspec.yaml`:
```yaml
dependencies:
  code_assets: ^1.0.0
  hooks: ^0.1.0
  native_toolchain_c: ^0.1.0
  record_use: ^0.6.0

dev_dependencies:
  ffigen: ^20.1.1
```

### Step 2: Define C Specifications
Define your target C library compilation metadata inside `lib/src/c_library.dart`. This lets both the build and link hooks share a single source of truth for assets, names, and sources.

### Step 3: Implement Build and Link Hook Scripts
Write the compilation orchestration script inside `hook/build.dart` and the dead-code elimination logic inside `hook/link.dart`.

### Step 4: Run the Hook Cycle
Running standard test suites dynamically launches the build and link hook lifecycle in the background:
```bash
dart test
```

---

## Choosing an Integration Approach

There are two primary methods for integrating and delivering C/C++ native assets in Dart. Select the one that matches your project requirements:

| Aspect | Method 1: Local Compilation & Tree-Shaking | Method 2: Precompiled Downloads |
| :--- | :--- | :--- |
| **Primary Use Case** | When C/C++ source code is included directly in the package and you want maximum size optimization. | When compiling locally is slow/complex, or when avoiding developer host toolchain requirements. |
| **Host Toolchain Requirements** | Requires pre-installed platform C compiler (Xcode tools, MSVC, GCC). | Zero compiler setup required on developer/user machines. |
| **Binary Optimization** | Premium. Unused symbols are completely tree-shaken, decreasing library size. | Standard. Standard compiled binaries are shipped as-is. |
| **Offline Setup** | Fully compliant. Works completely offline. | Requires network access to download libraries, with offline fallback. |

---

## Method 1: Local Compilation with Linker Tree-Shaking (Recommended)

In this approach, the build hook invokes local toolchains (GCC, Clang, MSVC) to compile source files directly. The link hook subsequently filters output symbols utilizing compiler options, retaining only target methods invoked in user code. This represents the standard, robust SQLite pattern under `pkgs/code_assets/example/sqlite`.

### Prerequisite Host Compiler Toolchains

Since `package:native_toolchain_c` delegates actual dynamic compilation to the host operating system's default toolchain, the development machine **must** have one of the following compiler packages pre-installed:

*   **macOS**: Xcode Command Line Tools. Install via:
    ```bash
    xcode-select --install
    ```
*   **Linux**: GCC or Clang. Install via:
    ```bash
    sudo apt install build-essential
    ```
*   **Windows**: MSVC (Microsoft Visual C++). Install the **Visual Studio Installer** and select the **Desktop development with C++** workload.

*Note: If no compatible toolchain is discovered on the host path, the build hook script will throw a compilation execution exception. Ensure to specify compiler constraints or adopt Method 2 if toolchains cannot be guaranteed.*

### C Source and Bindings Setup

Assume a C source defining simple math functions at `third_party/sqlite/sqlite3.c` with its entry point header at `third_party/sqlite/sqlite3.h`:

```c
#ifndef SQLITE3_H_
#define SQLITE3_H_

const char *sqlite3_libversion(void);

#endif // SQLITE3_H_
```

We utilize a programmatic FFIgen script (`tool/ffigen.dart`) to create FFI bindings in `lib/src/third_party/sqlite3.g.dart`, enabling recorded usage tracking and producing the lookup metadata map in `lib/src/third_party/sqlite3.record_use_mapping.g.dart`:

```dart
// AUTO-GENERATED FILE - DO NOT MODIFY.
// Generated via ffigen.

const recordUseMapping = {
  'sqlite3_libversion': 'sqlite3_libversion',
};
```

### Defining the C Library Build Spec

Define the centralized library specification in `lib/src/c_library.dart`:

```dart
import 'package:native_toolchain_c/native_toolchain_c.dart';

/// The C build specification for the sqlite library.
final cLibrary = CLibrary(
  name: 'sqlite3',
  assetName: 'src/third_party/sqlite3.g.dart',
  sources: ['third_party/sqlite/sqlite3.c'],
);
```

### Implementing `hook/build.dart`

Implement `hook/build.dart` using `CLibrary.build`. This builds the library to a dynamic library (e.g. `.so`, `.dylib`, or `.dll`) inside the hook's target directory:

```dart
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:sqlite/src/c_library.dart';

void main(List<String> args) async {
  await build(args, (input, output) async {
    if (input.config.buildCodeAssets) {
      await cLibrary.build(
        input: input,
        output: output,
        defines: {
          if (input.config.code.targetOS == OS.windows)
            // Ensure C functions are explicitly exported in the Windows DLL
            'SQLITE_API': '__declspec(dllexport)',
        },
      );
    }
  });
}
```

### Implementing `hook/link.dart`

Implement the link optimization phase in `hook/link.dart`. This utilizes compiler tree-shaking options (`LinkerOptions.treeshake`) to compile a minimized, dead-code-eliminated binary based on symbol usage records:

```dart
import 'package:hooks/hooks.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:record_use/record_use.dart';
import 'package:sqlite/src/c_library.dart';
import 'package:sqlite/src/third_party/sqlite3.record_use_mapping.g.dart';

void main(List<String> arguments) async {
  await link(arguments, (input, output) async {
    await cLibrary.link(
      input: input,
      output: output,
      linkerOptions: LinkerOptions.treeshake(
        // Map Dart Method references back to raw C symbol names
        symbolsToKeep: input.recordedUses?.calls.keys.cast<Method>().map(
          (e) => recordUseMapping[e.name]!,
        ),
      ),
    );
  });
}
```

---

## Method 2: Downloading Precompiled Dynamic Libraries

An alternative approach compiles binaries beforehand on a central build machine, archives them, and downloads the target binary during the build hook execution. This matches the paradigm demonstrated in the `download_asset` hook package.

### Why Download Precompiled Binaries?

*   **Host Constraints**: Compiling large C/C++ libraries locally requires a complete compiler setup (GCC, Xcode/SDKs, Visual Studio) that the end-developer's host machine may not possess.
*   **Compile Speed**: Precompiled downloads execute in milliseconds compared to potentially long multi-minute compilation processes.
*   **Platform Bridging**: Allows cross-compiling constraints to be avoided if host architectures are limited.

---

### Implementing Precompiled Dynamic Downloads

We configure our build hook to detect local compiler flags (e.g. `local_build`). If not specified, the hook utilizes `HttpClient` to pull down platform-specific libraries, calculates the MD5 hash to confirm download safety against a configured hashes lookup table, and registers the binary file as a `CodeAsset`:

#### 1. Defining Target Hashes (`lib/src/hook_helpers/hashes.dart`)
Define target MD5 hash checks per platform file in your package sources:

```dart
const assetHashes = {
  'libnative_add_macos_arm64.dylib': '4a88f50438a98402db2dbd47b59eb412',
  'libnative_add_linux_x64.so': '9f5e15043aa98402dcdbbd47b59ea520',
  'native_add_windows_x64.dll': 'a881e5043ba98402acdebd47b59fa321',
};
```

#### 2. Hook Downloader Helper (`lib/src/hook_helpers/download.dart`)
Implement the downloading and integrity check logic using dynamic target filename matching:

```dart
import 'dart:io';
import 'package:code_assets/code_assets.dart';
import 'package:crypto/crypto.dart';

const version = '1.0.0';

Uri downloadUri(String target) => Uri.parse(
  'https://github.com/my-org/my-native-repo/releases/download/$version/$target',
);

Future<File> downloadAsset(
  OS targetOS,
  Architecture targetArchitecture,
  Directory outputDir,
) async {
  final fileName = targetOS.dylibFileName('native_add_${targetOS.name}_${targetArchitecture.name}');
  final uri = downloadUri(fileName);
  
  final client = HttpClient()..findProxy = HttpClient.findProxyFromEnvironment;
  final request = await client.getUrl(uri);
  final response = await request.close();
  
  if (response.statusCode != 200) {
    throw ArgumentError('Download target $uri failed: Code ${response.statusCode}');
  }
  
  final targetFile = File.fromUri(outputDir.uri.resolve(fileName));
  await targetFile.create(recursive: true);
  await response.pipe(targetFile.openWrite());
  
  return targetFile;
}

Future<String> hashAsset(File file) async {
  return md5.convert(await file.readAsBytes()).toString();
}
```

#### 3. Implementing `hook/build.dart`

Write the final download build hook incorporating local compilation fallback:

```dart
import 'dart:io';
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:my_download_package/src/hook_helpers/hashes.dart';
import 'package:my_download_package/src/hook_helpers/download.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';

void main(List<String> args) async {
  await build(args, (input, output) async {
    final localBuild = input.userDefines['local_build'] as bool? ?? false;

    if (localBuild) {
      final name = 'native_add_${input.config.code.targetOS.name}_${input.config.code.targetArchitecture.name}';
      final builder = CBuilder.library(
        name: name,
        assetName: 'native_add.dart',
        sources: ['src/native_add.c'],
      );
      await builder.run(input: input, output: output);
    } else {
      final targetOS = input.config.code.targetOS;
      final targetArch = input.config.code.targetArchitecture;
      final outputDir = Directory.fromUri(input.outputDirectory);

      final file = await downloadAsset(targetOS, targetArch, outputDir);

      final fileHash = await hashAsset(file);
      final expectedFileName = targetOS.dylibFileName('native_add_${targetOS.name}_${targetArch.name}');
      final expectedHash = assetHashes[expectedFileName];

      if (fileHash != expectedHash) {
        throw Exception(
          'Security Mismatch: File $expectedFileName hash verification failed! '
          'Found hash: $fileHash, expected: $expectedHash.'
        );
      }

      output.assets.code.add(
        CodeAsset(
          package: input.packageName,
          name: 'native_add.dart',
          linkMode: DynamicLoadingBundled(),
          file: file.uri,
        ),
      );
    }
  });
}
```

---

## Verification Checklist

Before declaring a build or link hook implementation complete, always perform the following checks:

### 1. Local Execution Sandbox
Run unit tests and confirm the native assets compile/link process completes with no runtime or build tool exceptions:
```bash
dart test
```

### 2. Verify Target Outputs
Navigate to your package target directory and verify that dynamic binary assets are created for the host system:
*   **macOS**: Verify `.dart_tool/resources/` or target directories contain `.dylib` files.
*   **Linux**: Verify `.dart_tool/resources/` or target directories contain `.so` files.
*   **Windows**: Verify `.dart_tool/resources/` or target directories contain `.dll` files.

### 3. Verify Tree-Shaking Stripping
To ensure the link hook is actually stripping unused native symbols and compressing binary packaging, perform the following validation:

1. Compile a production bundle of the CLI/app:
   ```bash
   dart build cli bin/main.dart
   ```
2. Navigate to the compiled build directory containing the dynamic library.
3. Query the exported dynamic symbol tables:
   *   **macOS**:
       ```bash
       nm -gU build/cli/lib/libsqlite3.dylib
       ```
   *   **Linux**:
       ```bash
       nm -D build/cli/lib/libsqlite3.so
       ```
   *   **Windows** (using MSVC Developer Command Prompt):
       ```cmd
       dumpbin /EXPORTS build\cli\lib\sqlite3.dll
       ```
4. **Confirm Target Exports**: Verify that the command outputs **only** the explicitly kept entry point functions (e.g. `sqlite3_libversion`) and does not output any unreferenced/stripped symbols.
5. **No Bundle Scenario**: If the application does not import or invoke any methods from the native library:
   - Verify that the link hook logs: `Skipping linking as no symbols are to be kept.`
   - Verify that no library was built/placed in the production bundle (the `.dylib`/`.so`/`.dll` file is not generated, saving bundle size).

### 4. Verify Offline Compliance (User Defines)
Confirm offline compliance is fully active and the download fallback executes perfectly offline:

1. Configure the `local_build: true` define for your package in the package's `pubspec.yaml` (or the workspace root `pubspec.yaml`):
   ```yaml
   hooks:
     user_defines:
       <your_package_name>:
         local_build: true
   ```
2. Disable the machine's network adapter or run in a sandboxed offline shell.
3. Launch unit tests:
   ```bash
   dart test
   ```
4. Verify the test suite successfully compiles local source files using host compilers, has no compile errors, and never attempts network download requests.

<!-- chapter:end slug=dart-setup-ffi-assets -->

---

<!-- chapter:begin slug=dart-use-doc-examples position=10 -->

## 10. dart-use-doc-examples

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-use-doc-examples/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-doc-examples/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-use-doc-examples.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-use-doc-examples
description: "How to inject external code examples into Dartdoc using the {@example} directive, and how to filter those files using #hide, #region, and #endregion tags."
---

# Using Examples in Dartdoc

## Contents
*   [1. The `{@example}` Directive](#1-the-example-directive)
*   [2. Using Regions](#2-using-regions)
*   [3. Hiding Setup Code](#3-hiding-setup-code)
*   [4. Marker Filtering Rules](#4-marker-filtering-rules)
*   [5. Placement and Path Resolution](#5-placement-and-path-resolution)
*   [6. Verification](#6-verification)

When writing documentation that requires multi-line code examples, you should generally extract those examples into standalone `.dart` files and inject them using the `{@example}` directive, rather than writing them inline inside `///` comments. This ensures the examples can be analyzed, linted, and executed.

## 1. The `{@example}` Directive
The `{@example}` directive parses an external file and resolves it into a fenced Markdown code block in the generated documentation.

**Syntax:** `{@example <path>[#<region>] [lang=LANGUAGE] [indent=keep|strip]}`

*   **`<path>`**: The path to the file. A leading `/` evaluates from the package root. Otherwise, it is relative to the current file.
*   **`lang`**: The language for the markdown fence. Auto-detected from the file extension (e.g., `dart`), but can be explicit (e.g., `lang=text`).
*   **`indent`**: `strip` (default) aggressively removes shared leading indentation from the code block.

*Bad (Inline Markdown):*
```dart
/// Makes a client service request to the backend.
///
/// ```dart
/// final client = Client();
/// client.send();
/// ```
```

*Good (External File Injection):*
```dart
/// Makes a client service request to the backend.
///
/// {@example /example/client_request.dart}
```

## 2. Using Regions
Often, an external example file contains imports, setup, or `void main()` wrappers that you don't want to show in the documentation. You can extract a specific block of code by appending `#<region>` to the `{@example}` directive path, and wrapping that code with `#region` and `#endregion` comments in the target file.

**Dart Code (e.g., `/example/client.dart`):**
```dart
import 'package:http/http.dart';

void main() {
  // #region request_snippet
  final client = Client();
  client.send();
  // #endregion request_snippet
}
```

**Dartdoc Usage:**
```dart
/// Connects the client to the server and sends a request.
///
/// {@example /example/client.dart#request_snippet}
```

## 3. Hiding Setup Code
If there is a specific line of code within your extracted region that is necessary for the compiler/analyzer to pass but irrelevant (or distracting) for the documentation reader, append `#hide` to that line.

**Dart Code:**
```dart
final mockServer = startServer(); // #hide
final data = await fetch(mockServer.url);
```
In the generated documentation, only `final data = await fetch(mockServer.url);` will be visible. The line with `#hide` is completely dropped.

## 4. Marker Filtering Rules
When working with `#hide`, `#region`, and `#endregion` markers, you must follow these two technical constraints:

*   **Region Required:** The markers are only processed and stripped when you target a specific region suffix (e.g., `{@example file.dart#region_name}`). If you inject an entire file without a region suffix, the file is embedded exactly as it appears in the source, including any marker text like `// #hide`.
*   **Format Agnosticism:** The marker system is completely format-agnostic. Dartdoc simply runs a regex to strip lines containing the marker strings, meaning it works identically in non-Dart files (e.g., inside YAML comments `# #region` or HTML comments `<!-- #region -->`).

## 5. Placement and Path Resolution
The `{@example}` directive is a block-level directive. It must appear on its own line prefixed with `///`. Its internal `<path>` parser follows strict URI reference rules:

*   **Package-Root Paths (`/`)**: Paths starting with a leading slash automatically resolve directly to the root of the Dart package. Use this when the destination file is deep.
    *   *Example:* `{@example /test/data/sample.txt}` exactly maps to `<package_root>/test/data/sample.txt`.
*   **Relative Paths**: Paths without a leading slash resolve relative to the directory of the file containing the doc comment.
    *   *Example:* `{@example ../utils/demo.dart}`
*   **Boundary Enforcement:** Using `..` segments to traverse upward is perfectly acceptable, but dartdoc natively stops directory traversal at the package root (it will never escape the package).
*   **No Network URLs:** Absolute URIs (e.g., starting with `https://`) are strictly not supported. The example file *must* sit natively somewhere in the local filesystem.
*   **Separators & Encoding:** Because dartdoc resolves the path as a URI, you must always use forward slashes (`/`) as folder separators (even on Windows). You can natively include URI-encoded characters (like `%20` for spaces) as permitted by URI reference rules.

## 6. Verification
After injecting examples:
1.  Run `dart analyze` on the example files to ensure the hidden setup code compiles.
2.  (Optional) Run `dart doc` to verify that dartdoc successfully parsed the directive without throwing a "Failed to read file" or "missing region" warning.

<!-- chapter:end slug=dart-use-doc-examples -->

---

<!-- chapter:begin slug=dart-use-ffigen position=11 -->

## 11. dart-use-ffigen

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-use-ffigen/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-ffigen/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-use-ffigen.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-use-ffigen
description: 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/Objective-C/Swift integrations, or replacing hand-crafted `dart:ffi` setups.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Thu, 28 May 2026 07:21:07 GMT
---
# Generating FFI Bindings using package:ffigen

## Contents
- [Introduction](#introduction)
- [Constraints](#constraints)
- [FFIgen Overview](#ffigen-overview)
- [Step-by-Step Workflow](#step-by-step-workflow)
- [Concrete Example: Binding a C Library](#concrete-example-binding-a-c-library)
- [Verification Checklist](#verification-checklist)

## Introduction

Automate and standardize the generation of FFI bindings using `package:ffigen` (`FfiGenerator`). Writing FFI bindings by hand is error-prone, brittle, and highly discouraged.

## Constraints

*   **No Hand-Written FFI Bindings**: If native headers (`.h` files) exist or are generated by a build step, never write manual `DynamicLibrary.lookup`, `@Native` external functions, or raw struct classes. Always use `FfiGenerator` to generate them.
*   **Generator Location**: The generator script should be located at `tool/ffigen.dart` within the target package root.
*   **Header Location**: If the native header files are third-party, they should be located in `third_party/` within the target package (otherwise placing them in a `src/` directory at the package root is also acceptable). If the headers are not in one of these standard locations, notify the user that it would be cleaner to move the header files to the standard location (e.g., `third_party/`).
*   **Targeted Inclusion Filters**: Avoid importing an entire native library unless specifically needed. Always apply precise inclusion lists using positive matches to minimize the size and cognitive load of the generated code (e.g., using `Functions.includeSet` or filtering matches in `include` closures).
*   **Output Setup**: If the generated FFI bindings interface with a third-party library (or reference third-party headers), the generated files must always be placed under `lib/src/third_party/`. The primary generated FFI bindings file must strictly use the `.g.dart` extension (e.g. `sqlite3.g.dart`).
*   **Preamble & License Headers**: Always supply a premium `preamble` in the `Output` class to specify the license. This must match the native third-party library's license, explicitly include the copyright header of the target native header file, and contain an automatic generation warning (e.g. `// Generated by package:ffigen. Do not edit manually.`).
*   **No Unnecessary Commits of Stale Bindings**: Ensure you run the generator script and check if the generated files have changed *before* finishing your task. Always verify the package by running `dart analyze`.
*   **Record Usage and Tree Shaking**: If the package is integrated into standard runtime execution or compiles native assets via native hooks:
    *   Enable recorded usage on all functions by setting `recordUse: (_) => true` under `Functions`.
    *   Specify the `recordUseMapping` target in `Output` (which must strictly be a `.g.dart` file under `lib/src/third_party/`, e.g. `lib/src/third_party/sqlite3.record_use_mapping.g.dart`) to register bindings for symbol tree shaking.

## FFIgen Overview

To construct the programmatic generator, use the core configuration objects imported from `package:ffigen/ffigen.dart`:

### 1. `FfiGenerator`
The parent class that orchestrates the configuration, parsing, and code generation.
```dart
FfiGenerator({
  Headers headers = const Headers(),
  Enums enums = Enums.excludeAll,
  Functions functions = Functions.excludeAll,
  Globals globals = Globals.excludeAll,
  Integers integers = const Integers(),
  Macros macros = Macros.excludeAll,
  Structs structs = Structs.excludeAll,
  Typedefs typedefs = Typedefs.excludeAll,
  Unions unions = Unions.excludeAll,
  UnnamedEnums unnamedEnums = UnnamedEnums.excludeAll,
  ObjectiveC? objectiveC,
  required Output output,
}).generate();
```

### 2. `Headers`
Configures Clang header parsing targets and compiler flags.
*   `entryPoints`: A list of target header `Uri` inputs.
*   `include`: A filter function `bool Function(Uri header)` that handles transitive header imports.
*   `compilerOptions`: Custom preprocessor/include compiler flags to pass directly to libclang.
*   `ignoreSourceErrors`: Set to `true` to silence errors occurring inside third-party headers during parsing.

### 3. `Functions`
Specifies which native C/C++ functions to expose in Dart.
*   `include`: A matcher function (e.g. `(decl) => {'my_func'}.contains(decl.originalName)` or `Functions.includeSet({'my_func'})`).
*   `isLeaf`: Declares functions as leaf functions (`(decl) => true`) if they do not call back into Dart or block thread execution.
*   `recordUse`: Enables metadata generation for native asset tree shaking (essential in `dart-lang/native`). Set to `(_) => true`.

### 4. `Output`
Configures target generated files.
*   `dartFile`: Target `Uri` where the primary FFI bindings will be written.
*   `recordUseMapping`: Target `Uri` for recorded usage metadata maps (crucial for linking-time tree shaking).
*   `preamble`: Text inserted at the top of the generated file (licensing, annotations).
*   `format`: Set to `true` to run the Dart formatter automatically.

## Step-by-Step Workflow

### Step 1: Check/Add Dependencies
Open the package's `pubspec.yaml` and verify the `dev_dependencies` contains `ffigen`. Use the Dart MCP server or look up the latest version on [pub.dev](https://pub.dev/packages/ffigen) (e.g., `^20.1.1`).

You can add it automatically using the CLI:
```bash
dart pub add dev:ffigen
```

### Step 2: Formulate Paths Dynamically
Create a programmatic generator script under the package's `tool/` directory (e.g., `tool/ffigen.dart`).
Resolve paths relative to `Platform.script` to make sure it runs successfully from any working directory:

```dart
final packageRoot = Platform.script.resolve('../');
final headerFile = packageRoot.resolve('third_party/library.h');
final targetBindings = packageRoot.resolve('lib/src/third_party/bindings.g.dart');
```

### Step 3: Write the Script (`tool/ffigen.dart`)
Define `void main()` and run `FfiGenerator` with dynamic options (see complete example below).

### Step 4: Run Code Generation
Execute the script from the terminal inside the target package folder:
```bash
dart run tool/ffigen.dart
```

### Step 5: Static Analysis
Verify that the generated bindings are correct and resolve any analysis issues. FFIgen automatically runs the Dart formatter on the output file (via `format: true` configuration), so manual formatting is not required.

1.  Run the static analyzer inside the target package:
    ```bash
    dart analyze
    ```
2.  **Addressing Warnings/Lints**: If `dart analyze` reports style or lint warnings inside the generated file, append the corresponding warning codes to the `ignore_for_file:` list in your generator script's `preamble` configuration (e.g., adding `camel_case_types`, `non_constant_identifier_names`, etc.). Do not modify the package's global rules.
3.  **Addressing Compilation Errors**: If `dart analyze` reports actual compiler or analysis errors (not warnings) inside the generated file, do not attempt to edit the generated file manually. Report these error details directly to the user so they can file an issue on the repository at [github.com/dart-lang/native](https://github.com/dart-lang/native).


## Concrete Example: Binding a C Library

Let's assume we are working with the SQLite package under `pkgs/code_assets/example/sqlite`, which embeds SQLite C library sources inside `third_party/sqlite/` and accesses it via FFI.

### The C Header File (`third_party/sqlite/sqlite3.h`)
```c
// The author disclaims copyright to this source code.

#ifndef SQLITE3_H_
#define SQLITE3_H_

const char *sqlite3_libversion(void);

#endif // SQLITE3_H_
```

### BEFORE: Manual FFI Binding (The Anti-Pattern)
A developer might attempt to handcraft this integration. It is fragile, blocks tree-shaking metadata, and is highly prone to ABI and structural mapping issues:

```dart
// lib/src/sqlite3_manual.dart
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';

// Flaw 1: Hardcoded DynamicLibrary lookup blocks integration with modern native asset compilation.
final ffi.DynamicLibrary _dylib = ffi.DynamicLibrary.open('libsqlite3.so');

// Flaw 2: Manual function type matching requires writing redundant dynamic lookup boilerplate and lacks tree-shaking metadata.
typedef _sqlite3_libversion_C = ffi.Pointer<ffi.Char> Function();
typedef _sqlite3_libversion_Dart = ffi.Pointer<ffi.Char> Function();

final _sqlite3_libversion_Dart sqlite3LibVersion = _dylib
    .lookup<ffi.NativeFunction<_sqlite3_libversion_C>>('sqlite3_libversion')
    .asFunction();
```

### AFTER: Generating via FFIgen (The Correct Pattern)

Create a programmatic script at `tool/ffigen.dart`:

```dart
// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';
import 'package:ffigen/ffigen.dart';

void main() {
  // Resolve paths dynamically relative to Platform.script
  final packageRoot = Platform.script.resolve('../');
  final entryHeader = packageRoot.resolve('third_party/sqlite/sqlite3.h');
  final bindingsOutput = packageRoot.resolve('lib/src/third_party/sqlite3.g.dart');
  final treeShakeMapping = packageRoot.resolve('lib/src/third_party/sqlite3.record_use_mapping.g.dart');

  FfiGenerator(
    headers: Headers(
      entryPoints: [entryHeader],
    ),
    functions: Functions(
      include: (decl) => {'sqlite3_libversion'}.contains(decl.originalName),
      // Essential for package optimization and tree-shaking
      recordUse: (_) => true,
    ),
    output: Output(
      dartFile: bindingsOutput,
      recordUseMapping: treeShakeMapping,
      format: true,
      preamble: '''

// AUTO-GENERATED FILE - DO NOT MODIFY.
// Generated via ffigen.
// To regenerate: dart run tool/ffigen.dart

// ignore_for_file: type=lint, unused_import, unused_element, deprecated_member_use_from_same_package, experimental_member_use
''',
    ),
  ).generate();

  print('Successfully generated sqlite3 FFI bindings.');
}
```

### Running the Generator script
Run this in the package root directory:
```bash
dart run tool/ffigen.dart
```

This will automatically create:
1.  `lib/src/third_party/sqlite3.g.dart`
2.  `lib/src/third_party/sqlite3.record_use_mapping.g.dart`

## Verification Checklist

Always perform the following verification before completing a binding generation task:

1.  **Correct Setup**: Verify the target generated files are inside `lib/src/third_party/` (required for third-party licensed code) and the primary FFI bindings file strictly uses the `.g.dart` extension.
2.  **Static Analysis**: Run `dart analyze` and ensure there are zero compiler/analyzer errors or warnings in the package.
    *   If static warnings are reported in the generated bindings, suppress them by adding `ignore_for_file` rules to the generator's `preamble` configuration (do not modify global package rules).
    *   If actual compiler or analyzer errors are reported in the generated bindings, do not edit the generated file manually. Report the details to the user and direct them to file an issue at [github.com/dart-lang/native](https://github.com/dart-lang/native).

<!-- chapter:end slug=dart-use-ffigen -->

---

<!-- chapter:begin slug=dart-use-path-package position=12 -->

## 12. dart-use-path-package

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-use-path-package/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-path-package/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-use-path-package.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (2), referenced from this skill's directory:
  - `examples/cross_platform_paths.dart` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-path-package/examples/cross_platform_paths.dart
  - `examples/file_system_context.dart` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-path-package/examples/file_system_context.dart

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-use-path-package
description: >-
  Cross-platform file and directory path manipulation, segment splitting, extension extraction, and context conversion using `package:path` and `package:file`. Use when writing, inspecting, joining, splitting, or refactoring file paths, directory names, or extensions, or replacing raw string path operations (`.split('/')`, `'$dir/$file'`, `.endsWith('.ext')`, `.replaceAll('\\', '/')`). Don't use for HTTP network URI routing, database query strings, or non-path string processing.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Sun, 06 Sep 2026 07:14:00 GMT
---

# Safe Cross-Platform Path Manipulation in Dart

## Contents
* [1. Core Principles & Cross-Platform Rules](#1-core-principles--cross-platform-rules)
* [2. Recommended package:path Idioms vs. String Anti-Patterns](#2-recommended-packagepath-idioms-vs-string-anti-patterns)
* [3. Bridging Native Paths to POSIX, Git, & URL Contexts](#3-bridging-native-paths-to-posix-git--url-contexts)
* [4. Mockable File Systems (`package:file` vs. Global `p.*`)](#4-mockable-file-systems-packagefile-vs-global-p)
* [5. Extensions, Compound Extensions & Stem Extraction](#5-extensions-compound-extensions--stem-extraction)
* [6. Workflows & Audit Checklist](#6-workflows--audit-checklist)
* [References & Examples](#references--examples)

---

## 1. Core Principles & Cross-Platform Rules

### Avoid Treating File Paths as Raw Strings
* Native file paths on Windows use backslashes (`\`), whereas macOS and Linux use forward slashes (`/`).
* String operations like `.contains('foo/')`, `.startsWith('foo/')`, or `.split('/')` silently fail on Windows native paths.
* String interpolation like `'$dir/$file'` injects forward slashes on Windows and produces duplicate slashes (`//`) when `$dir` ends with a trailing slash.

**Rule**: Always decompose paths into segments using `p.split(path)` before inspecting directory hierarchy or segment names, and always join path components using `p.join(...)`.

### Pragmatic Boundary Joining vs. Multi-Segment Decomposition (`p.join`)
* **Cross-Platform Libraries (Windows + POSIX)**: Pass individual path segments to `p.join(dir, 'sub', 'file.json')` so `package:path` inserts OS-native separators (`\` on Windows, `/` on POSIX) between every component.
* **POSIX-Only Tools & Static Subpath Greppability**: In codebases exclusively targeting Linux/macOS (or when joining a dynamic base path to a known static subpath), decomposing 5–6 static segments into separate arguments (`p.join(home, '.local', 'share', 'app', 'bin', 'config.json')`) causes `dart format` to wrap across 6–8 vertical lines and **destroys substring greppability** (`grep` / `code_search` for `.local/share/app/bin`).
* **Rule for POSIX Targets**: Prefer **2-argument boundary joining** (`p.join(home, '.local/share/app/bin/config.json')`). This prevents duplicate-slash bugs (`//`) at variable boundaries while preserving single-line readability and exact string searchability.

### Normalization vs. Canonicalization (`p.normalize` vs. `p.canonicalize`)
* `p.normalize(path)` resolves `.` and `..` segments purely lexically without consulting the filesystem or standardizing case.
* When deduplicating directory paths or comparing physical file identity across symlinks, relative roots, or case-insensitive filesystems, use `p.canonicalize(path)`.

### Strip Location Specifiers & Convert URIs Safely
* Strings formatted as `<path>:<line>-<col>` or `<path>:<line>` are not pure file paths. Passing them directly to `p.normalize` or `Uri.parse` causes bugs (on Windows, `Uri.parse` mistakes `C:` for a URI scheme and `:line` for a port).
* Extract the trailing `:line-col` suffix via regular expression (`RegExp(r'^(.*?):(\d+(?:-\d+)?)$')`) *before* passing the file path to `package:path`.
* **URI Boundary Conversions**: When converting between file paths and `Uri` objects, always use `p.toUri(path)` and `p.fromUri(uri)` rather than `Uri.parse(path)` or manual string concatenation.

---

## 2. Recommended package:path Idioms vs. String Anti-Patterns

### Path Joining
* **Prefer**: `p.join(dir, file)`
* **Avoid**: `'$dir/$file'` or `'a/$b'`
* **Why**: String interpolation injects `/` on Windows and creates duplicate
  slashes (`//`) when `$dir` ends with a trailing separator.

### Segment Matching
* **Prefer**: `p.split(path).contains('foo')`
* **Avoid**: `path.contains('foo/')`
* **Why**: String matching fails on Windows backslashes (`foo\bar`) and produces
  false positives on partial substring names (e.g. `barfoo/`).

### Root and Directory Prefixes
* **Prefer**: `p.split(path).first == 'foo'` or `p.isWithin('foo', path)`
* **Avoid**: `path.startsWith('foo/')`
* **Why**: Fails on Windows separators and misses relative prefix variants such
  as `./foo/`.

### File Extensions
* **Prefer**: `p.extension(path) == '.wasm'`
* **Avoid**: `path.endsWith('.wasm')`
* **Why**: Substring suffix matching falsely matches directories (`foo.wasm/`)
  or non-extension suffixes.

### Extension Slicing and Compound Extensions
* **Prefer**: `p.withoutExtension(path)` and `p.extension(path, 2)`
* **Avoid**: `path.lastIndexOf('.')` and manual `substring` slicing
* **Why**: Manual arithmetic breaks on hidden dotfiles (`.gitignore`) and
  compound extensions (`.js.map`, `.tar.gz`).

### POSIX and URL Path Conversion
* **Prefer**: `p.posix.joinAll(p.split(path))` or `p.url.joinAll(p.split(path))`
* **Avoid**: `path.replaceAll(r'\', '/')`
* **Why**: Ad-hoc separator replacement fails on root drives and mixes OS
  context with POSIX or URL targets.

### URI Conversion
* **Prefer**: `p.toUri(path)` and `p.fromUri(uri)`
* **Avoid**: `Uri.parse(path)` and `uri.path`
* **Why**: Direct URI parsing fails on Windows drive letters (`C:`) and leaks
  percent-encoding (e.g. `%20` for spaces).

### Directory Basename Helper
* **Prefer**:
  `String canonicalDirName(Directory d) => p.basename(p.normalize(d.absolute.path));`
* **Avoid**: Repeating `p.basename(p.normalize(dir.absolute.path))` inline
  across files.
* **Why**: Centralizes canonical directory naming logic and reduces boilerplate.

---

## 3. Bridging Native Paths to POSIX, Git, & URL Contexts

Avoid calling `.replaceAll('\\', '/')` or `.replaceAll(r'\', '/')` to convert
OS-native paths into POSIX paths (for Git, YAML, archive manifests) or URL
segments.

**Rule**: Split the relative native path using `p.split(...)`, inspect segments
with **Dart 3 list pattern matching**, and join using `p.posix.joinAll(...)` or
`p.url.joinAll(...)`. Always call `p.relative(filePath, from: root)` first so
leading root segments (`'/'` on POSIX or `r'C:\'` on Windows) do not interfere
with relative prefix patterns:

```dart
import 'package:path/path.dart' as p;

String computeWebAssetKey(String filePath, String projectRoot) {
  final relative = p.relative(filePath, from: projectRoot);
  final segments = p.split(relative);
  return switch (segments) {
    ['assets', ...] => p.posix.joinAll(segments),
    _ => p.posix.joinAll(['assets', ...segments]),
  };
}
```

### Git Paths and Repository Metadata
* Git repository tree objects, `.gitignore` pattern rules, `.gitattributes`,
  and git-tracked symlinks strictly use POSIX forward slashes (`/`), even on
  Windows.
* Inserting native Windows backslashes (`\`) into `.gitignore` or git commands
  causes Git to treat `\` as an escape character rather than a directory
  separator, silently breaking pattern matching.
* When generating `.gitignore` entries, repository manifests, or symlink
  targets programmatically from native file paths, convert the relative native
  path using `p.posix.joinAll(p.split(relativePath))` or `p.posix.join(...)`.

---

## 4. Mockable File Systems (`package:file` vs. Global `p.*`)

In codebases that use `package:file` (e.g., CLI applications or services tested
with `MemoryFileSystem`), avoid calling top-level `p.*` functions on `File` or
`Directory` paths.

* Top-level `p.*` functions bind to the *host operating system* running the test.
* If a unit test creates a `MemoryFileSystem(style: FileSystemStyle.windows)` on a Linux or macOS runner, global `p.split(file.path)` will split on `/` instead of `\`, breaking the test.

**Rule**: Always use the `Context` attached to the `FileSystem` (`file.fileSystem.path`):

```dart
import 'package:file/file.dart';

List<String> listSubdirectoryNames(Directory dir) {
  final pathContext = dir.fileSystem.path;
  return dir
      .listSync()
      .whereType<Directory>()
      .map((d) => pathContext.basename(d.path))
      .toList();
}
```

---

## 5. Extensions, Compound Extensions & Stem Extraction

Avoid manual `.lastIndexOf('.')` and `.substring()` arithmetic when extracting file extensions or inserting content hashes. `p.extension` natively supports multi-level extensions via its optional `level` parameter.

* **Multi-Dot Stem Nuance**: Calling `p.extension('main.dart.wasm', 2)` returns `'.dart.wasm'` because it blindly captures the last two dot-separated segments. When hashing or stripping extensions on files that may have multi-dot stems (e.g., `main.dart.wasm` vs. `main.dart.js.map`), check whether `p.extension(filename, 2)` matches a known compound extension (or `.endsWith('.map')`) before falling back to single-level `p.extension(filename)`:

```dart
import 'package:path/path.dart' as p;

String insertContentHash(String filename, String hash) {
  final compoundExt = p.extension(filename, 2);
  // Only use the 2-level extension for true compound suffixes (e.g., '.js.map')
  final ext = compoundExt.endsWith('.map')
      ? compoundExt
      : p.extension(filename);
  final stem = filename.substring(0, filename.length - ext.length);
  return '$stem.$hash$ext';
}
```

---

## 6. Workflows & Audit Checklist

### Path Refactoring Checklist
- [ ] Replace string interpolation (`'$dir/$file'`) with `p.join(dir, file)`.
- [ ] Replace `.contains('dir/')` and `.startsWith('dir/')` with `p.split(path)` segment checks or `p.isWithin(parent, child)`.
- [ ] Replace `.replaceAll(r'\', '/')` with `p.posix.joinAll(p.split(path))` (or `p.url.joinAll`).
- [ ] Replace `.endsWith('.ext')` on file paths with `p.extension(path) == '.ext'`.
- [ ] Replace manual dot-index slicing with `p.withoutExtension(path)` and `p.extension(path, [level])`.
- [ ] Verify that code using `package:file` accesses `fileSystem.path` instead of global `p.*`.
- [ ] Ensure Git paths, `.gitignore` entries, and symlink targets use `p.posix` forward slashes.

---

## References & Examples

* **Cross-Platform Path & POSIX Conversion Examples**: [examples/cross_platform_paths.dart](examples/cross_platform_paths.dart)
* **Mockable FileSystem Path Context Example**: [examples/file_system_context.dart](examples/file_system_context.dart)

<!-- chapter:end slug=dart-use-path-package -->

---

<!-- chapter:begin slug=dart-use-pattern-matching position=13 -->

## 13. dart-use-pattern-matching

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-use-pattern-matching/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-pattern-matching/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-use-pattern-matching.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (1), referenced from this skill's directory:
  - `examples/json_patterns.dart` — https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-pattern-matching/examples/json_patterns.dart

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-use-pattern-matching
description: >-
  Applies Dart 3 pattern matching, switch expressions, and destructuring
  idiomatically to validate data schemas, handle algebraic data types, and
  decompose control flow. Use when refactoring complex if-else chains,
  parsing polymorphic JSON or API responses, destructuring Records or Maps, or
  enforcing exhaustiveness on sealed classes. Don't use for simple boolean
  conditions, single-variable type promotion (use `is`), or basic collection
  filtering.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Sun, 06 Sep 2026 06:43:00 GMT
---
# Implementing Dart Patterns

## Contents
- [Pattern Selection Strategy](#pattern-selection-strategy)
- [Switch Statements vs. Expressions](#switch-statements-vs-expressions)
- [Core Pattern Implementations](#core-pattern-implementations)
- [Pragmatic Balance & Anti-Patterns](#pragmatic-balance--anti-patterns)
- [Workflows](#workflows)
- [Examples](#examples)

## Pattern Selection Strategy

Apply specific pattern types based on the data structure and desired outcome. Follow these conditional guidelines:

*   **If validating and extracting from deserialized data (e.g., JSON):** Use Map, List, and Object patterns to validate schema structure and destructure properties in a single step.
*   **If handling polymorphic payloads or responses:** Use `switch` expressions over map discriminant keys to deserialize into `sealed` class hierarchies.
*   **If handling multiple return values:** Use Record patterns to destructure fields directly into local variables.
*   **If executing type-specific behavior (Algebraic Data Types):** Use Object patterns combined with `sealed` classes to ensure exhaustiveness.
*   **If matching numeric ranges or conditions:** Use Relational (`>=`, `<=`) and Logical-and (`&&`) patterns within switch arms.
*   **If multiple cases share logic:** Use Logical-or (`||`) patterns to share a single case body or guard clause.
*   **If ignoring specific values:** Use the Wildcard pattern (`_`) or a non-matching Rest element (`...`) in collections.

## Switch Statements vs. Expressions

Select the appropriate switch construct based on the execution context:

*   **If producing a value:** Use a **switch expression**.
    *   Syntax: `switch (value) { pattern => expression, }`
    *   Rule: Each case must be a single expression. No implicit fallthrough. Must be exhaustive.
*   **If executing statements or side effects:** Use a **switch statement**.
    *   Syntax: `switch (value) { case pattern: statements; }`
    *   Rule: Empty cases fall through to the next case. Non-empty cases implicitly break (no `break` keyword required).

## Core Pattern Implementations

Implement patterns using the following syntax and rules:

*   **Logical-or (`||`):** `pattern1 || pattern2`. Both branches must define the exact same set of variables.
*   **Logical-and (`&&`):** `pattern1 && pattern2`. Branches must *not* define overlapping variables.
*   **Relational:** `==`, `!=`, `<`, `>`, `<=`, `>=` followed by a constant expression.
*   **Cast (`as`):** `pattern as Type`. Throws if the value does not match the type. Use to forcibly assert types during destructuring.
*   **Null-check (`?`):** `pattern?`. Fails the match if the value is null. Binds the variable to the non-nullable base type.
*   **Null-assert (`!`):** `pattern!`. Throws if the value is null.
*   **Variable:** `var name` or `Type name`. Binds the matched value to a new local variable.
*   **Wildcard (`_`):** Matches any value and discards it.
*   **List:** `[pattern1, pattern2]`. Matches lists of exact length unless a Rest element (`...` or `...var rest`) is used.
*   **Map:** `{"key": pattern}`. Matches maps containing the specified keys. Ignores unmatched keys.
*   **Record:** `(pattern1, named: pattern2)`. Matches records of the exact shape. Use `:var name` to infer the getter name.
*   **Object:** `ClassName(field: pattern)`. Matches instances of `ClassName`. Use `:var field` to infer the getter name.

## Pragmatic Balance & Anti-Patterns

Pattern matching and switch expressions should simplify code, not add syntactic overhead. Observe the following boundaries:

### 1. Prefer `is` Type Promotion over `if-case` for Single Promotable Variables
When checking or promoting a single variable, use standard `is` checks instead of `if-case` patterns that introduce shadow aliases.

*   **Prefer:**
    ```dart
    // ✅ Promotes `key` directly in-place without extra variables
    for (final MapEntry(:key, :value) in map.entries) {
      if (key is String && value != null) {
        process(key, value);
      }
    }
    ```
*   **Avoid:**
    ```dart
    // ❌ Anti-pattern: Introduces unnecessary alias variable `k`
    for (final MapEntry(:key, :value) in map.entries) {
      if (key case final String k when value != null) {
        process(k, value);
      }
    }
    ```

### 2. Consolidate Nullable Types in Switch Arms
When mapping or returning values where both `null` and a type `T` are valid and handled identically, match the nullable type `T?` directly rather than creating redundant `null` arms.

*   **Prefer:**
    ```dart
    // ✅ Clean nullable pattern match
    switch (value) {
      final String? s => s,
      _ => throw FormatException('Invalid value: $value'),
    }
    ```
*   **Avoid:**
    ```dart
    // ❌ Redundant separate null arm
    switch (value) {
      final String s => s,
      null => null,
      _ => throw FormatException('Invalid value: $value'),
    }
    ```

### 3. Preserve Fast-Fail Validation (Do Not Silently Drop Data)
Do not use `if-case` in loops or deserialization to filter elements if malformed data should trigger an error or diagnostic warning.

*   **Prefer:**
    ```dart
    // ✅ Fast-fail with explicit diagnostic error
    for (final raw in rawTasks) {
      if (raw is! Map<String, dynamic>) {
        throw FormatException('Expected Map item, got ${raw.runtimeType}: $raw');
      }
      _applyTask(raw);
    }
    ```
*   **Avoid:**
    ```dart
    // ❌ Silently ignores malformed items
    for (final raw in rawTasks) {
      if (raw case final Map<String, dynamic> taskMap) {
        _applyTask(taskMap);
      }
    }
    ```

### 4. Avoid Single-Case or Boolean Switches
*   Use `if (x is T)` instead of a `switch` statement with only 1 case and `default: break;`.
*   Use standard conditional ternary operators (`condition ? a : b`) instead of `switch (condition) { true => a, false => b }`.

### 5. Avoid Gratuitous Object Destructuring
Use standard property access (`user.name`) rather than object pattern destructuring (`final User(:name) = user;`) when reading a single property on a known non-null instance.

### 6. Avoid `if-case` for Standalone Scalar Comparisons
Use standard boolean operators (`if (code >= 200 && code < 300)`) instead of `if (code case >= 200 && < 300)` for standalone conditions. Reserve relational patterns for multi-arm `switch` tables.

## Workflows

### Task Progress: Implementing Pattern Matching
Copy this checklist to track progress when implementing complex pattern matching logic:

- [ ] Identify the data structure being evaluated (JSON, Record, Class, Enum).
- [ ] Select the appropriate switch construct (Expression for values, Statement for side-effects).
- [ ] Define the required patterns (Object, Map, List, Record).
- [ ] Extract required data using Variable patterns (`var x`, `:var y`).
- [ ] Apply Guard clauses (`when condition`) for logic that cannot be expressed via patterns.
- [ ] Handle unmatched cases using a Wildcard (`_`) or `default` clause (if not using a sealed class).
- [ ] Run static analyzer for exhaustiveness and dead code (`dart analyze`).
- [ ] Verify runtime Map/JSON pattern behavior on omitted keys (`containsKey` semantics) vs explicit `null` values.

### Feedback Loop 1: Exhaustiveness Checking (Static Verification)
When switching over `sealed` classes or enums, ensure all subtypes are handled at compile time:

1. **Run analyzer:** Execute `dart analyze`.
2. **Review errors:** Look for "The type 'X' is not exhaustively matched by the switch cases" or unreachable pattern arm warnings.
3. **Fix:** Add the missing Object patterns for unhandled subtypes, or add an explicit wildcard (`_`) arm if a default fallback or error is acceptable.

### Feedback Loop 2: Runtime Map & JSON Pattern Verification
Because `dart analyze` cannot statically verify dynamic `Map<String, dynamic>` keys, validate runtime pattern semantics explicitly:

1. **Omitted Keys vs. Explicit `null`**: A map pattern `{'key': String? val}` checks `map.containsKey('key')`. If `'key'` is omitted from the JSON payload, the pattern fails to match at runtime even though `String?` is nullable. Extract optional keys from the validated map directly (`map['key'] as String?`).
2. **Fast-Fail Fallback**: Ensure unmatched or malformed map structures hit an explicit `_ => throw FormatException(...)` arm rather than silently failing an `if-case` check.

## Examples

### Polymorphic JSON Deserialization (Discriminated Unions)
Use Map patterns with switch expressions to validate tagged JSON payloads and
construct `sealed` class hierarchies. See
[examples/json_patterns.dart](examples/json_patterns.dart) for an executable
implementation demonstrating tagged `ApiResponse` parsing into `SuccessResponse`
and `ErrorResponse`.

### Nested JSON Validation and Optional Fields
Use nested Map and List patterns to validate required schema structure and
extract collections in a single step. See
[examples/json_patterns.dart](examples/json_patterns.dart) for an executable
implementation of `processUserPayload`.

Map patterns check for key existence (`containsKey`). If an optional JSON key
might be omitted entirely from the payload (rather than explicitly passed as
`'key': null`), destructure required keys via the pattern and extract optional
fields directly from the matched submap.

### Algebraic Data Types (Sealed Classes)
Use Object patterns with switch expressions to handle family types exhaustively.

```dart
sealed class Shape {}

class Square implements Shape {
  final double length;
  Square(this.length);
}

class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

// Switch expression guarantees exhaustiveness due to `sealed` modifier.
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(:var radius)   => math.pi * radius * radius,
};
```

### Variable Swapping and Destructuring
Use variable assignment patterns to swap values or extract record fields without temporary variables.

```dart
var (a, b) = ('left', 'right');
(b, a) = (a, b); // Swap values

// Destructuring a function return
var (name, age) = getUserInfo();
```

### Guard Clauses and Logical-or
Use `when` to evaluate arbitrary conditions after a pattern matches.

```dart
switch (shape) {
  case Square(length: var s) || Circle(radius: var s) when s > 0:
    print('Valid positive shape with dimension $s');
  case Square() || Circle():
    print('Zero or negative dimension shape');
}
```

<!-- chapter:end slug=dart-use-pattern-matching -->

---

<!-- chapter:begin slug=dart-use-primary-constructors position=14 -->

## 14. dart-use-primary-constructors

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-use-primary-constructors/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-use-primary-constructors/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-use-primary-constructors.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-use-primary-constructors
description: >
  Help users write syntactically and semantically correct primary constructors in Dart, and migrate/use the new constructor syntax, empty-body semicolon syntax, in-body initializer list syntax, and abbreviated concise constructor syntax.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Thu, 09 Jul 2026 23:13:25 GMT
---

# Dart Primary Constructors & New Constructor Syntax Skill

Use this skill when helping users write, refactor, or debug code using Dart's **Primary Constructors** feature.

### Dart Version Requirements
*   **Dart 3.13 and above**: Primary constructors are enabled by default.
*   **Dart 3.12**: The feature is available but experimental. Users must explicitly enable the experiment flag `primary-constructors` via `--enable-experiment=primary-constructors` or in `analysis_options.yaml`:
```yaml
analyzer:
  enable-experiment:
    - primary-constructors
```
*   **Dart 3.11 and earlier**: Primary constructors are not supported.

---

## 1. Overview
Primary Constructors allow developers to declare a non-redirecting generative constructor as well as a set of instance variables directly in the class header. This significantly reduces boilerplate and improves code readability.

### Key Benefits
- Combines field declaration, parameter declaration, and initialization into a single declaration known as a declaring parameter declaration.
- Enables safe reference to constructor parameters in non-late field initializers (Primary Initializer Scope).
- Allows empty declaration bodies to be represented concisely with a semicolon (`;`).
- Introduces abbreviated concise syntax for in-body constructors.

---

## 2. Syntax Reference

### 2.1 Basic Class Header Syntax
To declare a primary constructor, place a parameter list immediately after the type name (and optional type parameters):

```dart
// Declares fields x and y, and a generative constructor Point(this.x, this.y)
class Point(var int x, var int y);

// Declares final fields
class PointFinal(final int x, final int y);
```

### 2.2 Declaring, Initializing, and Plain Parameters
A primary constructor parameter list distinguishes between three types of parameters:
1. **Declaring Parameters**: Indicated by the `var` or `final` modifier (e.g., `final int x`). They implicitly create a corresponding instance field in the class.
2. **Initializing Parameters**: Indicated by the `this.` or `super.` prefix (e.g., `this.x` or `super.x`). They initialize an existing field or a super constructor parameter, respectively.
3. **Regular Parameters**: Declared without modifiers (e.g., `int y`). They do not become fields and are only available during initialization (e.g., in field initializers or the `this :` initializer list in the class body).

```dart
// `x` is a field and a parameter because it has the keyword `final`. In particular, we can use the name `x` in the initializer list in the in-body part of the primary constructor. 'y' is a only parameter because it has neither of the keywords `final` or `var`, but `y` is passed to the super constructor via the `this :` initializer list.
class C(final int x, int y) extends Base {
  this : super(y);
}
```

Declaring parameters and initializing parameters are two ways of achieving the same goal: declaring a class with instance fields which are set in the constructor. Regular parameters are different in that their values are not automatically routed to an instance field.

### 2.3 Constant Primary Constructors
To make a primary constructor `const`, place the `const` keyword before the class/type name in the declaration header:

```dart
class const Point(final int x, final int y);
extension type const Ext(int x);
enum const MyEnum(final int x) {
  entry(1);
}
```

### 2.4 Extension Types
Extension types **must** use primary constructors.
- The single parameter in the header is the representation field.
- The representation variable cannot use the `var` modifier (using `var` triggers the `representation_field_modifier` error).
- The representation variable can optionally use the `final` modifier. If `final` is not present then it is inferred; that is, the parameter is declaring whether or not it's explicitly `final`.

### 2.5 Empty Body Semicolon Shorthand (`;`)
When a class, mixin class, mixin, extension or extension type has an empty body, the `{}` braces can be replaced by a semicolon (`;`):

```dart
class C(int x);
mixin class MC;
extension type ET(int x);
mixin M;
extension Ext on C;
```

### 2.6 The In-Body Part of a Primary Constructor (`this ...`)
If a primary constructor requires assertions or custom field initializations, they can be declared in the body using the `this :` syntax:

```dart
class Point(var int x, var int y) {
  // Initializer list in class body
  this : assert(x >= 0), y = y * 2;
}
```

You can also write a constructor body with this syntax (`this {...}`).

### 2.7 Abbreviated Concise Constructor Syntax
For constructors declared within the class body, the class name can be omitted and replaced with the `new` or `factory` keywords:

| Traditional Syntax | Abbreviated Concise Syntax |
| :--- | :--- |
| `MyClass() {}` | `new() {}` |
| `MyClass.name() {}` | `new name() {}` |
| `const MyClass();` | `const new();` |
| `const MyClass.name();` | `const new name();` |
| `factory MyClass() => ...` | `factory() => ...` |
| `factory MyClass.name() => ...` | `factory name() => ...` |

---

## 3. Semantics & Scoping Rules

### 3.1 Primary Initializer Scope
When a primary constructor is declared, its formal parameters are introduced into the **Primary Initializer Scope**. This scope is the current scope for non-late field initializers in the class body and the primary constructor's initializer list (after `this :`).
This allows non-late fields to reference constructor parameters directly during declaration:
  ```dart
  class DeltaPoint(final int x, int delta) {
    // 'x' and 'delta' are in scope here
    final int y = x + delta;
  }
  ```

### 3.2 Late Instance Variables Restriction
The primary initializer scope is **not** active for `late` instance variable initializers.
- Since `late` variables can be evaluated after construction has completed, their initializers cannot safely access constructor parameters.
- Attempting to access a primary constructor parameter in a `late` field initializer results in a compile-time error.

### 3.3 Shadowing
Primary constructor parameters shadow class members (fields) of the same name within the primary initializer scope:
- In a non-late initializer: `int y = x` refers to parameter `x`.
- In a `late` initializer: `late int y = x` refers to field `x` (if it exists) because the parameter `x` is out of scope.

### 3.4 Generative Constructor Restrictions
To guarantee that the primary constructor (and the associated initializer scope) always executes:
- A class, mixin class, or enum declaration with a primary constructor **cannot** declare any other non-redirecting generative constructors (except extension types).
- All other generative constructors declared in the body **must** redirect (directly or indirectly) to the primary constructor.

### 3.5 Parameter Mutation Errors
Primary constructor parameters are non-assignable inside the initialization phase.
- Any assignment to a parameter (e.g., `p = value`, `p++`) inside field initializers or the `this :` initializer list is a compile-time error.

### 3.6 Double Initialization Errors
Initializing a field twice (e.g., once in the field declaration/initializer and once in the `this :` initializer list or as an initializing formal) is a compile-time error.

---

## 4. Diagnostics & Troubleshooting

Most errors and lints have quick-fixes, run `dart fix` to fix those violations. For other common errors, fix them using the following table:

| Error / Lint Code | Common Cause | Resolution |
| :--- | :--- | :--- |
| **Invalid Late Access** | Referencing a primary constructor parameter inside a `late` field initializer. | Make the field non-late, or pass the value through another non-late field. |
| `fieldInitializedInInitializerAndDeclaration` | Initializing a variable both in its declaration and in the `this :` list. | Remove one of the initializations. |
| `nonRedirectingGenerativeConstructorWithPrimary` | Declaring a in-body generative constructor in the body without redirecting to the primary. | Change the in-body constructor such that it is redirecting (e.g. `this(...)`) or remove the in-body constructor. |

---

## 5. Step-by-Step Refactoring Workflows

### Workflow 5.1: Migrating a Class to a Primary Constructor

Follow these steps to migrate a verbose class to the new primary constructor syntax:

1. **Identify Candidate Fields and Constructor**:
   Locate generative constructors and the fields they initialize. In this case, this would be the `name` and `age` fields.
   ```dart
   // Before
   class User {
     final String name;
     final int age;
     User(this.name, this.age);
   }
   ```

2. **Move Fields to the Header**:
   Place fields in the header with `final` or `var` modifiers and append a semicolon (`;`) if the body is empty. The `name` and `age` fields are now written the primary constructor as declaring parameters `final String name` and `final int age`, respectively.
   ```dart
   // After
   class User(final String name, final int age);
   ```

3. **Handle Custom Initializers and Assertions**:
   If there is an initializer list or assert block, move it to a `this` block inside the body:
   ```dart
   // Before
   class Point {
     final int x;
     final int y;
     Point(this.x, this.y) : assert(x >= 0);
   }

   // After
   class Point(final int x, final int y) {
     this : assert(x >= 0);
   }
   ```

4. **Leverage Primary Initializer Scope for Calculations**:
   If a field value is calculated from parameters, declare it inside the body and assign it directly using the parameters:
   ```dart
   // Before
   class Rect {
     final double width;
     final double height;
     final double area;
     Rect(this.width, this.height) : area = width * height;
   }

   // After
   class Rect(final double width, final double height) {
     // 'width' and 'height' are in scope here
     final double area = width * height;
   }
   ```

5. **Convert In-Body Constructors to Redirecting**:
   Ensure all in-body generative constructors redirect to the primary constructor:
   ```dart
   // Before
   class Point {
     final int x;
     final int y;
     Point(this.x, this.y);
     Point.zero() : x = 0, y = 0;
   }

   // After
   class Point(final int x, final int y) {
     new zero() : this(0, 0); // Redirects to primary
   }
   ```

### Workflow 5.2: Applying Abbreviated (Concise) In-Body Constructors

When the user prefers to keep the constructor in the class body but wants to reduce verbosity, suggest the abbreviated constructor syntax:

```dart
// Before
class DatabaseService {
  final String url;
  DatabaseService(this.url);
  DatabaseService.local() : url = 'localhost';
  factory DatabaseService.create() => DatabaseService('default');
}

// After
class DatabaseService {
  final String url;
  new(this.url); // Omit class name, use 'new'
  new local() : url = 'localhost'; // Use 'new local' for named constructors
  factory create() => DatabaseService('default'); // Omit class name from factory
}
```

<!-- chapter:end slug=dart-use-primary-constructors -->

---

<!-- chapter:begin slug=dart-write-documentation position=15 -->

## 15. dart-write-documentation

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/dart-write-documentation/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/dart-write-documentation/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/dart-write-documentation.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: dart-write-documentation
description: "Rules and formatting guidelines for writing Dart /// API documentation and doc comments. Use when documenting Dart code, writing doc comments for any Dart declaration (libraries, classes, methods, variables, etc.), or when instructed to follow the Effective Dart documentation guidelines."
---

# Writing Dart API Documentation

## Contents
*   [1. Scope and Structure](#1-scope-and-structure)
*   [2. Tone and Openers](#2-tone-and-openers)
*   [3. Strict Anti-Patterns (Banned)](#3-strict-anti-patterns-banned)
*   [4. Technical Placement & Resolution](#4-technical-placement--resolution)
*   [5. Linking and Markdown](#5-linking-and-markdown)
*   [6. Verification](#6-verification)
*   [Examples](#examples)

When asked to write or update documentation for Dart code, you must strictly follow these formatting rules based on the "Effective Dart: Documentation" guidelines.

## 1. Scope and Structure
*   **Target Public APIs:** Focus your documentation efforts on public declarations. Do not document private members (those starting with an underscore `_`) unless explicitly instructed, as they do not appear in generated API reference sites.
*   **Always use `///`:** Use `///` consecutive line comments for all API documentation. Never use `/** ... */` block comments.
*   **Proper Sentences:** Format all comments like proper sentences. Capitalize the first word (unless it's a lowercase identifier) and end with a period.
*   **The First Paragraph:** The first paragraph of a doc comment must be a single, concise sentence that summarizes the element. End it with a period. Dartdoc extracts this verbatim for list views.
*   **Separation:** Always separate the first sentence summary from the rest of the documentation with a blank line containing `///`. Never output a completely empty newline (e.g., a `\n` without `///`), as this terminates the doc comment block.

## 2. Tone and Openers
*   **Noun phrases for properties:** Start descriptions of variables, getters, or setters with a noun phrase.
    `/// The radius of the sphere.` (Not "Gets the radius...")
*   **"Whether" for booleans:** Start documentation for boolean properties with "Whether".
    `/// Whether the connection is active.`
*   **Third-person verbs for methods:** Start descriptions of methods or functions with a third-person verb that describes what it does.
    `/// Initializes the database.` (Not "Initialize" or "This method initializes").
*   **Avoid redundancy:** Do not restate the signature or the element name. Do not say "This class is a..." or "The foo method does...".

## 3. Strict Anti-Patterns (Banned)
*   **No Javadoc/TSDoc Tags (`@param`, `@return`, `@throws`, etc.):** Never use Javadoc-style tags (`@param`, `@return`, `@returns`, `@throws`, `@exception`, `@see`, `@type`). Instead, weave parameter names, return behavior, and exceptions into the prose.

## 4. Technical Placement & Resolution
*   **Annotations (`@override`, etc.):** Doc comments must be placed before metadata annotations.
*   **Inherited Documentation:** Avoid duplicating doc comments on `@override` members if the behavior does not differ from the superclass or interface. Dartdoc automatically inherits the base documentation.
*   **Getter/Setter Pairs:** If a property has both a getter and a setter, place the documentation only on the getter. Tooling will emit a warning if both are documented.
*   **Default Constructors:** To link to a default, unnamed constructor in doc comments, you must use the `.new` syntax (e.g., `[ClassName.new]`).

## 5. Linking and Markdown
*   **Square brackets (`[identifier]`) for in-scope symbols:** Use square brackets to link to any in-scope identifier (parameters, classes, methods, fields, and top-level functions) so dartdoc can resolve them. Never use backticks for parameters.
*   **No parentheses in method links:** Avoid parentheses in links (e.g., use `[String.contains]`, not `[String.contains()]`).
*   **Backticks for keywords & literals:** Use backticks for keywords, literals, and arbitrary expressions (e.g. `` `null` ``, `` `true` ``, `` `void` ``). Never put keywords in square brackets (avoid `[null]` or `[true]`).
*   **Out-of-Scope Links:** If you need to link to a symbol that is not imported by the current library, use the `@docImport` directive at the top of the file (on the `library;` declaration) rather than adding a standard `import`.
*   **Code Blocks:** For code samples, always label the language fence. Use ```` ```dart ```` for Dart, or ```` ```sh ```` for shell commands. Do not leave code blocks unlabelled, as Dartdoc will attempt to auto-detect the language and frequently guesses wrong.
*   **Formatting:** Use standard Markdown (bold, lists, etc.) after the first paragraph to fully explain edge cases, exceptions thrown, and internal behavior the caller cannot see.

## 6. Verification
After writing or updating doc comments:
1. Run `dart analyze` to ensure all bracketed references resolve properly without triggering `comment_references` warnings.
2. (Optional) Run `dart doc` to verify the generated documentation renders cleanly.

## Examples

### 1. Banned Tags vs. Prose
**Bad:**
```dart
/// This method fetches data.
/// @param force true to force reload.
/// @return the data
/// @throws NetworkException if host is unreachable.
Data load(bool force) { ... }
```
**Good:**
```dart
/// Fetches the remote data.
///
/// If [force] is true, this bypasses the local cache and forces a
/// network request.
///
/// Throws a [NetworkException] if the host is unreachable.
Data load(bool force) { ... }
```

### 2. The Annotation Placement Trap
**Bad:**
```dart
@override
/// Renders the widget to the screen.
Widget build(BuildContext context) { ... }
```
**Good:**
```dart
/// Renders the widget to the screen.
@override
Widget build(BuildContext context) { ... }
```

### 3. Openers and Tone
**Bad:**
```dart
/// Gets if the connection is active.
bool get isActive => _active;

/// This method initializes the connection.
void init() { ... }
```
**Good:**
```dart
/// Whether the connection is active.
bool get isActive => _active;

/// Initializes the connection.
void init() { ... }
```

### 4. Constructor Linking
**Bad:**
```dart
/// Creates a new user. Similar to calling [User()].
User.create() { ... }
```
**Good:**
```dart
/// Creates a new user. Similar to calling [User.new].
User.create() { ... }
```

### 5. Out-of-Scope Links (@docImport)
**Bad:**
```dart
import 'package:http/http.dart'; // Adds unnecessary runtime dependency just for docs

/// To use this, you must pass a [Client].
```
**Good:**
```dart
/// @docImport 'package:http/http.dart';
library;

/// To use this, you must pass a [Client].
```

<!-- chapter:end slug=dart-write-documentation -->

---

<!-- chapter:begin slug=flutter-add-integration-test position=16 -->

## 16. flutter-add-integration-test

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-integration-test/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-add-integration-test/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-add-integration-test.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-add-integration-test
description: Configures Flutter Driver for app interaction and converts MCP actions into permanent integration tests. Use when adding integration testing to a project, exploring UI components via MCP, or automating user flows with the integration_test package.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 18:29:20 GMT
---
# Implementing Flutter Integration Tests

## Contents
- [Project Setup and Dependencies](#project-setup-and-dependencies)
- [Interactive Exploration via MCP](#interactive-exploration-via-mcp)
- [Test Authoring Guidelines](#test-authoring-guidelines)
- [Execution and Profiling](#execution-and-profiling)
- [Workflow: End-to-End Integration Testing](#workflow-end-to-end-integration-testing)
- [Examples](#examples)

## Project Setup and Dependencies

Configure the project to support integration testing and Flutter Driver extensions.

1. Add required development dependencies to `pubspec.yaml`:
   ```bash
   flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
   flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
   ```
2. Enable the Flutter Driver extension in your application entry point (typically `lib/main.dart` or a dedicated `lib/main_test.dart`):
   - Import `package:flutter_driver/driver_extension.dart`.
   - Call `enableFlutterDriverExtension();` before `runApp()`.
3. Add `Key` parameters (e.g., `ValueKey('login_button')`) to critical widgets in the application code to ensure reliable targeting during tests.

## Interactive Exploration via MCP

Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.

- **Launch**: Execute `launch_app` with `target: "lib/main_test.dart"` to start the application and acquire the DTD URI.
- **Inspect**: Execute `get_widget_tree` to discover available `Key`s, `Text` nodes, and widget `Type`s.
- **Interact**: Execute `tap`, `enter_text`, and `scroll` to simulate user flows.
- **Wait**: Always execute `waitFor` or verify state with `get_health` when navigating or triggering animations.
- **Troubleshoot Unmounted Widgets**: If a widget is not found in the tree, it may be lazily loaded in a `SliverList` or `ListView`. Execute `scroll` or `scrollIntoView` to force the widget to mount before interacting with it.

## Test Authoring Guidelines

Structure integration tests using the `flutter_test` API paradigm. 

- Create a dedicated `integration_test/` directory at the project root.
- Name all test files using the `<name>_test.dart` convention.
- Initialize the binding by calling `IntegrationTestWidgetsFlutterBinding.ensureInitialized();` at the start of `main()`.
- Load the application UI using `await tester.pumpWidget(MyApp());`.
- Trigger frames and wait for animations to complete using `await tester.pumpAndSettle();` after interactions like `tester.tap()`.
- Assert widget visibility using `expect(find.byKey(ValueKey('foo')), findsOneWidget);` or `findsNothing`.
- Scroll to specific off-screen widgets using `await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);`.

**Conditional Logic for Legacy `flutter_driver`:**
- If maintaining or migrating legacy `flutter_driver` tests, use `driver.waitFor()`, `driver.waitForAbsent()`, `driver.tap()`, and `driver.scroll()` instead of the `WidgetTester` APIs.

## Execution and Profiling

Execute tests using the `flutter drive` command. Require a host driver script located in `test_driver/integration_test.dart` that calls `integrationDriver()`.

**Conditional Execution Targets:**
- **If testing on Chrome:** Launch `chromedriver --port=4444` in a separate terminal, then run:
  `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome`
- **If testing headless web:** Run with `-d web-server`.
- **If testing on Android (Local):** Run `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart`.
- **If testing on Firebase Test Lab (Android):** 
  1. Build debug APK: `flutter build apk --debug`
  2. Build test APK: `./gradlew app:assembleAndroidTest`
  3. Upload both APKs to the Firebase Test Lab console.

## Workflow: End-to-End Integration Testing

Copy and follow this checklist to implement and verify integration tests.

- [ ] **Task Progress: Setup**
  - [ ] Add `integration_test` and `flutter_test` to `pubspec.yaml`.
  - [ ] Inject `enableFlutterDriverExtension()` into the app entry point.
  - [ ] Assign `ValueKey`s to target widgets.
- [ ] **Task Progress: Exploration**
  - [ ] Run `launch_app` via MCP.
  - [ ] Map the widget tree using `get_widget_tree`.
  - [ ] Validate interaction paths using MCP tools (`tap`, `enter_text`).
- [ ] **Task Progress: Authoring**
  - [ ] Create `integration_test/app_test.dart`.
  - [ ] Write test cases using `WidgetTester` APIs.
  - [ ] Create `test_driver/integration_test.dart` with `integrationDriver()`.
- [ ] **Task Progress: Execution & Feedback Loop**
  - [ ] Run `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart`.
  - [ ] **Feedback Loop**: Review test output -> If `PumpAndSettleTimedOutException` occurs, check for infinite animations -> If widget not found, add `scrollUntilVisible` -> Re-run test until passing.

## Examples

### Standard Integration Test (`integration_test/app_test.dart`)

```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('End-to-end test', () {
    testWidgets('tap on the floating action button, verify counter', (tester) async {
      // Load app widget.
      await tester.pumpWidget(const MyApp());

      // Verify the counter starts at 0.
      expect(find.text('0'), findsOneWidget);

      // Find the floating action button to tap on.
      final fab = find.byKey(const ValueKey('increment'));

      // Emulate a tap on the floating action button.
      await tester.tap(fab);

      // Trigger a frame and wait for animations.
      await tester.pumpAndSettle();

      // Verify the counter increments by 1.
      expect(find.text('1'), findsOneWidget);
    });
  });
}
```

### Host Driver Script (`test_driver/integration_test.dart`)

```dart
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();
```

### Performance Profiling Driver Script (`test_driver/perf_driver.dart`)

Use this driver script if you wrap your test actions in `binding.traceAction()` to capture performance metrics.

```dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';

Future<void> main() {
  return integrationDriver(
    responseDataCallback: (data) async {
      if (data != null) {
        final timeline = driver.Timeline.fromJson(
          data['scrolling_timeline'] as Map<String, dynamic>,
        );

        final summary = driver.TimelineSummary.summarize(timeline);

        await summary.writeTimelineToFile(
          'scrolling_timeline',
          pretty: true,
          includeSummary: true,
        );
      }
    },
  );
}
```

<!-- chapter:end slug=flutter-add-integration-test -->

---

<!-- chapter:begin slug=flutter-add-widget-preview position=17 -->

## 17. flutter-add-widget-preview

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-widget-preview/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-add-widget-preview/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-add-widget-preview.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-add-widget-preview
description: Adds interactive widget previews to the project using the previews.dart system. Use when creating new UI components or updating existing screens to ensure consistent design and interactive testing.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 20:05:23 GMT
---
# Previewing Flutter Widgets

## Contents
- [Preview Guidelines](#preview-guidelines)
- [Handling Limitations](#handling-limitations)
- [Workflows](#workflows)
- [Examples](#examples)

## Preview Guidelines

Use the Flutter Widget Previewer to render widgets in real-time, isolated from the full application context. 

- **Target Elements:** Apply the `@Preview` annotation to top-level functions, static methods within a class, or public widget constructors/factories that have no required arguments and return a `Widget` or `WidgetBuilder`.
- **Imports:** Always import `package:flutter/widget_previews.dart` to access the preview annotations.
- **Custom Annotations:** Extend the `Preview` class to create custom annotations that inject common properties (e.g., themes, wrappers) across multiple widgets.
- **Multiple Configurations:** Apply multiple `@Preview` annotations to a single target to generate multiple preview instances. Alternatively, extend `MultiPreview` to encapsulate common multi-preview configurations.
- **Runtime Transformations:** Override the `transform()` method in custom `Preview` or `MultiPreview` classes to modify preview configurations dynamically at runtime (e.g., generating names based on dynamic values, which is impossible in a `const` context).

## Handling Limitations

Adhere to the following constraints when authoring previewable widgets, as the Widget Previewer runs in a web environment:

- **No Native APIs:** Do not use native plugins or APIs from `dart:io` or `dart:ffi`. Widgets with transitive dependencies on `dart:io` or `dart:ffi` will throw exceptions upon invocation. Use conditional imports to mock or bypass these in preview mode.
- **Asset Paths:** Use package-based paths for assets loaded via `dart:ui` `fromAsset` APIs (e.g., `packages/my_package_name/assets/my_image.png` instead of `assets/my_image.png`).
- **Public Callbacks:** Ensure all callback arguments provided to preview annotations are public and constant to satisfy code generation requirements.
- **Constraints:** Apply explicit constraints using the `size` parameter in the `@Preview` annotation if your widget is unconstrained, as the previewer defaults to constraining them to approximately half the viewport.

## Workflows

### Creating a Widget Preview
Copy and track this checklist when implementing a new widget preview:

- [ ] Import `package:flutter/widget_previews.dart`.
- [ ] Identify a valid target (top-level function, static method, or parameter-less public constructor).
- [ ] Apply the `@Preview` annotation to the target.
- [ ] Configure preview parameters (`name`, `group`, `size`, `theme`, `brightness`, etc.) as needed.
- [ ] If applying the same configuration to multiple widgets, extract the configuration into a custom class extending `Preview`.

### Interacting with Previews
Follow the appropriate conditional workflow to launch and interact with the Widget Previewer:

**If using a supported IDE (Android Studio, IntelliJ, VS Code with Flutter 3.38+):**
1. Launch the IDE. The Widget Previewer starts automatically.
2. Open the "Flutter Widget Preview" tab in the sidebar.
3. Toggle "Filter previews by selected file" at the bottom left if you want to view previews outside the currently active file.

**If using the Command Line:**
1. Navigate to the Flutter project's root directory.
2. Run `flutter widget-preview start`.
3. View the automatically opened Chrome environment.

**Feedback Loop: Preview Iteration**
1. Modify the widget code or preview configuration.
2. Observe the automatic update in the Widget Previewer.
3. If global state (e.g., static initializers) was modified: Click the global hot restart button at the bottom right.
4. If only the local widget state needs resetting: Click the individual hot restart button on the specific preview card.
5. Review errors in the IDE/CLI console -> fix -> repeat.

## Examples

### Basic Preview
```dart
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

@Preview(name: 'My Sample Text', group: 'Typography')
Widget mySampleText() {
  return const Text('Hello, World!');
}
```

### Custom Preview with Runtime Transformation
```dart
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

final class TransformativePreview extends Preview {
  const TransformativePreview({
    super.name,
    super.group,
  });

  PreviewThemeData _themeBuilder() {
    return PreviewThemeData(
      materialLight: ThemeData.light(),
      materialDark: ThemeData.dark(),
    );
  }

  @override
  Preview transform() {
    final originalPreview = super.transform();
    final builder = originalPreview.toBuilder();
    
    builder
      ..name = 'Transformed - ${originalPreview.name}'
      ..theme = _themeBuilder;

    return builder.toPreview();
  }
}

@TransformativePreview(name: 'Custom Themed Button')
Widget myButton() => const ElevatedButton(onPressed: null, child: Text('Click'));
```

### MultiPreview Implementation
```dart
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

/// Creates light and dark mode previews automatically.
final class MultiBrightnessPreview extends MultiPreview {
  const MultiBrightnessPreview({required this.name});

  final String name;

  @override
  List<Preview> get previews => const [
        Preview(brightness: Brightness.light),
        Preview(brightness: Brightness.dark),
      ];

  @override
  List<Preview> transform() {
    final previews = super.transform();
    return previews.map((preview) {
      final builder = preview.toBuilder()
        ..group = 'Brightness'
        ..name = '$name - ${preview.brightness!.name}';
      return builder.toPreview();
    }).toList();
  }
}

@MultiBrightnessPreview(name: 'Primary Card')
Widget cardPreview() => const Card(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Content')));
```

<!-- chapter:end slug=flutter-add-widget-preview -->

---

<!-- chapter:begin slug=flutter-add-widget-test position=18 -->

## 18. flutter-add-widget-test

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-add-widget-test/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-add-widget-test/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-add-widget-test.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-add-widget-test
description: Implement a component-level test using `WidgetTester` to verify UI rendering and user interactions (tapping, scrolling, entering text). Use when validating that a specific widget displays correct data and responds to events as expected.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 21:15:41 GMT
---
# Writing Flutter Widget Tests

## Contents
- [Setup & Configuration](#setup--configuration)
- [Core Components](#core-components)
- [Workflow: Implementing a Widget Test](#workflow-implementing-a-widget-test)
- [Interaction & State Management](#interaction--state-management)
- [Examples](#examples)

## Setup & Configuration

Ensure the testing environment is properly configured before authoring widget tests.

1. Add the `flutter_test` dependency to the `dev_dependencies` section of `pubspec.yaml`.
2. Place all test files in the `test/` directory at the root of the project.
3. Suffix all test file names with `_test.dart` (e.g., `widget_test.dart`).

## Core Components

Utilize the following `flutter_test` components to interact with and validate the widget tree:

*   **`WidgetTester`**: The primary interface for building and interacting with widgets in the test environment. Provided automatically by the `testWidgets()` function.
*   **`Finder`**: Locates widgets in the test environment (e.g., `find.text('Submit')`, `find.byType(TextField)`, `find.byKey(Key('submit_btn'))`).
*   **`Matcher`**: Verifies the presence or state of widgets located by a `Finder` (e.g., `findsOneWidget`, `findsNothing`, `findsNWidgets(2)`, `matchesGoldenFile`).

## Workflow: Implementing a Widget Test

Copy the following checklist to track progress when implementing a new widget test.

### Task Progress
- [ ] **Step 1: Define the test.** Use `testWidgets('description', (WidgetTester tester) async { ... })`.
- [ ] **Step 2: Build the widget.** Call `await tester.pumpWidget(MyWidget())` to render the UI. Wrap the widget in a `MaterialApp` or `Directionality` widget if it requires inherited directional or theme data.
- [ ] **Step 3: Locate elements.** Instantiate `Finder` objects for the target widgets.
- [ ] **Step 4: Verify initial state.** Use `expect(finder, matcher)` to validate the initial render.
- [ ] **Step 5: Simulate interactions.** Execute gestures or inputs (e.g., `await tester.tap(buttonFinder)`).
- [ ] **Step 6: Rebuild the tree.** Call `await tester.pump()` or `await tester.pumpAndSettle()` to process state changes.
- [ ] **Step 7: Verify updated state.** Use `expect()` to validate the UI after the interaction.
- [ ] **Step 8: Run and validate.** Execute `flutter test test/your_test_file_test.dart`.
- [ ] **Step 9: Feedback Loop.** Review test output -> identify failing matchers -> adjust widget logic or test assertions -> re-run until passing.

## Interaction & State Management

Apply the following conditional logic based on the type of interaction or state change being tested:

*   **If testing static rendering:** Call `await tester.pumpWidget()` once, then immediately run `expect()` assertions.
*   **If testing standard state changes (e.g., button taps):** 
    1. Call `await tester.tap(finder)`.
    2. Call `await tester.pump()` to trigger a single frame rebuild.
*   **If testing animations, transitions, or asynchronous UI updates:** 
    1. Trigger the action (e.g., `await tester.drag(finder, Offset(500, 0))`).
    2. Call `await tester.pumpAndSettle()` to repeatedly pump frames until no more frames are scheduled (animation completes).
*   **If testing text input:** Call `await tester.enterText(textFieldFinder, 'Input string')`.
*   **If testing items in a dynamic or long list:** Call `await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder)` to ensure the target widget is rendered before interacting with it.

## Examples

### High-Fidelity Widget Test Implementation

**Target Widget (`lib/todo_list.dart`):**
```dart
import 'package:flutter/material.dart';

class TodoList extends StatefulWidget {
  const TodoList({super.key});

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  final todos = <String>[];
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          children: [
            TextField(controller: controller),
            Expanded(
              child: ListView.builder(
                itemCount: todos.length,
                itemBuilder: (context, index) {
                  final todo = todos[index];
                  return Dismissible(
                    key: Key('$todo$index'),
                    onDismissed: (_) => setState(() => todos.removeAt(index)),
                    child: ListTile(title: Text(todo)),
                  );
                },
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              todos.add(controller.text);
              controller.clear();
            });
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}
```

**Test Implementation (`test/todo_list_test.dart`):**
```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/todo_list.dart';

void main() {
  testWidgets('Add and remove a todo item', (WidgetTester tester) async {
    // 1. Build the widget
    await tester.pumpWidget(const TodoList());

    // 2. Verify initial state
    expect(find.byType(ListTile), findsNothing);

    // 3. Enter text into the TextField
    await tester.enterText(find.byType(TextField), 'Buy groceries');

    // 4. Tap the add button
    await tester.tap(find.byType(FloatingActionButton));

    // 5. Rebuild the widget to reflect the new state
    await tester.pump();

    // 6. Verify the item was added
    expect(find.text('Buy groceries'), findsOneWidget);

    // 7. Swipe the item to dismiss it
    await tester.drag(find.byType(Dismissible), const Offset(500, 0));

    // 8. Build the widget until the dismiss animation ends
    await tester.pumpAndSettle();

    // 9. Verify the item was removed
    expect(find.text('Buy groceries'), findsNothing);
  });
}
```

<!-- chapter:end slug=flutter-add-widget-test -->

---

<!-- chapter:begin slug=flutter-apply-architecture-best-practices position=19 -->

## 19. flutter-apply-architecture-best-practices

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-apply-architecture-best-practices/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-apply-architecture-best-practices/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-apply-architecture-best-practices.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-apply-architecture-best-practices
description: Architects a Flutter application using the recommended layered approach (UI, Logic, Data). Use when structuring a new project or refactoring for scalability.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 20:11:20 GMT
---
# Architecting Flutter Applications

## Contents
- [Architectural Layers](#architectural-layers)
- [Project Structure](#project-structure)
- [Workflow: Implementing a New Feature](#workflow-implementing-a-new-feature)
- [Examples](#examples)

## Architectural Layers

Enforce strict Separation of Concerns by dividing the application into distinct layers. Never mix UI rendering with business logic or data fetching.

### UI Layer (Presentation)
Implement the MVVM (Model-View-ViewModel) pattern to manage UI state and logic.
*   **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.
*   **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.

### Data Layer
Implement the Repository pattern to isolate data access logic and create a single source of truth.
*   **Services:** Create stateless classes to wrap external APIs (HTTP clients, local databases, platform plugins). Return raw API models or `Result` wrappers.
*   **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.

### Logic Layer (Domain - Optional)
*   **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.

## Project Structure

Organize the codebase using a hybrid approach: group UI components by feature, and group Data/Domain components by type.

```text
lib/
├── data/
│   ├── models/         # API models
│   ├── repositories/   # Repository implementations
│   └── services/       # API clients, local storage wrappers
├── domain/
│   ├── models/         # Clean domain models
│   └── use_cases/      # Optional business logic classes
└── ui/
    ├── core/           # Shared widgets, themes, typography
    └── features/
        └── [feature_name]/
            ├── view_models/
            └── views/
```

## Workflow: Implementing a New Feature

Follow this sequential workflow when adding a new feature to the application. Copy the checklist to track progress.

### Task Progress
- [ ] **Step 1: Define Domain Models.** Create immutable data classes for the feature using `freezed` or `built_value`.
- [ ] **Step 2: Implement Services.** Create or update Service classes to handle external API communication.
- [ ] **Step 3: Implement Repositories.** Create the Repository to consume Services and return Domain Models.
- [ ] **Step 4: Apply Conditional Logic (Domain Layer).**
  - *If the feature requires complex data transformation or cross-repository logic:* Create a Use Case class.
  - *If the feature is a simple CRUD operation:* Skip to Step 5.
- [ ] **Step 5: Implement the ViewModel.** Create the ViewModel extending `ChangeNotifier`. Inject required Repositories/Use Cases. Expose immutable state and command methods.
- [ ] **Step 6: Implement the View.** Create the UI widget. Use `ListenableBuilder` or `AnimatedBuilder` to listen to ViewModel changes.
- [ ] **Step 7: Inject Dependencies.** Register the new Service, Repository, and ViewModel in the dependency injection container (e.g., `provider` or `get_it`).
- [ ] **Step 8: Run Validator.** Execute unit tests for the ViewModel and Repository.
  - *Feedback Loop:* Run tests -> Review failures -> Fix logic -> Re-run until passing.

## Examples

### Data Layer: Service and Repository

```dart
// 1. Service (Raw API interaction)
class ApiClient {
  Future<UserApiModel> fetchUser(String id) async {
    // HTTP GET implementation...
  }
}

// 2. Repository (Single source of truth, returns Domain Model)
class UserRepository {
  UserRepository({required ApiClient apiClient}) : _apiClient = apiClient;
  
  final ApiClient _apiClient;
  User? _cachedUser;

  Future<User> getUser(String id) async {
    if (_cachedUser != null) return _cachedUser!;
    
    final apiModel = await _apiClient.fetchUser(id);
    _cachedUser = User(id: apiModel.id, name: apiModel.fullName); // Transform to Domain Model
    return _cachedUser!;
  }
}
```

### UI Layer: ViewModel and View

```dart
// 3. ViewModel (State management and presentation logic)
class ProfileViewModel extends ChangeNotifier {
  ProfileViewModel({required UserRepository userRepository}) 
      : _userRepository = userRepository;

  final UserRepository _userRepository;

  User? _user;
  User? get user => _user;

  bool _isLoading = false;
  bool get isLoading => _isLoading;

  Future<void> loadProfile(String id) async {
    _isLoading = true;
    notifyListeners();

    try {
      _user = await _userRepository.getUser(id);
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }
}

// 4. View (Dumb UI component)
class ProfileView extends StatelessWidget {
  const ProfileView({super.key, required this.viewModel});

  final ProfileViewModel viewModel;

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: viewModel,
      builder: (context, _) {
        if (viewModel.isLoading) {
          return const Center(child: CircularProgressIndicator());
        }
        
        final user = viewModel.user;
        if (user == null) {
          return const Center(child: Text('User not found'));
        }

        return Column(
          children: [
            Text(user.name),
            ElevatedButton(
              onPressed: () => viewModel.loadProfile(user.id),
              child: const Text('Refresh'),
            ),
          ],
        );
      },
    );
  }
}
```

<!-- chapter:end slug=flutter-apply-architecture-best-practices -->

---

<!-- chapter:begin slug=flutter-build-responsive-layout position=20 -->

## 20. flutter-build-responsive-layout

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-build-responsive-layout/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-build-responsive-layout/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-build-responsive-layout.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-build-responsive-layout
description: Use `LayoutBuilder`, `MediaQuery`, or `Expanded/Flexible` to create a layout that adapts to different screen sizes. Use when you need the UI to look good on both mobile and tablet/desktop form factors.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 20:17:40 GMT
---
# Implementing Adaptive Layouts

## Contents
- [Space Measurement Guidelines](#space-measurement-guidelines)
- [Widget Sizing and Constraints](#widget-sizing-and-constraints)
- [Device and Orientation Behaviors](#device-and-orientation-behaviors)
- [Workflow: Constructing an Adaptive Layout](#workflow-constructing-an-adaptive-layout)
- [Workflow: Optimizing for Large Screens](#workflow-optimizing-for-large-screens)
- [Examples](#examples)

## Space Measurement Guidelines
Determine the available space accurately to ensure layouts adapt to the app window, not just the physical device.

*   **Use `MediaQuery.sizeOf(context)`** to get the size of the entire app window.
*   **Use `LayoutBuilder`** to make layout decisions based on the parent widget's allocated space. Evaluate `constraints.maxWidth` to determine the appropriate widget tree to return.
*   **Do not use `MediaQuery.orientationOf` or `OrientationBuilder`** near the top of the widget tree to switch layouts. Device orientation does not accurately reflect the available app window space.
*   **Do not check for hardware types** (e.g., "phone" vs. "tablet"). Flutter apps run in resizable windows, multi-window modes, and picture-in-picture. Base all layout decisions strictly on available window space.

## Widget Sizing and Constraints
Understand and apply Flutter's core layout rule: **Constraints go down. Sizes go up. Parent sets position.**

*   **Distribute Space:** Use `Expanded` and `Flexible` within `Row`, `Column`, or `Flex` widgets.
    *   Use `Expanded` to force a child to fill all remaining available space (equivalent to `Flexible` with `fit: FlexFit.tight` and a `flex` factor of 1.0).
    *   Use `Flexible` to allow a child to size itself up to a specific limit while still expanding/contracting. Use the `flex` factor to define the ratio of space consumption among siblings.
*   **Constrain Width:** Prevent widgets from consuming all horizontal space on large screens. Wrap widgets like `GridView` or `ListView` in a `ConstrainedBox` or `Container` and define a `maxWidth` in the `BoxConstraints`.
*   **Lazy Rendering:** Always use `ListView.builder` or `GridView.builder` when rendering lists with an unknown or large number of items.

## Device and Orientation Behaviors
Ensure the app behaves correctly across all device form factors and input methods.

*   **Do not lock screen orientation.** Locking orientation causes severe layout issues on foldable devices, often resulting in letterboxing (the app centered with black borders). Android large format tiers require both portrait and landscape support.
*   **Fallback for Locked Orientation:** If business requirements strictly mandate a locked orientation, use the `Display API` to retrieve physical screen dimensions instead of `MediaQuery`. `MediaQuery` fails to receive the larger window size in compatibility modes.
*   **Support Multiple Inputs:** Implement support for basic mice, trackpads, and keyboard shortcuts. Ensure touch targets are appropriately sized and keyboard navigation is accessible.

## Workflow: Constructing an Adaptive Layout

Follow this workflow to implement a layout that adapts to the available `BoxConstraints`.

**Task Progress:**
- [ ] Identify the target widget that requires adaptive behavior.
- [ ] Wrap the widget tree in a `LayoutBuilder`.
- [ ] Extract the `constraints.maxWidth` from the builder callback.
- [ ] Define an adaptive breakpoint (e.g., `largeScreenMinWidth = 600`).
- [ ] **If `maxWidth > largeScreenMinWidth`:** Return a large-screen layout (e.g., a `Row` placing a navigation sidebar and content area side-by-side).
- [ ] **If `maxWidth <= largeScreenMinWidth`:** Return a small-screen layout (e.g., a `Column` or standard navigation-style approach).
- [ ] Run validator -> resize the application window -> review layout transitions -> fix overflow errors.

## Workflow: Optimizing for Large Screens

Follow this workflow to prevent UI elements from stretching unnaturally on large displays.

**Task Progress:**
- [ ] Identify full-width components (e.g., `ListView`, text blocks, forms).
- [ ] **If optimizing a list:** Convert `ListView.builder` to `GridView.builder` using `SliverGridDelegateWithMaxCrossAxisExtent` to automatically adjust column counts based on window size.
- [ ] **If optimizing a form or text block:** Wrap the component in a `ConstrainedBox`.
- [ ] Apply `BoxConstraints(maxWidth: [optimal_width])` to the `ConstrainedBox`.
- [ ] Wrap the `ConstrainedBox` in a `Center` widget to keep the constrained content centered on large screens.
- [ ] Run validator -> test on desktop/tablet target -> review horizontal stretching -> adjust `maxWidth` or grid extents.

## Examples

### Adaptive Layout using LayoutBuilder
Demonstrates switching between a mobile and desktop layout based on available width.

```dart
import 'package:flutter/material.dart';

const double largeScreenMinWidth = 600.0;

class AdaptiveLayout extends StatelessWidget {
  const AdaptiveLayout({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > largeScreenMinWidth) {
          return _buildLargeScreenLayout();
        } else {
          return _buildSmallScreenLayout();
        }
      },
    );
  }

  Widget _buildLargeScreenLayout() {
    return Row(
      children: [
        const SizedBox(width: 250, child: Placeholder(color: Colors.blue)),
        const VerticalDivider(width: 1),
        Expanded(child: const Placeholder(color: Colors.green)),
      ],
    );
  }

  Widget _buildSmallScreenLayout() {
    return const Placeholder(color: Colors.green);
  }
}
```

### Constraining Width on Large Screens
Demonstrates preventing a widget from consuming all horizontal space.

```dart
import 'package:flutter/material.dart';

class ConstrainedContent extends StatelessWidget {
  const ConstrainedContent({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(
            maxWidth: 800.0, // Maximum width for readability
          ),
          child: ListView.builder(
            itemCount: 50,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('Item $index'),
              );
            },
          ),
        ),
      ),
    );
  }
}
```

<!-- chapter:end slug=flutter-build-responsive-layout -->

---

<!-- chapter:begin slug=flutter-fix-layout-issues position=21 -->

## 21. flutter-fix-layout-issues

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-fix-layout-issues/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-fix-layout-issues/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-fix-layout-issues.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-fix-layout-issues
description: Fixes Flutter layout errors (overflows, unbounded constraints) using Dart and Flutter MCP tools. Use when addressing "RenderFlex overflowed", "Vertical viewport was given unbounded height", or similar layout issues.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 19:45:59 GMT
---
# Resolving Flutter Layout Errors

## Contents
- [Constraint Violation Diagnostics](#constraint-violation-diagnostics)
- [Layout Error Resolution Workflow](#layout-error-resolution-workflow)
- [Examples](#examples)

## Constraint Violation Diagnostics

Flutter layout operates on a strict rule: **Constraints go down. Sizes go up. Parent sets position.** Layout errors occur when this negotiation fails, typically due to unbounded constraints or unconstrained children. 

Diagnose layout failures using the following error signatures:

*   **"Vertical viewport was given unbounded height"**: Triggered when a scrollable widget (`ListView`, `GridView`) is placed inside an unconstrained vertical parent (`Column`). The parent provides infinite height, and the child attempts to expand infinitely.
*   **"An InputDecorator...cannot have an unbounded width"**: Triggered when a `TextField` or `TextFormField` is placed inside an unconstrained horizontal parent (`Row`). The text field attempts to determine its width based on infinite available space.
*   **"RenderFlex overflowed"**: Triggered when a child of a `Row` or `Column` requests a size larger than the parent's allocated constraints. Visually indicated by yellow and black warning stripes.
*   **"Incorrect use of ParentData widget"**: Triggered when a `ParentDataWidget` is not a direct descendant of its required ancestor. (e.g., `Expanded` outside a `Flex`, `Positioned` outside a `Stack`).
*   **"RenderBox was not laid out"**: A cascading side-effect error. Ignore this and look further up the stack trace for the primary constraint violation (usually an unbounded height/width error).

## Layout Error Resolution Workflow

Copy and use this checklist to systematically resolve layout constraint violations.

### Task Progress
- [ ] Run the application in debug mode to capture the exact layout exception in the console.
- [ ] Identify the primary error message (ignore cascading "RenderBox was not laid out" errors).
- [ ] Apply the conditional fix based on the specific error type:
  - **If "Vertical viewport was given unbounded height"**: Wrap the scrollable child (`ListView`, `GridView`) in an `Expanded` widget to consume remaining space, or wrap it in a `SizedBox` to provide an absolute height constraint.
  - **If "An InputDecorator...cannot have an unbounded width"**: Wrap the `TextField` or `TextFormField` in an `Expanded` or `Flexible` widget.
  - **If "RenderFlex overflowed"**: Constrain the overflowing child by wrapping it in an `Expanded` widget (to force it to fit) or a `Flexible` widget (to allow it to be smaller than the allocated space).
  - **If "Incorrect use of ParentData widget"**: Move the `ParentDataWidget` to be a direct child of its required parent. Ensure `Expanded`/`Flexible` are direct children of `Row`/`Column`/`Flex`. Ensure `Positioned` is a direct child of `Stack`.
- [ ] Execute Flutter hot reload.
- [ ] Run validator -> review errors -> fix: Inspect the UI to verify the red/grey error screen or yellow/black overflow stripes are resolved. If new layout errors appear, repeat the workflow.

## Examples

### Fixing Unbounded Height (ListView in Column)

**Input (Error State):**
```dart
// Throws "Vertical viewport was given unbounded height"
Column(
  children: <Widget>[
    const Text('Header'),
    ListView(
      children: const <Widget>[
        ListTile(title: Text('Item 1')),
        ListTile(title: Text('Item 2')),
      ],
    ),
  ],
)
```

**Output (Resolved State):**
```dart
// Wrap ListView in Expanded to constrain its height to the remaining Column space
Column(
  children: <Widget>[
    const Text('Header'),
    Expanded(
      child: ListView(
        children: const <Widget>[
          ListTile(title: Text('Item 1')),
          ListTile(title: Text('Item 2')),
        ],
      ),
    ),
  ],
)
```

### Fixing Unbounded Width (TextField in Row)

**Input (Error State):**
```dart
// Throws "An InputDecorator...cannot have an unbounded width"
Row(
  children: [
    const Icon(Icons.search),
    TextField(), 
  ],
)
```

**Output (Resolved State):**
```dart
// Wrap TextField in Expanded to constrain its width to the remaining Row space
Row(
  children: [
    const Icon(Icons.search),
    Expanded(
      child: TextField(),
    ),
  ],
)
```

### Fixing RenderFlex Overflow

**Input (Error State):**
```dart
// Throws "A RenderFlex overflowed by X pixels on the right"
Row(
  children: [
    const Icon(Icons.info),
    const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
  ],
)
```

**Output (Resolved State):**
```dart
// Wrap the Text widget in Expanded to force it to wrap within the available constraints
Row(
  children: [
    const Icon(Icons.info),
    Expanded(
      child: const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
    ),
  ],
)
```

<!-- chapter:end slug=flutter-fix-layout-issues -->

---

<!-- chapter:begin slug=flutter-implement-json-serialization position=22 -->

## 22. flutter-implement-json-serialization

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-implement-json-serialization/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-implement-json-serialization/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-implement-json-serialization.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-implement-json-serialization
description: Create model classes with `fromJson` and `toJson` methods using `dart:convert`. Use when manually mapping JSON keys to class properties for simple data structures.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 21:44:50 GMT
---
# Serializing JSON Manually in Flutter

## Contents
- [Core Guidelines](#core-guidelines)
- [Workflow: Implementing a Serializable Model](#workflow-implementing-a-serializable-model)
- [Workflow: Fetching and Parsing JSON](#workflow-fetching-and-parsing-json)
- [Examples](#examples)

## Core Guidelines

- **Import `dart:convert`**: Utilize Flutter's built-in `dart:convert` library for manual JSON encoding (`jsonEncode`) and decoding (`jsonDecode`).
- **Enforce Type Safety**: Always cast the `dynamic` result of `jsonDecode()` to the expected type, typically `Map<String, dynamic>` for objects or `List<dynamic>` for arrays.
- **Encapsulate Serialization Logic**: Define plain model classes containing properties corresponding to the JSON structure. Implement a `fromJson` factory constructor and a `toJson` method within the model.
- **Handle Background Parsing**: If parsing large JSON documents (execution time > 16ms), offload the parsing logic to a separate isolate using Flutter's `compute()` function to prevent UI jank.
- **Throw Exceptions on Failure**: When handling HTTP responses, throw an exception if the status code is not successful (e.g., not 200 OK or 201 Created). Do not return `null`.

## Workflow: Implementing a Serializable Model

Use this checklist to implement manual JSON serialization for a data model.

**Task Progress:**
- [ ] Define the plain model class with `final` properties.
- [ ] Implement the `factory Model.fromJson(Map<String, dynamic> json)` constructor.
- [ ] Implement the `Map<String, dynamic> toJson()` method.
- [ ] Write unit tests for both serialization methods.
- [ ] Run validator -> review type mismatch errors -> fix casting logic.

1. **Define the Model**: Create a class with properties matching the JSON keys.
2. **Implement `fromJson`**: Extract values from the `Map` and cast them to the appropriate Dart types. Use pattern matching or explicit casting.
3. **Implement `toJson`**: Return a `Map<String, dynamic>` mapping the class properties back to their JSON string keys.
4. **Validate**: Execute unit tests to ensure type safety, autocompletion, and compile-time exception handling function correctly.

## Workflow: Fetching and Parsing JSON

Use this conditional workflow when retrieving and parsing JSON from a network request.

**Task Progress:**
- [ ] Execute the HTTP request.
- [ ] Validate the response status code.
- [ ] Determine parsing strategy (Synchronous vs. Isolate).
- [ ] Decode and map the JSON to the model.

1. **Execute Request**: Use the `http` package to perform the network call.
2. **Validate Response**: 
   - If `response.statusCode == 200` (or 201 for POST), proceed to parsing.
   - If the status code indicates failure, throw an `Exception`.
3. **Determine Parsing Strategy**:
   - If parsing a **small payload** (e.g., a single object), parse synchronously on the main thread.
   - If parsing a **large payload** (e.g., an array of thousands of objects), use `compute(parseFunction, response.body)` to parse in a background isolate.
4. **Decode and Map**: Pass the decoded JSON to your model's `fromJson` constructor.

## Examples

### High-Fidelity Model Implementation

```dart
import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;

  const User({
    required this.id,
    required this.name,
    required this.email,
  });

  // Factory constructor for deserialization
  factory User.fromJson(Map<String, dynamic> json) {
    return switch (json) {
      {
        'id': int id,
        'name': String name,
        'email': String email,
      } => 
        User(
          id: id,
          name: name,
          email: email,
        ),
      _ => throw const FormatException('Failed to load User.'),
    };
  }

  // Method for serialization
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}
```

### Synchronous Parsing (Small Payload)

```dart
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<User> fetchUser(http.Client client, int userId) async {
  final response = await client.get(
    Uri.parse('https://api.example.com/users/$userId'),
    headers: {'Accept': 'application/json'},
  );

  if (response.statusCode == 200) {
    // Decode returns dynamic, cast to Map<String, dynamic>
    final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
    return User.fromJson(jsonMap);
  } else {
    throw Exception('Failed to load user');
  }
}
```

### Background Parsing (Large Payload)

```dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
  final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
  return parsed.map<User>((json) => User.fromJson(json)).toList();
}

Future<List<User>> fetchUsers(http.Client client) async {
  final response = await client.get(
    Uri.parse('https://api.example.com/users'),
    headers: {'Accept': 'application/json'},
  );

  if (response.statusCode == 200) {
    // Offload expensive parsing to a background isolate
    return compute(parseUsers, response.body);
  } else {
    throw Exception('Failed to load users');
  }
}
```

<!-- chapter:end slug=flutter-implement-json-serialization -->

---

<!-- chapter:begin slug=flutter-setup-declarative-routing position=23 -->

## 23. flutter-setup-declarative-routing

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-setup-declarative-routing/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-setup-declarative-routing/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-setup-declarative-routing.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-setup-declarative-routing
description: Configure `MaterialApp.router` using a package like `go_router` for advanced URL-based navigation. Use when developing web applications or mobile apps that require specific deep linking and browser history support.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 21:08:03 GMT
---
# Implementing Routing and Deep Linking

## Contents
- [Core Concepts](#core-concepts)
- [Workflow: Initializing the Application and Router](#workflow-initializing-the-application-and-router)
- [Workflow: Configuring Platform Deep Linking](#workflow-configuring-platform-deep-linking)
- [Workflow: Implementing Nested Navigation](#workflow-implementing-nested-navigation)
- [Examples](#examples)

## Core Concepts

Use the `go_router` package for declarative routing in Flutter. It provides a robust API for complex routing scenarios, deep linking, and nested navigation. 

- **GoRouter**: The central configuration object defining the application's route tree.
- **GoRoute**: A standard route mapping a URL path to a Flutter screen.
- **ShellRoute / StatefulShellRoute**: Wraps child routes in a persistent UI shell (e.g., a `BottomNavigationBar`). `StatefulShellRoute` maintains the state of parallel navigation branches.
- **Path URL Strategy**: Removes the default `#` fragment from web URLs, essential for clean deep linking across platforms.

## Workflow: Initializing the Application and Router

Follow this workflow to bootstrap a new Flutter application with `go_router` and configure the root routing mechanism.

### Task Progress
- [ ] Create the Flutter application.
- [ ] Add the `go_router` dependency.
- [ ] Configure the URL strategy for web/deep linking.
- [ ] Implement the `GoRouter` configuration.
- [ ] Bind the router to `MaterialApp.router`.

### 1. Scaffold the Application
Run the following commands to create the app and add the required routing package:
```bash
flutter create <app-name>
cd <app-name>
flutter pub add go_router
```

### 2. Configure the Router
Define a top-level `GoRouter` instance. Handle authentication or state-based routing using the `redirect` parameter.

```dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_web_plugins/url_strategy.dart';

void main() {
  // Use path URL strategy to remove the '#' from web URLs
  usePathUrlStrategy();
  runApp(const MyApp());
}

final GoRouter _router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
      routes: [
        GoRoute(
          path: 'details/:id',
          builder: (context, state) => DetailsScreen(id: state.pathParameters['id']!),
        ),
      ],
    ),
  ],
  errorBuilder: (context, state) => ErrorScreen(error: state.error),
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
      title: 'Routing App',
    );
  }
}
```

## Workflow: Configuring Platform Deep Linking

Configure the native platforms to intercept specific URLs and route them into the Flutter application.

### Task Progress
- [ ] Determine target platforms (iOS, Android, or both).
- [ ] Apply conditional configuration for Android (Manifest + Asset Links).
- [ ] Apply conditional configuration for iOS (Plist + Entitlements + AASA).
- [ ] Run validator -> review errors -> fix.

### If configuring for Android:
1. **Modify `AndroidManifest.xml`**: Add the intent filter inside the `<activity>` tag for `.MainActivity`.
```xml
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="http" android:host="yourdomain.com" />
    <data android:scheme="https" />
</intent-filter>
```
2. **Host `assetlinks.json`**: Serve the following JSON at `https://yourdomain.com/.well-known/assetlinks.json`.
```json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.yourcompany.yourapp",
    "sha256_cert_fingerprints": ["YOUR_SHA256_FINGERPRINT"]
  }
}]
```

### If configuring for iOS:
1. **Modify `Info.plist`**: Opt-in to Flutter's default deep link handler. 
*Note: If using a third-party deep linking plugin (e.g., `app_links`), set this to `NO` to prevent conflicts.*
```xml
<key>FlutterDeepLinkingEnabled</key>
<true/>
```
2. **Modify `Runner.entitlements`**: Add the associated domain.
```xml
<key>com.apple.developer.associated-domains</key>
<array>
  <string>applinks:yourdomain.com</string>
</array>
```
3. **Host `apple-app-site-association`**: Serve the following JSON (without a `.json` extension) at `https://yourdomain.com/.well-known/apple-app-site-association`.
```json
{
  "applinks": {
    "apps": [],
    "details": [{
      "appIDs": ["TEAM_ID.com.yourcompany.yourapp"],
      "paths": ["*"],
      "components": [{"/": "/*"}]
    }]
  }
}
```

### Validation Loop
Run validator -> review errors -> fix.
- **Android**: Test using ADB.
  ```bash
  adb shell 'am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://yourdomain.com/details/123"' com.yourcompany.yourapp
  ```
- **iOS**: Test using `xcrun` on a booted simulator.
  ```bash
  xcrun simctl openurl booted https://yourdomain.com/details/123
  ```

## Workflow: Implementing Nested Navigation

Use `StatefulShellRoute` to implement persistent UI shells (like a bottom navigation bar) that maintain the state of their child routes.

### Task Progress
- [ ] Define `StatefulShellRoute.indexedStack` in the `GoRouter` configuration.
- [ ] Create `StatefulShellBranch` instances for each navigation tab.
- [ ] Implement the shell widget using `StatefulNavigationShell`.

```dart
final GoRouter _router = GoRouter(
  initialLocation: '/home',
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        return ScaffoldWithNavBar(navigationShell: navigationShell);
      },
      branches: [
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/home',
              builder: (context, state) => const HomeScreen(),
            ),
          ],
        ),
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/settings',
              builder: (context, state) => const SettingsScreen(),
            ),
          ],
        ),
      ],
    ),
  ],
);
```

## Examples

### High-Fidelity Shell Widget Implementation
Implement the UI shell that consumes the `StatefulNavigationShell` to handle branch switching.

```dart
class ScaffoldWithNavBar extends StatelessWidget {
  const ScaffoldWithNavBar({
    required this.navigationShell,
    super.key,
  });

  final StatefulNavigationShell navigationShell;

  void _goBranch(int index) {
    navigationShell.goBranch(
      index,
      // Support navigating to the initial location when tapping the active tab.
      initialLocation: index == navigationShell.currentIndex,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: navigationShell,
      bottomNavigationBar: NavigationBar(
        selectedIndex: navigationShell.currentIndex,
        onDestinationSelected: _goBranch,
        destinations: const [
          NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
          NavigationDestination(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
    );
  }
}
```

### Programmatic Navigation
Use the `context.go()` and `context.push()` extension methods provided by `go_router`.

```dart
// Replaces the current route stack with the target route (Declarative)
context.go('/details/123');

// Pushes the target route onto the existing stack (Imperative)
context.push('/details/123');

// Navigates using a named route and path parameters
context.goNamed('details', pathParameters: {'id': '123'});

// Pops the current route
context.pop();
```

<!-- chapter:end slug=flutter-setup-declarative-routing -->

---

<!-- chapter:begin slug=flutter-setup-localization position=24 -->

## 24. flutter-setup-localization

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-setup-localization/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-setup-localization/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-setup-localization.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-setup-localization
description: Add `flutter_localizations` and `intl` dependencies, enable "generate true" in `pubspec.yaml`, and create an `l10n.yaml` configuration file. Use when initializing localization support for a new Flutter project.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 21:27:35 GMT
---
# Internationalizing Flutter Applications

## Contents
- [Core Concepts](#core-concepts)
- [Setup Workflow](#setup-workflow)
- [Implementation Workflow](#implementation-workflow)
- [Advanced Formatting](#advanced-formatting)
- [Examples](#examples)

## Core Concepts
Flutter handles internationalization (i18n) and localization (l10n) via the `flutter_localizations` and `intl` packages. The standard approach uses App Resource Bundle (`.arb`) files to define localized strings, which are then compiled into a generated `AppLocalizations` class for type-safe access within the widget tree.

## Setup Workflow

Copy and track this checklist when initializing internationalization in a Flutter project:

- [ ] **Task Progress**
  - [ ] 1. Add dependencies to `pubspec.yaml`.
  - [ ] 2. Enable the `generate` flag.
  - [ ] 3. Create the `l10n.yaml` configuration file.
  - [ ] 4. Configure `MaterialApp` or `CupertinoApp`.

### 1. Add Dependencies
Add the required localization packages to the project. Execute the following commands in the terminal:
```bash
flutter pub add flutter_localizations --sdk=flutter
flutter pub add intl:any
```

Verify your `pubspec.yaml` includes the following under `dependencies`:
```yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: any
```

### 2. Enable Code Generation
Open `pubspec.yaml` and enable the `generate` flag within the `flutter` section to automate localization tasks:
```yaml
flutter:
  generate: true
```

### 3. Create Configuration File
Create a new file named `l10n.yaml` in the root directory of the Flutter project. Define the input directory, template file, and output file:
```yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
synthetic-package: true
```

### 4. Configure the App Entry Point
Import the generated localizations and the `flutter_localizations` library in your `main.dart`. Inject the delegates and supported locales into your `MaterialApp` or `CupertinoApp`.

```dart
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // Adjust path if synthetic-package is false

// ... inside build method
return MaterialApp(
  localizationsDelegates: const [
    AppLocalizations.delegate,
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: const [
    Locale('en'), // English
    Locale('es'), // Spanish
  ],
  home: const MyHomePage(),
);
```

## Implementation Workflow

Follow this workflow when adding or modifying localized content.

### 1. Define ARB Files
*   **If creating NEW content:** Add the base string to the template file (`lib/l10n/app_en.arb`). Include a description for context.
*   **If EDITING existing content:** Locate the key in all supported `.arb` files and update the values.

```json
{
  "helloWorld": "Hello World!",
  "@helloWorld": {
    "description": "The conventional newborn programmer greeting"
  }
}
```

Create corresponding files for other locales (e.g., `app_es.arb`):
```json
{
  "helloWorld": "¡Hola Mundo!"
}
```

### 2. Generate Localization Classes
Run the following command to trigger code generation:
```bash
flutter pub get
```
*Feedback Loop:* Run validator -> review terminal output for ARB syntax errors -> fix missing commas or mismatched placeholders -> re-run `flutter pub get`.

### 3. Consume Localized Strings
Access the localized strings in your widget tree using `AppLocalizations.of(context)`. Ensure the widget calling this is a descendant of `MaterialApp`.

```dart
Text(AppLocalizations.of(context)!.helloWorld)
```

## Advanced Formatting

Use placeholders for dynamic data, plurals, and conditional selects.

### Placeholders
Define parameters within curly braces and specify their type in the metadata object.
```json
"hello": "Hello {userName}",
"@hello": {
  "description": "A message with a single parameter",
  "placeholders": {
    "userName": {
      "type": "String",
      "example": "Bob"
    }
  }
}
```

### Plurals
Use the `plural` syntax to handle quantity-based string variations. The `other` case is mandatory.
```json
"nWombats": "{count, plural, =0{no wombats} =1{1 wombat} other{{count} wombats}}",
"@nWombats": {
  "description": "A plural message",
  "placeholders": {
    "count": {
      "type": "num",
      "format": "compact"
    }
  }
}
```

### Selects
Use the `select` syntax for conditional strings, such as gendered text.
```json
"pronoun": "{gender, select, male{he} female{she} other{they}}",
"@pronoun": {
  "description": "A gendered message",
  "placeholders": {
    "gender": {
      "type": "String"
    }
  }
}
```

## Examples

### Complete `l10n.yaml`
```yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
synthetic-package: true
use-escaping: true
```

### Complete Widget Implementation
```dart
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class GreetingWidget extends StatelessWidget {
  final String userName;
  final int notificationCount;

  const GreetingWidget({
    super.key, 
    required this.userName, 
    required this.notificationCount,
  });

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Column(
      children: [
        Text(l10n.hello(userName)),
        Text(l10n.nWombats(notificationCount)),
      ],
    );
  }
}
```

<!-- chapter:end slug=flutter-setup-localization -->

---

<!-- chapter:begin slug=flutter-use-http-package position=25 -->

## 25. flutter-use-http-package

- **Source:** https://github.com/flutter/agent-plugins/blob/main/skills/flutter-use-http-package/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/skills/flutter-use-http-package/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/flutter-use-http-package.md
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: flutter-use-http-package
description: Use the `http` package to execute GET, POST, PUT, or DELETE requests. Use when you need to fetch from or send data to a REST API.
metadata:
  model: models/gemini-3.1-pro-preview
  last_modified: Tue, 21 Apr 2026 21:36:42 GMT
---
# Implementing Flutter Networking

## Contents
- [Configuration & Permissions](#configuration--permissions)
- [Request Execution & Response Handling](#request-execution--response-handling)
- [Background Parsing](#background-parsing)
- [Workflow: Executing Network Operations](#workflow-executing-network-operations)
- [Examples](#examples)

## Configuration & Permissions

Configure the environment and platform-specific permissions required for network access.

1. Add the `http` package dependency via the terminal:
   ```bash
   flutter pub add http
   ```
2. Import the package in your Dart files:
   ```dart
   import 'package:http/http.dart' as http;
   ```
3. Configure Android permissions by adding the Internet permission to `android/app/src/main/AndroidManifest.xml`:
   ```xml
   <uses-permission android:name="android.permission.INTERNET" />
   ```
4. Configure macOS entitlements by adding the network client key to both `macos/Runner/DebugProfile.entitlements` and `macos/Runner/Release.entitlements`:
   ```xml
   <key>com.apple.security.network.client</key>
   <true/>
   ```

## Request Execution & Response Handling

Execute HTTP operations and map responses to strongly typed Dart objects.

*   **URIs:** Always parse URL strings using `Uri.parse('your_url')`.
*   **Headers:** Inject authorization and content-type headers via the `headers` parameter map. Use `HttpHeaders.authorizationHeader` for auth tokens.
*   **Payloads:** For POST and PUT requests, encode the body using `jsonEncode()` from `dart:convert`.
*   **Status Validation:** Evaluate `response.statusCode`. Treat `200 OK` (GET/PUT/DELETE) and `201 CREATED` (POST) as success. 
*   **Error Handling:** Throw explicit exceptions for non-success status codes. Never return `null` on failure, as this prevents `FutureBuilder` from triggering its error state and causes infinite loading indicators.
*   **Deserialization:** Parse the raw string using `jsonDecode(response.body)` and map it to a custom Dart object using a factory constructor (e.g., `fromJson`).

## Background Parsing

Offload expensive JSON parsing to a separate Isolate to prevent UI jank (frame drops).

*   Import `package:flutter/foundation.dart`.
*   Use the `compute()` function to run the parsing logic in a background isolate.
*   Ensure the parsing function passed to `compute()` is a top-level function or a static method, as closures or instance methods cannot be passed across isolates.

## Workflow: Executing Network Operations

Use the following checklist to implement and validate network operations.

**Task Progress:**
- [ ] 1. Define the strongly typed Dart model with a `fromJson` factory constructor.
- [ ] 2. Implement the network request method returning a `Future<Model>`.
- [ ] 3. Apply conditional logic based on the operation type:
  - **If fetching data (GET):** Append query parameters to the URI.
  - **If mutating data (POST/PUT):** Set `'Content-Type': 'application/json; charset=UTF-8'` and attach the `jsonEncode` body.
  - **If deleting data (DELETE):** Return an empty model instance on success (`200 OK`).
- [ ] 4. Validate the `statusCode` and throw an `Exception` on failure.
- [ ] 5. Integrate the `Future` into the UI using `FutureBuilder`.
- [ ] 6. Handle `snapshot.hasData`, `snapshot.hasError`, and default to a `CircularProgressIndicator`.
- [ ] 7. **Feedback Loop:** Run the app -> trigger the network request -> review console for unhandled exceptions -> fix parsing or permission errors.

## Examples

### High-Fidelity Implementation: Fetching and Parsing in the Background

```dart
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

// 1. Top-level parsing function for Isolate
List<Photo> parsePhotos(String responseBody) {
  final parsed = (jsonDecode(responseBody) as List<Object?>)
      .cast<Map<String, Object?>>();
  return parsed.map<Photo>(Photo.fromJson).toList();
}

// 2. Network execution with background parsing
Future<List<Photo>> fetchPhotos() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/photos'),
    headers: {
      HttpHeaders.authorizationHeader: 'Bearer your_token_here',
      HttpHeaders.acceptHeader: 'application/json',
    },
  );

  if (response.statusCode == 200) {
    // Offload heavy parsing to a background isolate
    return compute(parsePhotos, response.body);
  } else {
    throw Exception('Failed to load photos. Status: ${response.statusCode}');
  }
}

// 3. Strongly typed model
class Photo {
  final int id;
  final String title;
  final String thumbnailUrl;

  const Photo({
    required this.id,
    required this.title,
    required this.thumbnailUrl,
  });

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as int,
      title: json['title'] as String,
      thumbnailUrl: json['thumbnailUrl'] as String,
    );
  }
}

// 4. UI Integration
class PhotoGallery extends StatefulWidget {
  const PhotoGallery({super.key});

  @override
  State<PhotoGallery> createState() => _PhotoGalleryState();
}

class _PhotoGalleryState extends State<PhotoGallery> {
  late Future<List<Photo>> _futurePhotos;

  @override
  void initState() {
    super.initState();
    // Initialize Future once to prevent re-fetching on rebuilds
    _futurePhotos = fetchPhotos();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Photo>>(
      future: _futurePhotos,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final photos = snapshot.data!;
          return ListView.builder(
            itemCount: photos.length,
            itemBuilder: (context, index) => ListTile(
              leading: Image.network(photos[index].thumbnailUrl),
              title: Text(photos[index].title),
            ),
          );
        } else if (snapshot.hasError) {
          return Center(child: Text('Error: ${snapshot.error}'));
        }
        
        // Default loading state
        return const Center(child: CircularProgressIndicator());
      },
    );
  }
}
```

<!-- chapter:end slug=flutter-use-http-package -->

---

## Part: Credited skills

---

<!-- chapter:begin slug=api-review position=26 -->

## 26. api-review

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/api-review/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/api-review/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/api-review.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (1), referenced from this skill's directory:
  - `references/canonical_api_design.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/api-review/references/canonical_api_design.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: api-review
description: Reviews the specified code against the canonical API Design guidelines. Use this skill when the user asks for an API review or to check code against API design principles.
---

# API review skill

This skill reviews code against the canonical API Design guidelines.

## Instructions

1. **Load Guidelines**: Read the API design guidelines from [references/canonical_api_design.md](references/canonical_api_design.md) to ensure they are fully available in the context.
2. **Identify Target**: Identify the code to review.
   - If the user specified files (e.g., "review main.dart"), use those.
   - If the user has an open file in their context, assume that is the target.
   - If neither, ask the user to specify the target files.
3. **Analyze**: For each target file, perform a deep analysis against the "Foundations of Canonical API Design Principles" (loaded in step 1), specifically looking for:
   - **Contract-First**: Is the interface clear and decoupled from implementation?
   - **KISS/YAGNI**: Are there unnecessary parameters or over-generalized features?
   - **Ergonomics**: Are names intent-revealing? Do they follow the Principle of Least Astonishment?
   - **CQS**: Are commands and queries separated?
   - **Safety**: Are types used strictly (Enums vs Strings)? Is validation visible?
   - **Explicit Configuration**: Are dependencies explicitly injected rather than implicitly resolved via global state, registries, or environment variables?
4. **Report**: Generate a structured report:
   - **Score**: Give a letter grade (A-F) based on alignment.
   - **Critical Issues**: Violations that _must_ be fixed (e.g., severe strictness or safety issues).
   - **Suggestions**: Ergonomic improvements (renaming, rearranging).
   - **Code Examples**: Provide `before` vs `after` code blocks for the suggested improvements.
   - Save the report as a markdown artifact in the conversation artifacts directory (e.g., `<appDataDir>/brain/<conversation-id>/api_review_results.md`).

<!-- chapter:end slug=api-review -->

---

<!-- chapter:begin slug=code-documentation position=27 -->

## 27. code-documentation

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/code-documentation/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-documentation/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/code-documentation.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (3), referenced from this skill's directory:
  - `references/dart.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-documentation/references/dart.md
  - `references/python.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-documentation/references/python.md
  - `references/typescript.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-documentation/references/typescript.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: code-documentation
description: Guide for writing effective code documentation, including docstrings, JSDoc, dartdoc, and implementation comments. Use this skill when writing new code, adding features, or improving existing documentation in Dart, Python, or TypeScript to ensure clarity and maintainability.
---

# Code Documentation Skill

This skill provides comprehensive guidelines for documenting code, prioritizing user-centric writing, clarity, and consistency.

## 1. General Philosophy

- **User-Centric**: Write for the person using your API. If you had to look up how to use something, document it so others don't have to.
- **Explain "Why"**: Explain _why_ code exists and _how_ to use it effectively, since the code signature already tells _what_ it does.
- **Be Concise**: Omit fluff. Avoid merely restating the code name, as it is not helpful.
- **Consistency**: Use standard terminology and consistent formatting.
- **Public APIs**: Document all public APIs (classes, members, top-level functions) without exception.
- **Code Samples**: Strongly consider adding code samples to explain usage.

## 2. General Structure

Follow this general structure for documentation comments across languages:

1.  **Summary Sentence**: Start with a single-sentence summary on the first line, ending with a period.
2.  **Blank Line**: Follow the summary with a blank line.
3.  **Details**: Add paragraphs, code samples, or lists as needed to explain parameters, return values, exceptions, and behavior.
4.  **Annotations**: Place doc comments **before** any metadata annotations.

## 3. Writing Guidelines

### Brevity & Style

- **Avoid Fluff**: Omit "This class...", "This method...", "Is used to...", "Note that...".
  - _Bad_: "This method is used to calculate the total."
  - _Good_: "Calculates the total."
- **Third-Person Verbs**: Start function/method docs with a third-person singular verb.
  - _Examples_: "Returns...", "Calculates...", "Updates...", "Creates...".
- **Noun Phrases**: Start variable/property docs with a noun phrase.
  - _Examples_: "The current color.", "A list of active users.".
- **Booleans**: Always start with "Whether" (or similar clear indicator).
  - _Good_: "Whether this widget is enabled."
  - _Bad_: "If this widget is enabled...", "True if...", "Flag to indicate...".
- **Avoid Jargon**: Use plain English unless the term is a widely accepted standard (e.g., "HTTP", "URL").

### Formatting

- **Sparingly**: Use Markdown features (bold, lists) sparingly.
- **No HTML**: Avoid HTML unless strictly necessary and supported by the documentation tool.
- **Parameters/Returns/Exceptions**: Use prose to describe parameters, return values, and thrown exceptions. Do not rely solely on tags like `@param` unless mandated by the language standard (e.g., Javadoc).

## 4. Implementation Comments

Ensure implementation comments (`//`) are accurate, relevant, factual, and provide information that is not readily understandable from the code. Remove or reword comments that do not meet these criteria. If an implementation comment provides information useful to an API consumer that is not already in the documentation comments, move it to the documentation comments.

## 5. Review Checklist

Use this checklist to verify your documentation:

1.  [ ] **Summary**: Ensure every public member starts with a one-sentence summary ending in a period.
2.  [ ] **Brevity**: Remove "This class..." or "This function..." fluff.
3.  [ ] **Completeness**: Document strict constraints (e.g., "must not be null") and exceptions.
4.  [ ] **Examples**: Consider adding a code sample for complex widgets or methods.

## 6. Language Specific Instructions

Refer to the language guides for detailed instructions on structure, linking, and framework-specific patterns:

- **Dart / Flutter**: [references/dart.md](references/dart.md)
- **TypeScript / JavaScript**: [references/typescript.md](references/typescript.md)
- **Python**: [references/python.md](references/python.md)

<!-- chapter:end slug=code-documentation -->

---

<!-- chapter:begin slug=code-review position=28 -->

## 28. code-review

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/code-review/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/code-review.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (5), referenced from this skill's directory:
  - `references/critique_rules.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/references/critique_rules.md
  - `references/review_criteria.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/references/review_criteria.md
  - `references/reviewing_tests.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/references/reviewing_tests.md
  - `references/splitting_reviews.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/references/splitting_reviews.md
  - `scripts/split_diff.py` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/code-review/scripts/split_diff.py

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: code-review
description: Performs a comprehensive, multi-step code review of pull requests or local code changes, using iterative refinement (generation, critique, synthesis) to ensure high-quality, actionable feedback. Use when you need to review code changes thoroughly.
---

# Comprehensive Code Review

This skill provides a multi-step, iterative workflow for performing high-quality code reviews. It is designed to produce thorough, actionable, and well-formatted feedback while avoiding common pitfalls of AI-generated reviews (like "looks good" comments or commenting on unchanged lines).

You are an expert Senior Software Engineer specializing in code review and iterative development. Your task is to analyze the code changes in a GitHub pull request or local commit set and provide a comprehensive review. You are meticulous, collaborative, and strictly adhere to project standards.

## Core Principles

- **Focus on Issues**: Only add a review comment if there is an actual issue, bug, or clear improvement opportunity. Do not add comments to validate or explain code.
- **Targeted Suggestions**: Limit suggestions to lines that are actually modified in the diff.
- **Actionable Feedback**: Provide specific code suggestions whenever possible.
- **Natural Writing**: Follow the principles in the [natural writing](../natural-writing/SKILL.md) skill for all written feedback.
- **Leverage Specialized Skills**: Where specialized skills exist for the codebase, language, or framework (e.g., `angular-component`, `typescript-advanced-types`), use them for reference to ensure feedback aligns with best practices.

## Workflow

Follow these steps sequentially to perform a comprehensive review:

### Step 1: Gather Changes

Before starting the review, gather the changes to be reviewed.

- **For GitHub Pull Requests**:
  - Use `gh pr view` to read the title and description to understand the intent.
  - Use `gh pr diff` to get the actual code changes.
  - _Reference: See the gh-cli skill for detailed usage._
- **For Local Changes**:
  - Use `git status` to see modified files.
  - Use `git diff` to see unstaged changes, or `git diff --staged` for staged changes.
  - Use `git log -p` to see recent commits if reviewing a local branch.

### Step 2: Context Enrichment

Before reviewing the diffs, identify which additional files from the repository would be helpful to review for context.
Consider:

- Files that are imported or referenced.
- Parent classes or interfaces.
- Related utility files.
- Test files corresponding to changed files.

_Reference: Use the guidelines in [splitting_reviews.md](references/splitting_reviews.md) if the review needs to be subdivided._

### Step 3: Generate Initial Review

Generate review comments focusing on the following criteria:

- **Correctness**: Verify functionality, handle edge cases, check API usage.
- **Efficiency**: Identify bottlenecks, redundant calculations.
- **Maintainability**: Assess readability, adherence to style guides.
- **Security**: Identify potential vulnerabilities.

**Guidelines**:

- Use the vetted criteria in [review_criteria.md](references/review_criteria.md).
- Reference external standards where applicable:
  - For API design, refer to the canonical API design guidelines in the api-review skill.
  - For documentation, refer to the code-documentation skill.
- **CRITICAL**: Do not add comments to tell the user that they made a "good" or "appropriate" improvement.

### Step 4: Critique and Refine (Review the Review)

Perform a self-critique pass on the generated comments.
Filter out or modify comments based on the rules in [critique_rules.md](references/critique_rules.md).
Ensure that:

- Comments are only on lines that begin with `+` or `-` in the diff.
- Comments are not merely informational or complimentary.
- Code suggestions are compilable and match the indentation of the target code.

### Step 5: Synthesis (Final Review)

Combine the refined comments into a final output.

- Deduplicate overlapping comments.
- Prioritize high-severity issues (critical, high).
- **Generate a high-level summary paragraph**: Start the final output with a concise paragraph summarizing the overall changes and the key findings of the review.
- **Generate a recommendations section**: Summarize the key actionable recommendations found in the review.
- **Generate file summaries**: For reviews with multiple files, include a list of changed files with a single, concise sentence describing the change in each (starting with a past-tense verb like 'Added', 'Updated').
- When writing file paths, write them as Markdown links.
- Ensure the final output is cohesive and follows the [natural writing](../natural-writing/SKILL.md) skill.

## Output Format

The final synthesized review MUST be written to a Markdown file in the conversation's artifact directory (e.g., `review_results.md` in `<appDataDir>/brain/<conversation-id>/`) and also displayed to the user.

The review file should contain:
1. The high-level summary paragraph.
2. File summaries (if applicable).
3. The list of review comments, ordered by severity.
4. A recommendations section summarizing key actionable feedback.

Each review comment in the list should specify:
- **File**: The path to the file.
- **Line**: The line number (anchored to the diff).
- **Severity**: `critical`, `high`, `medium`, or `low`.
- **Body**: The explanation of the issue.
- **Suggestion**: (Optional) The specific code replacement.

<!-- chapter:end slug=code-review -->

---

<!-- chapter:begin slug=grill-with-docs position=29 -->

## 29. grill-with-docs

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/grill-with-docs/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/grill-with-docs/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/grill-with-docs.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

Bundled files (2), referenced from this skill's directory:
  - `ADR-FORMAT.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/grill-with-docs/ADR-FORMAT.md
  - `CONTEXT-FORMAT.md` — https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/grill-with-docs/CONTEXT-FORMAT.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: grill-with-docs
description: Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise. Use when user wants to stress-test a plan against their project's language and documented decisions.
---

<what-to-do>

Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.

Ask the questions one at a time, waiting for feedback on each question before continuing.

If a question can be answered by exploring the codebase, explore the codebase instead.

</what-to-do>

<supporting-info>

## Domain awareness

During codebase exploration, also look for existing documentation:

### File structure

Most repos have a single context:

```
/
├── CONTEXT.md
├── docs/
│   └── adr/
│       ├── 0001-event-sourced-orders.md
│       └── 0002-postgres-for-write-model.md
└── src/
```

If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:

```
/
├── CONTEXT-MAP.md
├── docs/
│   └── adr/                          ← system-wide decisions
├── src/
│   ├── ordering/
│   │   ├── CONTEXT.md
│   │   └── docs/adr/                 ← context-specific decisions
│   └── billing/
│       ├── CONTEXT.md
│       └── docs/adr/
```

Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.

## During the session

### Challenge against the glossary

When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"

### Sharpen fuzzy language

When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."

### Discuss concrete scenarios

When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.

### Cross-reference with code

When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"

### Update CONTEXT.md inline

When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).

Don't couple `CONTEXT.md` to implementation details. Only include terms that are meaningful to domain experts.

### Offer ADRs sparingly

Only offer to create an ADR when all three are true:

1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons

If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).

</supporting-info>

<!-- chapter:end slug=grill-with-docs -->

---

<!-- chapter:begin slug=natural-writing position=30 -->

## 30. natural-writing

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/natural-writing/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/natural-writing/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/natural-writing.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: natural-writing
description: Contains well-defined rules for creating natural, accurate, and readable writing. Use whenever authoring longer text, like analysis documents, PR or CL descriptions, or documentation.
---
# Rules for Natural Writing

This document outlines strict rules to avoid common "AI-isms"—stylistic and structural patterns that language models typically fall into. Follow these rules to produce content that is more understandable, and reads as natural, human-authored text.

## 1. Vocabulary & Phrasing Controls

### The "Banned" List

Avoid these words, which are statistically overrepresented in AI text. Use simpler, more direct alternatives.

* **Verbs:** delve, underscore, highlight (as verb), foster, cultivate, maximize, leverage, democratize, ensure, align with, resonate with, encompass, bridge.  
* **Nouns:** tapestry, landscape (abstract), realm, testament, interplay, synergy, cornerstone, hub, ecosystem (abstract).  
* **Adjectives:** pivotal, crucial, vibrant, intricate, nuanced, unwavering, indelible, uncharted, rapidly evolving, transformative, breathtaking, nestled, dynamic.

### Avoid "Copula" Substitutions

Do not replace simple "is/are" verbs with flowery equivalents.

* **Bad:** "The library *serves as* a center for learning."  
* **Bad:** "The statue *stands as* a monument to..."  
* **Good:** "The library *is* a center for learning."  
* **Good:** "The statue *is* a monument to..."

### Eliminate "Elegant Variation"

Do not use synonyms just to avoid repeating a subject's name (e.g., "the eponymous character," "the titular protagonist," "the celebrated author"). It is acceptable to repeat the name or use pronouns naturally.

### Banned Temporal Words in Code & Comments

Do not use relative temporal terms in code, variable names, function names, or comments. These words lose their meaning as the codebase evolves over time.
* **Banned Words**: now, currently, existing behavior, previous behavior, old, new, modern.
* **Bad**: `// This function now uses the config parser instead of hardcoding.`
* **Good**: `// Resolves paths via [ConfigParser.loadConfig] to support custom config locations.`

## 2. Content & Tone

### No "Puffery" or Forced Significance

Do not inflate the importance of a topic with vague praise. If a subject is important, the facts should demonstrate it without help.

* **Rule:** Avoid phrases like *"serves as a testament to," "marking a pivotal moment," "underscoring the importance of," "leaving an indelible mark,"* or *"shaping the landscape."*  
* **Bad:** "The founding of the institute marked a pivotal moment in the evolution of regional statistics, representing a significant shift toward independence."  
* **Good:** "The institute was founded in 1989 to collect regional statistics."

### No Superficial Analysis

Avoid attaching "dangling" present-participle phrases that offer vague commentary.

* **Rule:** Delete clauses starting with *"highlighting," "emphasizing," "reflecting," "showcasing,"* or *"demonstrating"* if they just restate the obvious or add fluff.  
* **Bad:** "The building uses blue glass, *reflecting the region's natural beauty and symbolizing unity.*"  
* **Good:** "The building uses blue glass."

### Avoid Promotional Language

Maintain a neutral tone. Avoid "advertisement" words.

* **Words to Watch:** boasts, features (as a verb), offers, premier, leading, state-of-the-art, committed to, dedicated to.  
* **Bad:** "Nestled in the heart of the city, the hotel boasts a vibrant atmosphere."  
* **Good:** "The hotel is located in the city center."

### No "Challenges and Future Outlook" Formula

LLMs often end articles with a generic "Despite challenges... remains important" conclusion.

* **Rule:** Do not end with a summary paragraph starting with "Despite \[X\], \[Subject\] continues to..." or speculating on the future. End with the last fact.  
* **Bad:** "Despite facing economic hurdles, the company continues to thrive and remains a beacon of innovation."

### No "Title as Proper Noun" Leads

Do not treat a descriptive article title (like a list or broad topic) as a proper noun in the first sentence.

* **Bad:** "*The List of songs about Mexico* is a curated compilation..."  
* **Good:** "This list contains songs about Mexico..."

### No Generic "See Also" Links

Do not populate "See Also" sections with broad, generic terms.

* **Rule:** Links must be directly relevant and specific to the subject.  
* **Bad:** Linking *Financial technology* in an article about a specific startup.  
* **Good:** Linking a competitor or specific related technology.

### Attribution Precision

Do not use vague "weasel words."

* **Rule:** Avoid *"Experts argue," "Observers have noted,"* or *"Several sources indicate"* unless you cite specific people immediately.  
* **Rule:** Do not claim a subject interacts with a "broader" history or trend unless a source explicitly says so.

## 3. Sentence Structure

### No Negative Parallelism

Avoid sentences that structure a contrast unnecessarily.

* **Bad:** "It is *not only* a painting, *but also* a representation of..."  
* **Bad:** "It is *not* just about X; *it is* about Y."  
* **Good:** "It is a painting that represents..."

### No "Rule of Three"

Avoid listing exactly three adjectives or three noun phrases to sound "comprehensive."

* **Bad:** "The event brings together *marketers, engineers, and designers*." (Unless those specific three groups are the *only* ones).  
* **Bad:** "It is *bold, innovative, and unique*."

### No False Ranges

Do not use "from X to Y" unless X and Y are endpoints of a logical scale (like time or size).

* **Bad:** "The book covers everything *from* biology *to* space travel." (These are just two random topics, not a range).  
* **Good:** "The book covers topics including biology and space travel."

## 4. Structure & Formatting

### Headers

* **Rule:** Use Sentence case for headers (e.g., "Early life," not "Early Life").  
* **Rule:** Do not use "Title Case" in headers.

### Formatting Avoidance

* **No Inline-Header Lists:** Do not use the format: `* **Header:** Description...`. Use prose or simple lists.  
* **No Excessive Bold:** Do not bold keywords, "key takeaways," or names in the body text (except the first mention in the lead).  
* **No Symbols/Emojis:** Do not use emojis (🚀, 🧠) or unusual bullets (`#`, `-`) in lists. Use standard bullets (`*`).  
* **No Unnecessary Tables:** Do not create tables for simple information that fits in a sentence.  
* **Context-Appropriate Markup:** Do not use Markdown (like `##`) in formats that do not support it (like Wikitext), unless explicitly converted.

### Punctuation

* **Quotes:** Use straight quotes (`"`, `'`) and straight apostrophes (`'`). Do not use curly/smart quotes (`“`, `’`).  
* **Em Dashes:** Use em dashes sparingly. LLMs overuse them for emphasis. Use commas or parentheses instead.

## 5. Citations & Integrity

### No Hallucinations

* **Rule:** Never generate a citation unless you are looking at the source.  
* **Rule:** Do not invent URLs or DOIs.  
* **Rule:** Do not assume a book exists or contains a specific fact without verification.

## 6. Communication (Chat Context)

* **No "Collaborative" Filler:** Avoid starting responses with *"Certainly\!", "Here is the information,"* or *"I hope this helps."* Just provide the content.  
* **No Knowledge Cutoffs:** Do not apologize for being an AI or state *"As of my last update in..."* unless relevant to a specific time-sensitive fact.  
* **No Subject Lines:** Do not preface a response with `Subject: ...`  
* **Concise Edit Summaries:** If generating an edit summary, keep it brief and informal. Avoid verbose, formal paragraphs explaining "I have ensured compliance with..."

<!-- chapter:end slug=natural-writing -->

---

<!-- chapter:begin slug=unix-cli-best-practices position=31 -->

## 31. unix-cli-best-practices

- **Source:** https://github.com/flutter/agent-plugins/blob/main/.agents/agents/reidbaker-agent/skills/unix-cli-best-practices/SKILL.md
- **Raw:** https://raw.githubusercontent.com/flutter/agent-plugins/main/.agents/agents/reidbaker-agent/skills/unix-cli-best-practices/SKILL.md
- **Markdown:** https://skillsdocs.com/flutter/agent-plugins/unix-cli-best-practices.md
- **Origin:** Credited — installed into this repository, not published from it.
- **Licence:** BSD-3-Clause — https://spdx.org/licenses/BSD-3-Clause.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: unix-cli-best-practices
description: Safe, portable, and efficient command-line patterns for macOS/BSD Unix tools (grep, find, sed, awk, xargs, mdfind, pbcopy, open) and modern alternatives (ripgrep, fd). Covers common shell scripting and one-liner use cases including fast searching, text processing, codebase navigation, and parallel execution.
---

# Unix CLI best practices

This guide provides efficient, safe, and portable techniques for manipulating text and finding files from the command line on macOS. By default, macOS uses BSD-derived UNIX utilities (`grep`, `find`, `sed`, `awk`) which have subtle differences from their GNU/Linux counterparts.

When possible, use high-performance replacements (`ripgrep` and `fd`) which respect `.gitignore` rules by default and offer more ergonomic interfaces.

## Modern high-performance alternatives

Use these tools instead of standard BSD utilities for local codebase operations.

### ripgrep (`rg`)

Use `ripgrep` (`rg`) as the preferred tool for searching text. It is faster than standard `grep` and respects `.gitignore` rules by default.

Common use cases:
* Run `rg 'search_term'` to recursively search the current directory.
* Run `rg -S 'term'` to search case-insensitively unless the query contains uppercase letters. Use `rg -i 'term'` for strict case-insensitivity.
* Run `rg -g '*.ts' -g '!*.spec.ts' 'term'` to search `.ts` files while excluding `.spec.ts` files.
* Run `rg -v 'ignore_me'` to print lines that do not match the pattern.
* Run `rg -l 'term'` to list only the names of matching files. Combine with `rg -0` for null-terminated output suitable for `xargs`.
* Run `rg -F 'foo()'` to treat the search pattern as a fixed string rather than a regular expression.
* Run `rg -w 'const'` to match whole words only.
* Run `rg -C 2 'term'` to show two lines of surrounding context. Use `rg -B 2` for preceding context or `rg -A 2` for succeeding context.

Refer to `rg --help` for the complete options list.

### fd

Use `fd` as the preferred tool for traversing the filesystem and finding files. It is faster than standard `find` and respects `.gitignore` rules by default.

Common use cases:
* Run `fd 'pattern'` to find files matching the regex pattern anywhere in their path.
* Run `fd -e py -e txt` to filter results by file extensions.
* Run `fd -t d 'docs'` to find directories. Use `fd -t f` for files and `fd -t l` for symbolic links.
* Run `fd -H` to include hidden files, or `fd -I` to include ignored files (such as `node_modules`). Combine as `fd -HI` to search all files.
* Run `fd -p 'src/assets'` to match the pattern against the full path instead of just the filename.
* Run `fd -e log -x rm` to execute a command on each matching file individually. Use `-X` (e.g., `fd -e log -X rm`) to run the command once with all matching files as arguments.
* Run `fd -a 'pattern'` to return absolute paths instead of relative paths.

Refer to `fd --help` for the complete options list.

## Built-in tools for macOS and BSD

Use these built-in utilities only when `rg` and `fd` are unavailable. Apply precise filters to prevent performance degradation.

### Efficient searching with grep

Do not use `grep | grep -v 'unwanted_dir'` to exclude directories. This approach reads all files before filtering them. Use native exclusion arguments instead to exclude directories at the filesystem level:

```bash
# Slow: reads binary and ignored files
grep -R "pattern" . | grep -v "node_modules"

# Fast: skips the directory completely at the filesystem level
grep -R --exclude-dir=node_modules --exclude-dir=.git "pattern" .
```

Common `grep` flags:
* `-r` or `-R` to search recursively. `-R` follows symbolic links, while `-r` does not.
* `-I` to ignore binary files for faster execution and clean output.
* `--exclude="*.min.js"` to ignore files matching a specific glob.
* `--include="*.dart"` to search only files matching a specific glob.
* `-l` to print only the names of files containing matches.
* `-Z` to print a null character after each filename, which is useful when piping to `xargs -0`.

Example of safely deleting files containing a specific string:
```bash
grep -rlZ -I --exclude-dir=node_modules "DEPRECATED_API" . | xargs -0 rm
```

### High-performance traversal with find

Prevent `find` from traversing irrelevant directory trees by using the `-prune` option.

```bash
# Slow: traverses node_modules entirely, then filters output
find . -name "*.ts" | grep -v "node_modules"

# Fast: skips node_modules entirely
find . -name "node_modules" -prune -o -name "*.ts" -print
```

The expression `-name "node_modules" -prune` stops traversal when encountering a `node_modules` directory. The `-o` (OR) operator specifies that for any other directory or file ending in `.ts`, the path is printed.

### macOS portability with sed

macOS uses BSD `sed`, which differs from GNU `sed` in its handling of in-place editing.

Use the `-i` option with an explicit backup extension. To edit in-place without creating a backup, provide an empty string:

```bash
# Edit in-place without creating a backup
sed -i '' 's/oldName/newName/g' filename.txt

# Edit in-place and create a backup named filename.txt.bak
sed -i '.bak' 's/oldName/newName/g' filename.txt
```

Use the `-E` option to enable extended regular expressions, avoiding the need to escape parentheses and plus signs:
```bash
sed -E 's/(foo|bar)+/baz/g' file.txt
```

### Codebase analysis with awk

Use `awk` for line-by-line data extraction and text processing.

Common use cases:
* Print specific columns from space-separated input:
  ```bash
  ls -l | awk '{print $1, $3}'
  ```
* Find and print duplicate lines in a file without sorting them first:
  ```bash
  awk '!seen[$0]++' filename.txt
  ```
* Filter lines based on column values (for example, printing lines where the third column is greater than 100):
  ```bash
  awk '$3 > 100' data.txt
  ```
* Find lines matching a pattern and print their line number (`NR`) along with the content:
  ```bash
  awk '/Error/ {print NR, $0}' server.log
  ```

### Safe pipelines and parallelism with xargs

Use `xargs` to build and execute commands from standard input. Always use the `-0` option (null-terminated) when processing file paths to handle filenames containing spaces or special characters safely.

```bash
# Unsafe: will fail or perform unintended actions if filenames contain spaces
find . -name "*.log" | xargs rm

# Safe: handles spaces and special characters correctly
find . -name "*.log" -print0 | xargs -0 rm
```

Use the `-P` option to run tasks in parallel:
```bash
# Run up to 4 curl processes in parallel
cat urls.txt | xargs -n 1 -P 4 curl -O
```

### macOS-specific CLI tools

Use macOS-specific utilities to interact with operating system features:

* Use `mdfind` to query the macOS Spotlight index for fast, global file and content searches without scanning the disk:
  ```bash
  # Search by filename
  mdfind -name "project_spec"

  # Search by text content within files
  mdfind "kMDItemTextContent == 'TODO: Refactor'"
  ```
* Use `pbcopy` and `pbpaste` to interact with the system clipboard:
  ```bash
  # Copy file content to the clipboard
  cat ssh_key.pub | pbcopy

  # Paste clipboard content to a file
  pbpaste > new_file.txt
  ```
* Use `open` to open files, directories, or URLs with their default applications:
  ```bash
  # Open the current directory in Finder
  open .

  # Open a local HTML file using a specific application
  open -a "Google Chrome" index.html
  ```

<!-- chapter:end slug=unix-cli-best-practices -->
