Skip to content

Add dart development skill. - #3261

Open
polina-c wants to merge 2 commits into
mainfrom
dart-development-skill
Open

polina-c wants to merge 2 commits into
mainfrom
dart-development-skill

Conversation

@polina-c

@polina-c polina-c commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes http://github.com/a2ui-project/a2ui/pull/3289

Description

Adds the a2ui-dart-development skill, which tells assistants that write or review Dart code in this repository which language features a package may use. It also lowers the SDK floor of a2ui_agent from 3.10 to 3.8, and explains in the pubspec.yaml of a2ui_core and of a2ui_agent why their floors are lower than the floor of a2ui_flutter.

Motivation

Assistants judge Dart syntax from memory, and their training data often predates recent language features. Dart adds syntax in minor releases: null-aware elements in 3.8, dot shorthands in 3.10, primary constructors in 3.13. So an assistant can be wrong in two directions:

  1. It reports valid code as a compile error. In Implement agent 1.0. #3242 the review bot flagged 'catalogId': ?catalogId as a critical compile error three times (1, 2, 3). The line is a null-aware element, valid since Dart 3.8, and a2ui_agent required 3.10 at the time. The fix the bot proposed, if (catalogId != null) 'catalogId': catalogId, would have failed CI on the use_null_aware_elements lint. The author had to research and answer each comment, and an author who trusted the bot would have broken the build.
  2. It uses a feature that the package does not allow yet. An assistant that knows the latest Dart can write, for example, a primary constructor in a package that targets 3.10. flutter analyze rejects it, and the change needs another round.

a2ui_core and a2ui_agent are plain Dart. Agents and servers that do not run Flutter use both, and Flutter apps on older SDKs use a2ui_core. So their SDK floors follow what their own code needs rather than the floor of a2ui_flutter, which follows Flutter. a2ui_core allows 3.5 since #2819, and a2ui_agent compiles with 3.8 without changes.

Changes

  1. .agents/skills/a2ui-dart-development/SKILL.md, the new skill, describes:
    1. The language version rule above, and the features assistants most often misjudge, each with the version that added it. The versions were checked by analyzing each feature at each language version with the Dart 3.13 analyzer.
    2. Steps for a reviewer to take before calling a line invalid: look up the version the feature needs, compare it with the package's pubspec.yaml, and run flutter analyze.
    3. The analyzer settings in the root analysis_options.yaml that most often fail a change, including which initializers and loop iterables make a local variable's type obvious. The examples were checked with the analyzer.
    4. How dart format picks its style from the language version, and the commands CI runs.
  2. AGENTS.md lists the skill beside the Python and Swift development skills, and adds a2ui_cli to the Dart packages in the repository structure.
  3. .gemini/styleguide.md states the rule and links to the skill. The review bot reads the style guide, not AGENTS.md, so this is what reaches the bot that made the mistake in Implement agent 1.0. #3242.
  4. dart/a2ui_agent/pubspec.yaml lowers the SDK floor from 3.10 to 3.8, the oldest version the package's code compiles with, because it uses null-aware elements. dart/a2ui_agent/CHANGELOG.md records the change. Going down to 3.5, as a2ui_core does, would mean rewriting 4 null-aware elements and reformatting over 30 files in the style dart format uses before 3.7. That reformatting would conflict with the open pull requests that change a2ui_agent, such as Implement agent 1.0. #3242, feat(dart/agent): add RendererState; build validatePayload on it #3276 and feat(dart/agent)!: make the Parser stateless; add ResponseStream; bind RendererState to A2uiRequestProcessor #3277.
  5. dart/a2ui_core/pubspec.yaml and dart/a2ui_agent/pubspec.yaml explain in a comment why the floor is lower than the floor of a2ui_flutter. The comment in a2ui_agent says that agents on servers that do not run Flutter use the package. The comment in a2ui_core names those agents and servers and also Flutter apps on older SDKs, and notes that 3.5 is the lowest version that resolution: workspace allows.

