Install
$ agentstack add skill-zero-labsco-flutter-agent-kit-flutter-agent-kit ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Flutter Agent Kit
> Self-contained bundle (v1.0.0). This SKILL.md is an auto-generated, complete copy > of the guidance from AGENTS.md and the docs > in references/ (the canonical sources in this kit's repository root). It is > bundled so the skill works on its own even when a marketplace (e.g. skills.sh) > downloads only SKILL.md. The helper scripts (scripts/) are NOT included in > this download — clone the repo at https://github.com/zero-labsco/flutter-agent-kit to run them. > > Tool-agnostic. This skill loads via SKILL.md in any agent that supports > the format — Claude Code, Cursor, Codex, GitHub Copilot, CodeBuddy, OpenCode, > Aider, and any other tool skills.sh or a compatible marketplace targets. > Follow the guidance below for any Flutter / Dart task regardless of which tool > you use.
Overview
This skill activates for any Flutter / Dart project work. The guidance below is the tool-agnostic, bundled core: architecture, coding conventions, dependency and version rules, plugin platform-channel patterns, verification commands, and the deep-dive reference appendices.
General guidance (bundled from AGENTS.md)
Scope
Applies to any Flutter / Dart project, covering two scenarios:
- Application projects — UI apps with
lib/, state management, networking, persistence. - Plugin projects — packages exposing a platform channel for Android/iOS (and beyond).
In scope (this kit owns these): general Flutter / Dart conventions, lib/ structure, architecture pattern selection, dependency and version rules, platform-channel patterns, verification commands, and the anti-AI-smell / anti-hallucination discipline. These are tool-agnostic and apply to every project.
Out of scope (this kit does NOT own these): project-specific decisions and facts — exact package names and versions, business/domain logic, directory depth and folder naming beyond the recommended layouts, CI/CD configs, secrets, and any rule that is unique to one repo. Those belong in the project's own AGENTS.md (or its team docs), which should override this kit when they conflict. When a project already has an established convention, follow it (see Match the existing codebase, not a template) and do not impose this kit's defaults.
Uncertainty handling (say so instead of guessing)
When you are not certain about a fact — an API's existence or signature, a package's export, the project's intended behavior, a version's compatibility — do not fabricate a plausible-looking answer. Instead:
- State the uncertainty explicitly. Say "I can't verify X from the available
context" rather than emitting a confident-but-unchecked symbol or snippet.
- Point to where to verify. Name the source to check:
dart doc, the package
source in pubspec.lock, pub.dev, the project's own code/docs, or flutter analyze to surface errors. See API truthfulness.
- Prefer a safe, minimal stub over a wrong implementation. If you must
proceed, write the smallest correct shape you can defend and flag what needs confirmation, instead of guessing parameters or methods.
- Ask when the cost of being wrong is high (data loss, breaking changes,
auth/security). A short clarifying question beats a silent wrong assumption.
Coding conventions
- Follow
effective_dart. Enforce withflutter analyzeandflutter_lints. - Use null safety; avoid
!unless proven safe. Preferfinaland immutable models. - Name files
snake_case.dart, classesPascalCase, constantslowerCamelCaseorkConstant. - Keep
lib/free of business logic leakage into UI; separate data / domain / presentation. - Do not write hardcoded secrets; use
--dart-defineor a.envexcluded from VCS. - Do not hardcode theme values. Do not create a color-constants file
(e.g. app_colors.dart with static const brand = Color(0xFF2E5BFF)) — that only relocates hardcoded colors and still can't adapt to light/dark or brand swaps. Instead:
- Define the palette once in the app's
ThemeData, derived from a single
seed color via ColorScheme.fromSeed(seedColor: ...). Let Flutter generate the shades (primary, surface, error, …) for you.
- In widgets, read everything from the theme at runtime — `Theme.of(context)
.colorScheme.primary, .textTheme.titleLarge, .colorScheme.error — never literal Color(0xFF...), Colors.x`, or magic pixel numbers inline.
- The only acceptable exception is a project that already ships its own
design-token system wired into the theme (light/dark aware); then import those tokens, don't invent new hardcoded ones. This keeps the look consistent and themeable. See the UI guidance.
Dependencies and versioning
- Prefer the caret (
^) constraint on pub dependencies; do not pin exact versions without reason. - Keep
sdkconstraints realistic (e.g.>=3.0.0 /{data,domain,presentation}/. - Or a layer-first layout for small apps:
lib/data/,lib/domain/,lib/presentation/. - Choose state management deliberately:
Provider/Riverpodfor scoped DI,Bloc/Cubitfor event-driven flows,GetItfor service locators. Document the choice in the project README. - Default when unchosen: if the project has no established state-management
approach, recommend Riverpod (or Provider for very small apps) as the default — low boilerplate, scoped DI, and strong testability. Only pick Bloc/Cubit when the flow is genuinely event-driven and benefits from explicit states. Pick ONE primary approach and document it.
- Never import
lib/src/of a dependency directly; use its public API only. - Read existing code before generating. Imitate the project's established
patterns (file layout, naming, error handling, state shape) rather than emitting a generic template. Code that looks identical across every project is the tell-tale sign of an LLM — match the repo's voice.
- Verify APIs before using them (see API truthfulness). Never assume a
method/constructor/parameter or package export exists — confirm it in the pinned SDK/package version.
Componentization & reuse (reduce duplication)
Prefer composable, reusable components over copy-pasted UI and logic. Aim to remove duplication wherever the same markup or behavior appears more than once:
- Extract before repeating. The first time you write a block of UI, leave it
inline. The second time the same structure appears, extract it into a named widget / helper / function. Three or more repetitions of near-identical code is a strong signal to refactor into a shared component.
- Build a small shared component set. Colocate genuinely reusable widgets
(buttons, cards, inputs, headers, empty/error states, list rows) in lib//presentation/widgets/ or a cross-feature lib/shared/ (or lib/common/, lib/components/) following the project's existing convention. Give them clear, single-purpose names — not MyWidget.
- Parameterize, don't fork. When two usages differ only by data, color, or
callback, pass them as parameters instead of duplicating the widget with hardcoded variants. Prefer const constructors and a small set of named arguments over long positional lists.
- Prefer composition over inheritance. Compose small widgets (a
Card+
ListTile + Icon) rather than subclassing to reuse a look. Flutter widgets are cheap to nest; levers like Builder, LayoutBuilder, and InheritedWidget / provider reads share behavior without copying code.
- Reuse logic, not just markup. Lift repeated business rules, formatting,
validation, and parsing into services / extensions / free functions in domain or core/utils; don't re-implement the same if chain in three screens. Share state via the chosen state-management container instead of duplicating fetches.
- Match the project's existing components first. Before adding a new shared
widget, check whether one already exists (search lib/shared, lib/common, existing *_widget.dart). Reuse the repo's own building blocks so the UI stays consistent — do not introduce a second, parallel component library.
- Keep components self-contained and dependency-light. A shared widget should
not reach into a specific feature's state or data layer; pass what it needs via the constructor. That keeps it reusable and avoids accidental coupling.
- Don't over-abstract. Extract a component only when it earns its place (two+
real call sites, or a genuinely shared cross-feature need). A one-off widget pulled into shared/ prematurely adds indirection with no payoff.
Navigation & routing (avoid inline routes)
- Don't inline
Navigator.push(MaterialPageRoute(...))blocks inside widgets.
That scatters destinations and the page-construction logic across the codebase.
- Use a centralized router when the project has one —
go_router,
auto_route, or the project's own RouteGenerator. If the project has no convention, recommend go_router (declarative, typed routes, deep-linking) as the default for new apps.
- Keep routes in one module, not scattered. Define the router in a dedicated
location rather than inside main.dart or individual pages:
- Small apps: a single
lib/router.dart(orlib/app_router.dart) holding the
GoRouter/RouterConfig instance.
- Larger / multi-feature apps: a
lib/router/(orlib/routing/) folder with
the router, route table, and guards split out (e.g. app_router.dart, routes.dart, guards.dart).
- Define path strings as constants. Don't write magic route strings like
context.go('/users/123') across widgets — centralize them (e.g. route_paths.dart with static const users = '/users'; and a typed usersDetail(String id) helper) so destinations have one source of truth.
- Pass typed arguments, not raw Maps/strings. Route params should be typed
(e.g. GoRouterState.pathParameters['id'] parsed to the real type), not a loosely-typed Map passed through constructors.
- Match the project's existing navigation before introducing a new approach.
If screens currently use named routes or a specific package, stay consistent.
Architecture (plugin)
- Define the abstract API once in
lib/_platform_interface.dart(Platform). - Provide a concrete impl per target platform:
MethodChannelfor Android / iOS / macOS / Linux / Windows / OpenHarmony (鸿蒙), and pure-Dartdart:js_interopfor Web (no MethodChannel). - Register the right impl conditionally (use
kIsWeb+dart:ioPlatform.isX) in the public barrel; re-export public symbols only. Consumers call the abstract API and never change when a platform is added. - Keep native changes minimal and matching the method-channel contract. Android lives under
android/src/main/kotlin/..., iOS/macOS underios/Classes/macos/Classes, Linux/Windows underlinux//windows/(C++), OHOS underohos/(ArkTS). - See the Plugin Platform Channel Reference appendix below for a full multi-platform template.
Testing discipline
Generated code should be accompanied by tests, not shipped alone:
- Write a test for every non-trivial change. A new use case, repository
method, formatter, or validation rule gets a unit test. A new screen or flow gets at least one widget/integration test covering the critical path.
- Test by layer (see Testing layering in the Architecture Reference):
domain as pure unit tests; data with mocked sources (verify mapping and error handling); presentation with widget tests for key flows and integration tests for end-to-end.
- Make it runnable and green. After generating, the project must pass
flutter analyze and flutter test (or dart analyze / dart test for non-Flutter packages). Do not leave failing or commented-out tests behind.
- Prefer meaningful assertions over "does not throw". Assert behavior and
state, not just that the code executed.
- Match the project's existing test style (test framework, mocking library,
file location test/ vs */test/) before introducing a new pattern.
Dependency discipline
Adding a package is a decision, not a reflex:
- Confirm the need first. Before adding a dependency, check whether the SDK
or an existing package already covers the use case (e.g. dart:convert, dart:async, flutter/material.dart). Prefer the standard library over a third-party package.
- Audit the package before adding. On
pub.dev, check the **popularity +
health + maintenance** scores, last published date, open issues, and null-safety / SDK compatibility. Avoid unmaintained or single-maintainer packages for critical functionality.
- Avoid overlapping packages. Don't add two packages that do the same thing
(e.g. multiple HTTP clients, multiple state libraries). One chosen approach per concern.
- Scope correctly. Runtime needs go in
dependencies; test/build tooling
goes in dev_dependencies. Never commit a permanent dependency_overrides.
- Pin with care (see Dependencies and versioning): prefer caret (
^)
constraints; don't pin exact versions without reason.
Error handling (fail loudly, recover gracefully)
Generated code should treat failures as first-class, not an afterthought:
- Don't swallow exceptions. Avoid bare
catch (e) {}ortry { … } catch (_)
that discards the error. At minimum log it; rethrow or surface it when the caller can act on it.
- Represent failure explicitly. For operations that can fail, prefer throwing
a typed exception or returning a Result/sealed type over returning null to mean "it broke". A null success/failure ambiguity is a common source of downstream crashes.
- Use
async/await+try/catchfor async work rather than nested
.then().catchError() chains, which are harder to read and easy to leave unhandled.
- Show the user a recoverable message, not a stack trace. Map errors to a
human-readable, localized string (see Internationalization) and offer a retry where it makes sense — using the project's existing error/empty-state pattern, not a generic dialog.
- Catch at the right boundary. Let lower layers (
data/domain) throw and
let the presentation layer decide how to present the failure, rather than catching and hiding it deep inside a repository.
Internationalization (i18n)
- Don't hardcode user-facing strings. Extract them to
arbfiles
(lib/l10n/app_en.arb, app_zh.arb, …) via flutter_localizations + intl (or slang/easy_localization if the project already uses one).
- Generate the delegate (
flutter gen-l10n) and wirelocalizationsDelegates supportedLocalesinMaterialApp/CupertinoApp. Follow the project's
chosen i18n tool, not a new one.
- Keep plurals/formatting in the arb, not in Dart string concatenation, so
translators and locale rules are respected.
- Never convey meaning by UI text alone for accessibility — pair labels with
icons/semantics as noted in the UI guidance.
Verification commands (run locally before pushing)
dart format --line-length 80 .(orflutter format) — must report no
unformatted files. Run formatting before analyze; never hand-format around the formatter.
flutter analyze— must pass with no errors.flutter test— all unit tests green.flutter pub publish --dry-run— confirmpanascore and no excluded files.
Helper scripts
Located in scripts/dart/ (Dart, cross-platform, runs on the Dart SDK every Flutter dev already has) and scripts/python/ (Python, for environments without the Dart SDK). Both implement the same behavior and CLI; pick whichever fits your environment.
Run Dart with dart run scripts/dart/.dart [args], or Python with python scripts/python/.py [args] (o
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: zero-labsco
- Source: zero-labsco/flutter-agent-kit
- License: MIT
- Homepage: https://flutter-agent-kit.vercel.app
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.