dart-meta
Skill8 starsChanged 50 days agoMITView on GitHub
Senior production guidance for Dart `package:meta` in Flutter and Dart codebases. Use this skill whenever code imports or may need `package:meta`, adds/reviews annotations, models immutable state/value objects, designs package/public/internal/protected APIs, defines subclass/lifecycle contracts, uses `@useResult`/testing seams/experimental APIs/deprecations/custom annotations, responds to meta-related analyzer diagnostics, migrates legacy annotations to modern Dart language features, or audits whether metadata is useful, redundant, misleading, or wrongly claimed as a performance optimization—even when the user only asks “which annotation should I use?” or “modernize this Dart API”.
In this repository70 other files it gives its agents.
- camerawesome-flutterSkill
- dart-args-production-cliSkill
- dart-flutter-equatable-engineeringSkill
- dart-flutter-ffi-systems-engineeringSkill
- document-camera-frameSkill
- document-scan-flutterSkill
- figma-to-flutter-expertSkill
- flutter-animations-production-engineeringSkill
- flutter-app-hardening-reverse-engineeringSkill
- flutter-app-icon-engineeringSkill
- flutter-application-security-engineeringSkill
- flutter-app-links-deep-link-engineeringSkill
- flutter-cachingSkill
- flutter-concurrency-memory-performanceSkill
- flutter-confetti-engineeringSkill
- flutter-dart-package-engineeringSkill
- flutter-design-system-from-design-mdSkill
- flutter-dio-cache-interceptor-engineeringSkill
- flutter-dio-engineeringSkill
- flutter-doc-scannerSkill
- flutter-drift-persistence-engineeringSkill
- flutter-expert-tipsSkill
- flutter-firebase-analyticsSkill
- flutter-firebase-core-engineeringSkill
- flutter-firebase-messagingSkill
- flutter-get-it-injectable-dependency-injectionSkill
- flutter-go-router-engineeringSkill
- flutter-hive-persistence-engineeringSkill
- flutter-image-performanceSkill
- flutter-image-picker-production-engineeringSkill
- flutter-lints-static-analysis-engineeringSkill
- flutter-local-notifications-production-engineeringSkill
- flutter-memory-leak-engineeringSkill
- flutter-mobile-developmentSkill
- flutter-motion-engineeringSkill
- flutter-multi-environmentSkill
- flutter-native-splash-engineeringSkill
- flutter-package-plugin-selectionSkill
- flutter-path-provider-production-storageSkill
- flutter-performance-jank-optimizationSkill
- flutter-permission-handler-engineeringSkill
- flutter-pinputSkill
- flutter-production-build-releaseSkill
- flutter-production-engineeringSkill
- flutter-production-loggingSkill
- flutter-pro-image-editor-engineeringSkill
- flutter-secure-storage-security-engineeringSkill
- flutter-sentry-engineeringSkill
- flutter-share-plus-engineeringSkill
- flutter-skeletonizer-engineeringSkill
- flutter-squadron-concurrency-engineeringSkill
- flutter-supabase-engineeringSkill
- flutter-svg-engineeringSkill
- flutter-ui-performance-engineeringSkill
- flutter-url-launcher-engineeringSkill
- flutter-video-player-production-engineeringSkill
- flutter-webview-production-engineeringSkill
- freezed-production-engineeringSkill
- html-to-flutterSkill
- hydrated-blocSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
60 rules. About 0 are common, 30 are distinctive, and 30 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈30
Distinctive · estimate
This author's own choices. Worth a look.
30
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 9
Use package:meta as an API-contract and static-analysis tool, not as annotation decoration and not as a general runtime optimization …
- Distinctive: line 13
When expressing a contract, prefer the strongest accurate mechanism in this order:
- Distinctive: line 35
Prefer modern Dart language features over historical metadata when semantics match.
- Distinctive: line 36
Use an annotation only when it communicates a real contract and catches or documents a plausible misuse.
- Distinctive: line 37
Do not add metadata for cosmetic consistency or “more explicit” code when it provides no meaningful contract.
- Very specific: line 38
Do not claim ordinary meta.dart annotations improve Flutter rebuild speed, CPU execution, AOT, tree shaking, startup, memory, …
- Very specific: line 39
Treat @immutable as a correctness/analyzer contract, not a Flutter optimization switch.
- Very specific: line 41
Prefer _private for same-library privacy.
- Very specific: line 42
Prefer package structure (lib/src, curated exports) before relying on @internal as the sole package boundary.
- Very specific: line 43
Treat @protected as a supported subclass-extension contract, not Java-style access control.
- Very specific: line 44
Treat @internal as API governance, not security or authorization.
- Very specific: line 45
Use @visibleForTesting sparingly.
- Very specific: line 46
Use @mustCallSuper only when the superclass implementation preserves a real invariant/resource/lifecycle obligation.
- Very specific: line 47
Use @mustBeOverridden only when retaining a concrete base implementation is intentional and every concrete subclass must still make an …
- Very specific: line 48
Use @nonVirtual only when the class remains intentionally extensible but one concrete member must not be overridden.
- Very specific: line 49
Use @useResult only when discarding the value is likely a programmer bug.
- Very specific: line 50
Use @awaitNotRequired only when the returned Future is genuinely safe to ignore under the documented contract.
- Very specific: line 51
Use @experimental for genuinely unstable public APIs whose consumers consciously accept compatibility risk.
- Distinctive: line 53
Treat metadata changes in published packages as API-design changes that can affect supported use even when method signatures stay the same.
- Very specific: line 54
Avoid deprecated legacy meta APIs in new code except when demonstrating or performing migration.
- Distinctive: line 55
Do not suppress meta-related analyzer diagnostics broadly just to make analysis green.
- Distinctive: line 56
Do not copy Flutter-framework annotation density into ordinary application code without framework-like extension requirements.
- Very specific: line 57
Verify the annotation exists in the project's resolved meta version and is legal on the intended target.
- Very specific: line 58
Keep meta as a direct dependency when production code under lib/ imports it.
- Distinctive: line 63
Read only what the task requires.
- Distinctive: line 80
Before adding, removing, or changing metadata, inspect the relevant project state:
- Distinctive: line 92
Do not choose an annotation from its name alone.
- Distinctive: line 109
If no concrete answer exists, omit the annotation.
- Very specific: line 113
Before reaching for meta, use native Dart when it expresses the semantics accurately:
- Very specific: line 126
Do not mechanically replace legacy @sealed with Dart sealed.
- Distinctive: line 130
Use this as the first-pass decision matrix:
- Very specific: line 161
Use @immutable only when the type is intended to represent immutable value/configuration/state.
- Distinctive: line 183
If a class needs many test-only public members, refactor the architecture instead of widening more internals.
- Very specific: line 187
Use @mustCallSuper only when omitting the call breaks an invariant.
- Distinctive: line 189
Use language-level class modifiers for type-level inheritance restrictions.
- Very specific: line 201
Do not confuse @useResult with @awaitNotRequired.
- Very specific: line 211
Use Target/TargetKind only when authoring a real custom annotation library and target validation is meaningful.
- Very specific: line 213
Use RecordUse only for build/link-hook tooling that consumes reachable-use records.
- Very specific: line 215
Use noInline/tryInline only when dart2js is the relevant compiler, a real web performance problem exists, benchmarks/generated-code …
- Distinctive: line 219
When analysis reports a meta-related diagnostic:
- Distinctive: line 229
Do not globally suppress diagnostics such as immutable, protected/internal-use, must-call-super, non-virtual, missing-override, …
- Very specific: line 231
Read references/architecture-testing-debugging.md for diagnostic-specific guidance.
- Very specific: line 252
If the user asks for performance improvements, do not prescribe ordinary meta.dart annotations as optimization knobs.
- Distinctive: line 259
use metadata only if it improves correctness/API discipline around the optimization.
- Distinctive: line 265
When tooling is available:
- Very specific: line 268
run dart analyze / flutter analyze as appropriate.
- Distinctive: line 269
run tests covering public behavior and subclass/lifecycle contracts.
- Distinctive: line 270
verify immutable models cannot be observably mutated through exposed collections where that guarantee matters.
- Distinctive: line 271
verify package exports do not expose intended internal implementation accidentally.
- Distinctive: line 272
verify deprecation messages are actionable.
- Distinctive: line 273
verify no broad ignore/suppression was introduced without justification.
- Very specific: line 274
verify dependency declaration is direct when lib/ imports meta.
- Distinctive: line 275
verify changed public class modifiers/annotations do not silently break supported consumers.
- Very specific: line 276
verify version-sensitive APIs against the project's resolved SDK and meta version.
- Distinctive: line 278
If tooling is unavailable, explicitly state what remains unverified.
- Distinctive: line 293
remove decorative/redundant metadata.
- Distinctive: line 309
Do not claim an annotation has runtime behavior unless the supplied research explicitly establishes that effect.
- Distinctive: line 313
Before declaring the work complete, answer yes to every applicable item:
- Distinctive: line 326
Do deprecations provide a migration path?
- Distinctive: line 334
If any applicable answer is no, continue improving the design or report the unresolved gap explicitly.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Dart package:meta
Use package:meta as an API-contract and static-analysis tool, not as annotation decoration and not as a general runtime optimization mechanism.
Operating hierarchy
When expressing a contract, prefer the strongest accurate mechanism in this order:
Dart language guarantee
↓
Architecture / real privacy or package boundary
↓
Analyzer-enforced metadata contract
↓
Lint-enforced convention
↓
Documentation-only intentDefault rule:
If Dart can express the invariant directly, use Dart. If architecture/privacy can express it more strongly, use architecture/privacy. Use
metawhen analyzer/tooling can catch a realistic misuse that the stronger layers cannot express cleanly.
Specialist exceptions exist: package:meta/dart2js.dart compiler hints and RecordUse have compiler/build-tooling effects. Do not generalize those effects to ordinary meta.dart annotations.
Non-negotiable rules
- Prefer modern Dart language features over historical metadata when semantics match.
- Use an annotation only when it communicates a real contract and catches or documents a plausible misuse.
- Do not add metadata for cosmetic consistency or “more explicit” code when it provides no meaningful contract.
- Do not claim ordinary
meta.dartannotations improve Flutter rebuild speed, CPU execution, AOT, tree shaking, startup, memory, database/network performance, or binary size. - Treat
@immutableas a correctness/analyzer contract, not a Flutter optimization switch. - Distinguish final-field compliance from semantic/deep immutability; protect collection ownership when observable mutation would violate the value contract.
- Prefer
_privatefor same-library privacy. - Prefer package structure (
lib/src, curated exports) before relying on@internalas the sole package boundary. - Treat
@protectedas a supported subclass-extension contract, not Java-style access control. - Treat
@internalas API governance, not security or authorization. - Use
@visibleForTestingsparingly; test public behavior or extract a collaborator first when that creates cleaner design. - Use
@mustCallSuperonly when the superclass implementation preserves a real invariant/resource/lifecycle obligation. - Use
@mustBeOverriddenonly when retaining a concrete base implementation is intentional and every concrete subclass must still make an explicit override decision. - Use
@nonVirtualonly when the class remains intentionally extensible but one concrete member must not be overridden. - Use
@useResultonly when discarding the value is likely a programmer bug; avoid result-annotation noise. - Use
@awaitNotRequiredonly when the returnedFutureis genuinely safe to ignore under the documented contract; never use it merely to silence async lints. - Use
@experimentalfor genuinely unstable public APIs whose consumers consciously accept compatibility risk; otherwise keep the API internal. - Give deprecations actionable migration guidance and do not promise removal dates/versions without actual package policy.
- Treat metadata changes in published packages as API-design changes that can affect supported use even when method signatures stay the same.
- Avoid deprecated legacy
metaAPIs in new code except when demonstrating or performing migration. - Do not suppress meta-related analyzer diagnostics broadly just to make analysis green; first determine whether the caller, annotation, or architecture is wrong.
- Do not copy Flutter-framework annotation density into ordinary application code without framework-like extension requirements.
- Verify the annotation exists in the project's resolved
metaversion and is legal on the intended target. - Keep
metaas a direct dependency when production code underlib/imports it; do not rely on a transitive dependency. - Ordinary
metause does not require code generation orbuild_runner.
Load references progressively
Read only what the task requires. For a broad package/API audit, read the references in this order.
| Need | Reference |
Current API catalog, version evolution, deprecated/current annotations, meta_meta, TargetKind, RecordUse, dart2js hints | references/api-catalog.md |
@immutable, deep immutability, _private, @protected, @internal, @visibleForTesting | references/immutability-visibility.md |
Inheritance contracts, @mustCallSuper, @mustBeOverridden, @nonVirtual, native class modifiers, legacy @sealed migration | references/inheritance-modern-dart.md |
@useResult, async result rules, Flutter lifecycle, deprecation, testing boundaries | references/results-lifecycle-deprecation.md |
| Flutter app vs package/framework guidance, analyzer/lints, dependency rules | references/flutter-package-tooling.md |
| Annotation placement/combinations, redundancy, runtime-performance reality, compiler/build exceptions | references/annotation-combinations-performance.md |
| Annotation decision trees, anti-patterns, code-review/migration checklists, AI operating rules | references/decision-trees-review.md |
| Production code and before/after examples | references/patterns-examples.md |
| Architecture placement, tests, analyzer diagnostics, suppression strategy | references/architecture-testing-debugging.md |
| Official source catalog and research baseline | references/sources.md |
Phase 1 — Inspect the project before editing
Before adding, removing, or changing metadata, inspect the relevant project state:
- Dart SDK/language version;
- resolved
metaversion and whether it is a direct dependency; analysis_options.yamland enabled lints;- whether the code is application-internal, package-internal, public package API, framework-like extension API, or tooling code;
- Dart library boundaries and
lib/src/export structure; - existing class modifiers and subtype relationships;
- tests that rely on public/test seams;
- downstream callers/subclasses when changing published API contracts;
- whether the reported problem is compile-time/analyzer behavior or runtime behavior.
Do not choose an annotation from its name alone.
Phase 2 — Classify the intended contract
For every proposed annotation, answer:
- What concrete misuse are we preventing?
- Can Dart express this directly with a language/type/class-modifier feature?
- Can library privacy, package structure, composition, or a clearer interface enforce it more strongly?
- Is analyzer/tool behavior actually provided for this annotation in the resolved version?
- Is the annotation valid on this declaration kind?
- Is the contract true for every intended caller/subclass?
- Is this an app-level need or a package/framework/tooling-level need?
- Does it create compatibility obligations for future maintainers?
- Would ignoring the annotation plausibly produce a bug?
- Is anyone expecting a runtime-performance effect that the annotation does not provide?
If no concrete answer exists, omit the annotation.
Phase 3 — Prefer modern Dart first
Before reaching for meta, use native Dart when it expresses the semantics accurately:
required named parameter → required
never returns normally → Never
closed direct subtype family → sealed class
no external subtype → final class
extend but not implement → base class
implement but not extend → interface / abstract interface class
nullability contract → sound null-safety types
covariant parameter → covariantDo not mechanically replace legacy @sealed with Dart sealed; the historical metadata and native modifier have different package-vs-library subtype boundaries. Inspect existing subtype locations and compatibility first.
Phase 4 — Choose metadata by intent
Use this as the first-pass decision matrix:
| Intent | Preferred mechanism |
| Same Dart library only | _private |
| Same package implementation, not consumers | lib/src + curated exports; optionally @internal |
| Subclass-facing member | @protected |
| External subclass may override but ordinary external code should not call/reference | @visibleForOverriding |
| Override must execute base invariant | @mustCallSuper |
| Concrete base implementation exists but every concrete subclass must replace it | @mustBeOverridden |
| One member must remain non-overridable | @nonVirtual |
| Immutable class field discipline | @immutable / @Immutable(reason) |
| Ignored return value is likely a bug | @useResult / @UseResult(reason) |
| Returned Future is intentionally safe to ignore | @awaitNotRequired |
| Unstable public API | @experimental |
| Narrow exceptional test seam | @visibleForTesting |
| Value must not escape into persistent storage | @doNotStore |
| Temporary developer-only use must not be submitted | @doNotSubmit |
| Argument must be compile-time constant | @mustBeConst |
| Extension-type member intentionally redeclares | @redeclare |
| Intentional reopening under class-modifier lint policy | @reopen |
| Custom annotation target validation | Target / TargetKind from meta_meta.dart |
| Reachable-use recording for link/build hooks | RecordUse, specialist |
| dart2js inlining control | noInline / tryInline, specialist and benchmark-driven |
Consult references/api-catalog.md before using specialized APIs.
Phase 5 — Apply contract-specific gates
Immutability
Use @immutable only when the type is intended to represent immutable value/configuration/state. Ensure all fields are final and, when semantic immutability matters, prevent external mutation of owned collections or collaborators.
Do not infer:
- deep immutability from
finalalone; - thread safety from
@immutable; - faster Flutter rendering from
@immutable.
Flutter widget subclasses already inherit an immutable framework contract; do not redundantly annotate every custom widget merely for decoration.
Visibility
Choose the narrowest real boundary first:
same library → _private
same package → lib/src + curated exports (+ @internal if useful)
subclass extension API → @protected
override-only seam → @visibleForOverriding
exceptional test seam → @visibleForTestingIf a class needs many test-only public members, refactor the architecture instead of widening more internals.
Inheritance/lifecycle
Use @mustCallSuper only when omitting the call breaks an invariant. An empty current base body can still carry a meaningful contract if the API promises the call is required, but verify the actual declaration/documentation before editing overrides.
Use language-level class modifiers for type-level inheritance restrictions; use metadata for member-level or analyzer-only contracts that Dart does not directly express.
Result usage
Use @useResult where:
ignored result ≈ likely bugStrong candidates include immutable copy/update methods, validation/parse/transaction results, and result/error wrappers. Ordinary getters and harmless formatting methods generally do not need it.
Do not confuse @useResult with @awaitNotRequired; they express very different caller intent.
Experimental/deprecated APIs
For a public API that may change incompatibly and genuinely needs early consumers, mark it @experimental and document the instability. If users do not need early access, keep it internal instead.
For deprecation, prefer @Deprecated('Use X instead...') with a concrete migration path. Use targeted Deprecated.* forms when only a capability such as subclassing/implementation is being phased out and the supplied project SDK supports the intended API.
Custom annotations and specialist tooling
Use Target/TargetKind only when authoring a real custom annotation library and target validation is meaningful.
Use RecordUse only for build/link-hook tooling that consumes reachable-use records.
Use noInline/tryInline only when dart2js is the relevant compiler, a real web performance problem exists, benchmarks/generated-code analysis justify intervention, and normal compiler heuristics are demonstrably inadequate.
Phase 6 — Handle analyzer diagnostics correctly
When analysis reports a meta-related diagnostic:
- identify the annotation/contract involved;
- inspect the declaration and supported use boundary;
- decide whether the caller violates a correct contract;
- decide whether the annotation itself is wrong/stale;
- decide whether architecture has drifted away from the original contract;
- fix the root cause;
- suppress only when the exceptional use is intentional, local, documented, and narrower than redesigning the API.
Do not globally suppress diagnostics such as immutable, protected/internal-use, must-call-super, non-virtual, missing-override, unused-result, or testing-visibility failures merely to pass CI.
Read references/architecture-testing-debugging.md for diagnostic-specific guidance.
Phase 7 — Review published-package compatibility
For reusable/public packages, treat API-governance decisions deliberately:
- May consumers construct the type?
- May they extend it?
- May they implement it?
- May they mix it in?
- Is the subtype family closed?
- Which extension points are supported?
- Which overrides must call super?
- Which members must not be overridden?
- Is the API stable, experimental, internal, or deprecated?
- What compatibility window applies to migrations?
Adding native base, interface, final, or sealed modifiers to an existing public API can be breaking. Changing/removing analyzer contracts can also alter supported usage. Do compatibility analysis before “modernizing” a published package.
Phase 8 — Performance discipline
If the user asks for performance improvements, do not prescribe ordinary meta.dart annotations as optimization knobs.
Instead:
- profile the actual runtime problem;
- identify whether it is rebuild/layout/paint, allocation, I/O, algorithmic work, compiler output, or another real mechanism;
- optimize that mechanism;
- use metadata only if it improves correctness/API discipline around the optimization.
The only bundled research exceptions are specialized compiler/build contracts such as dart2js hints and RecordUse; even these are not general Flutter performance annotations.
Phase 9 — Validate changes
When tooling is available:
- run formatter;
- run
dart analyze/flutter analyzeas appropriate; - run tests covering public behavior and subclass/lifecycle contracts;
- verify immutable models cannot be observably mutated through exposed collections where that guarantee matters;
- verify package exports do not expose intended internal implementation accidentally;
- verify deprecation messages are actionable;
- verify no broad ignore/suppression was introduced without justification;
- verify dependency declaration is direct when
lib/importsmeta; - verify changed public class modifiers/annotations do not silently break supported consumers;
- verify version-sensitive APIs against the project's resolved SDK and
metaversion.
If tooling is unavailable, explicitly state what remains unverified.
Repair order for annotation-heavy or legacy code
Fix in this order:
- replace superseded legacy metadata with correct modern Dart where semantics match;
- repair real privacy/package architecture (
_private,lib/src, exports); - correct false or misleading annotations;
- repair immutability ownership problems;
- repair inheritance/lifecycle contracts;
- repair testing seams;
- repair result-use and async-result policy;
- improve experimental/deprecation lifecycle;
- configure useful analyzer/lints selectively;
- remove decorative/redundant metadata;
- investigate runtime performance separately.
Output expectations
For non-trivial design/review/migration tasks, make the reasoning reviewable. Include as appropriate:
- the contract being protected;
- why Dart language/architecture was or was not sufficient;
- the chosen annotation and analyzer/tooling effect;
- whether the pattern is app-oriented or package/framework-oriented;
- compatibility implications for public APIs;
- exact files/code changed;
- analyzer/test validation performed;
- remaining version or downstream-consumer risks.
Do not claim an annotation has runtime behavior unless the supplied research explicitly establishes that effect.
Final completion gate
Before declaring the work complete, answer yes to every applicable item:
- Was the intended misuse/invariant identified explicitly?
- Was a Dart language feature considered before metadata?
- Was real privacy/architecture considered before visibility annotations?
- Does each annotation match its actual analyzer/tooling semantics?
- Is the annotation legal for the declaration and available in the resolved version?
- Are immutable types semantically immutable to the degree their API promises?
- Are protected/internal/testing seams no wider than necessary?
- Does every
@mustCallSuperprotect a real invariant? - Is every
@useResultsignal selective and meaningful? - Is every
@awaitNotRequiredfuture genuinely safe to ignore? - Are experimental APIs intentionally public and lifecycle-managed?
- Do deprecations provide a migration path?
- Were legacy annotations migrated according to semantics rather than name similarity?
- Were public package compatibility effects reviewed?
- Were analyzer diagnostics fixed rather than broadly suppressed?
- Are runtime-performance claims separated from static-analysis metadata?
- Were specialist compiler/build annotations kept out of ordinary app code without evidence?
- Were analysis/tests run or remaining validation gaps stated?
If any applicable answer is no, continue improving the design or report the unresolved gap explicitly.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