Dependency limit

Neither package resolves on Dart 3.5 to 3.9 yet. a2ui_core depends on json_schema_builder: ^0.1.7, and every json_schema_builder release from 0.1.5 on requires Dart 3.10. The code of json_schema_builder 0.1.7 compiles with 3.8, so a release of it that declares >=3.8.0 would let both packages resolve on Dart 3.8 with no change in this repository. No release of json_schema_builder allows 3.5 to 3.7.

Verification

In dart/a2ui_core and dart/a2ui_agent, dart format --set-exit-if-changed, flutter analyze --fatal-infos and flutter test pass, and so does dart run tool/generate_express_parser.dart --check in a2ui_agent. At language version 3.7, a2ui_agent fails to analyze with 5 errors, all from null-aware elements.

🤖 Agent-generated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new documentation skill, 'a2ui-dart-development', to provide guidelines for Dart and Flutter development within the repository, and updates 'AGENTS.md' to include this new resource. The review feedback suggests correcting a reference to a non-existent package, adding specific guidelines for loop variable type annotations, and including a 'Common Pitfalls & Best Practices' section to improve the utility of the documentation.

- `strict-casts`, `strict-inference` and `strict-raw-types`: a value read from
JSON is `Object?` or `dynamic`, so cast it or match it with a pattern before
using it as a narrower type.
- `lines_longer_than_80_chars`, which `dart/a2ui_cli` turns off.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The package 'dart/a2ui_cli' is not listed in the repository structure in 'AGENTS.md'. If this package does not exist or was renamed, please update this reference to the correct package name (e.g., 'a2ui_agent' or 'a2ui_flutter').

Suggested change
- `lines_longer_than_80_chars`, which `dart/a2ui_cli` turns off.
- 'lines_longer_than_80_chars', which 'dart/a2ui_agent' turns off.

Comment on lines +85 to +88
- `specify_nonobvious_local_variable_types` and
`omit_obvious_local_variable_types`: write the type of a local variable when
its initializer does not make the type obvious, and leave it off when it
does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To make this guide more comprehensive and prevent common CI failures, consider adding the repository's specific guidelines for loop variables under these linter rules. Specifically, avoid explicit type annotations on loop variables when the iterable already has an explicit type argument, but retain them when iterating over collections (like 'List.of(...)' or map entries) where the type is non-obvious.

Suggested change
- `specify_nonobvious_local_variable_types` and
`omit_obvious_local_variable_types`: write the type of a local variable when
its initializer does not make the type obvious, and leave it off when it
does.
- 'specify_nonobvious_local_variable_types' and
'omit_obvious_local_variable_types': write the type of a local variable when
its initializer does not make the type obvious, and leave it off when it
does. For loop variables, avoid explicit type annotations if the iterable
already has an explicit type argument, but retain them when iterating over
collections (like List.of(...) or map entries) where the type is non-obvious.
References
  1. In Dart, avoid adding explicit type annotations to loop variables when the iterable has explicit type arguments, but retain them when iterating over collections (like List.of(...) or map entries) if specify_nonobvious_local_variable_types is enabled.

Comment on lines +91 to +92
- `unawaited_futures`: await a future, or pass it to `unawaited`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider adding a 'Common Pitfalls & Best Practices' subsection to document repository-specific Dart guidelines (such as map validation, safe element retrieval with 'firstOrNull', and raw string handling). This will make the skill file much more valuable for developers and automated agents.

Suggested change
- `unawaited_futures`: await a future, or pass it to `unawaited`.
- 'unawaited_futures': await a future, or pass it to 'unawaited'.
### Common Pitfalls & Best Practices
- Map Validation: When validating map inputs that can be either 'Map<dynamic, dynamic>' (e.g., from YAML parsers) or 'Map<String, Object?>', do not check 'is Map<String, Object?>' directly. Instead, check 'is Map' and use '.cast<String, Object?>()'. Defensive validation of map keys before calling '.cast' is unnecessary if the casted map is only accessed via direct key lookups (e.g., '[]') and never iterated.
- Safe Element Retrieval: Use 'firstOrNull' instead of 'first' on 'Iterable' to defensively avoid a 'StateError' if the collection is empty.
- Raw Strings: Backslashes have no special meaning inside raw string literals (prefixed with 'r') and do not escape the closing quote delimiter. Raw string literals can safely end with a backslash.
References
  1. In Dart, use .cast<String, Object?>() on Map instead of checking 'is Map<String, Object?>' directly, use firstOrNull instead of first to avoid StateError, and handle raw string literals correctly with trailing backslashes.

@polina-c
polina-c requested a review from gspencergoog October 16, 2026 20:20

@gspencergoog gspencergoog left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pull request introduces the a2ui-dart-development skill (.agents/skills/a2ui-dart-development/SKILL.md) and links it from .gemini/styleguide.md and AGENTS.md. The skill documents how each Dart package's environment: sdk: lower bound governs allowed language features and dart format styling, lists Dart 3.0 through 3.13 features and root analysis_options.yaml rules, and gives local verification commands matching CI.

All Dart language feature versions (3.0 through 3.13), analyzer rules, and relative links match the Dart 3.13.5 SDK and repository configuration, with a few minor documentation adjustments noted inline.

🤖 Agent-generated

fails CI. In `dart/a2ui_agent`, CI also runs
`dart run tool/generate_express_parser.dart --check`, which fails when the
generated Express parser is out of date with the grammar. After editing the
grammar, run the tool without `--check` and commit its output.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flutter_packages_test.yml excludes dart/a2ui_agent/e2e_test and samples/client/flutter/restaurant_finder/e2e_test from flutter test, running only dart pub get, dart format, and flutter analyze --fatal-infos on them. Those e2e_test suites call live Gemini models via ./scripts/e2e_test.sh and require GEMINI_API_KEY to be set. Contributors or agents editing an e2e_test package will hit immediate GEMINI_API_KEY is not configured test failures during local verification.

Suggested change
grammar, run the tool without `--check` and commit its output.
grammar, run the tool without `--check` and commit its output. In `e2e_test`
packages (`dart/a2ui_agent/e2e_test` and
`samples/client/flutter/restaurant_finder/e2e_test`), `flutter_packages_test.yml`
runs only `dart pub get`, `dart format`, and `flutter analyze --fatal-infos`
because their tests require `GEMINI_API_KEY` (see `./scripts/e2e_test.sh`).

🤖 Agent-generated

- Do not use a feature newer than the package's language version, even when
your SDK supports it. Raising the lower bound of `environment: sdk:` drops
users of older SDKs, so it is a change of its own, with a reason and an
entry in `CHANGELOG.md`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scripts/fix_format.sh passes explicit --language-version=3.10 and --language-version=3.5 flags to dart format, and presubmit-lint.yml runs ./scripts/fix_format.sh --check on every pull request. The guidance for raising environment: sdk: mentions CHANGELOG.md but omits updating the pinned version in scripts/fix_format.sh.

Suggested change
entry in `CHANGELOG.md`.
entry in `CHANGELOG.md`, and an update to the pinned `--language-version` in
`scripts/fix_format.sh`.

🤖 Agent-generated

---
name: a2ui-dart-development
description: >-
Language version, analysis, formatting and verification rules for Dart code

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description field opens with the noun phrase Language version, analysis, formatting and verification rules, which triggers a lint_skill.py warning. Opening with a third-person verb keeps the skill frontmatter consistent with a2ui-dart-versioning and passes lint_skill.py without warnings.

Suggested change
Language version, analysis, formatting and verification rules for Dart code
Defines language version, analysis, formatting, and verification rules for Dart code

🤖 Agent-generated

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants