复制安装命令
用 Codex 或 Claude 安装复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它先审查 Skill 页面再帮你安装。
复制前请先查看来源、License 和安全提示。
36 Flutter and Dart skills your coding agent loads by itself, sourced only from official documen...
用 Codex 或 Claude 安装复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它先审查 Skill 页面再帮你安装。
复制前请先查看来源、License 和安全提示。
来源文件:README.md
36 Flutter and Dart skills your coding agent loads by itself, sourced only from official documentation.
A skill is a folder with a SKILL.md file. Your agent reads the description, decides a task matches, and pulls in the guidance — you don't paste anything into a rules file or remember to @-mention a doc. Install once, and Firebase Auth guidance shows up when you touch auth, Riverpod guidance when you touch providers.
A comprehensive, (almost) non-opinionated collection: everything here is derived from official Flutter, Dart, Firebase, and package documentation. No personal preferences, no invented conventions.
npx skills add evanca/flutter-ai-rules
That's it. The Skills CLI discovers the packages under skills/ and installs them for supported agents.
Browse before installing, or take just one:
npx skills add evanca/flutter-ai-rules --list
npx skills add evanca/flutter-ai-rules --skill flutter-best-practices
This repo is also a plugin marketplace, so agents that support plugins can install the whole set and keep it updated in place. The manifests live at .claude-plugin/, .codex-plugin/, .cursor-plugin/, .agents/plugins/, and plugin.json — all pointing at the same skills/ directory.
Claude Code — plugin marketplaces:
/plugin marketplace add evanca/flutter-ai-rules
/plugin install flutter-ai-skills@flutter-ai-rules
Skills then load as flutter-ai-skills:bloc, flutter-ai-skills:riverpod, and so on.
Codex — plugins:
codex plugin marketplace add evanca/flutter-ai-rules
codex plugin install flutter-ai-skills@flutter-ai-rules
Cursor — plugins: in Cursor, run /add-plugin, or add the repo as a team marketplace under Dashboard → Settings → Plugins → Import from Repo:
https://github.com/evanca/flutter-ai-rules
Antigravity — plugins:
git clone --depth 1 https://github.com/evanca/flutter-ai-rules.git
agy plugin install ./flutter-ai-rules
Windsurf / Devin has no plugin manifest, but Cascade already scans .agents/skills/ and ~/.agents/skills/, so the manual copy below is the install path. GitHub Copilot doesn't read SKILL.md at all — see Rules and combined sets for what to use instead.
Prefer to do it by hand? Copy or symlink any skill folder into your agent's skills directory — .claude/skills/, .cursor/skills/, .codex/skills/, .agents/skills/ (Antigravity, Codex, Windsurf), .windsurf/skills/. Or vendor the whole set into your project:
git clone --depth 1 https://github.com/evanca/flutter-ai-rules.git temp_repo && mkdir -p .skills && cp -r temp_repo/skills/* .skills && rm -rf temp_repo
With a .skills/ folder you can also reference a skill explicitly when you want it: "Read @.skills/bloc/SKILL.md and create test coverage for the new methods."
| Skill | Loads when you're… |
|---|---|
flutter-best-practices | Writing, reviewing, or planning Flutter code |
effective-dart | Writing Dart, naming things, adding doc comments |
dart-3-updates | Using records, patterns, sealed classes, switch expressions |
flutter-app-architecture | Scaffolding a project or refactoring into layers |
architecture-feature-first | Designing folder structure for a new feature |
flutter-errors | Hitting RenderFlex overflows, unbounded constraints, layout errors |
flutter-use-column-row-first | Building responsive layouts with Row, Column, Expanded, Flexible |
flutter-pre-caching | Preloading fonts, images, animations, or config |
| Skill | Loads when you're… |
|---|---|
bloc | Creating a Cubit or Bloc, modeling state, wiring providers |
riverpod | Setting up providers, combining requests, managing disposal |
provider | Consuming state, optimizing rebuilds, using ProxyProvider |
flutter-change-notifier | Setting up ChangeNotifier models and consuming them |
| Skill | Loads when you're… |
|---|---|
testing | Writing unit, widget, or golden tests; fixing flaky tests |
mockito | Generating mocks, stubbing, verifying interactions |
mocktail | Mocking without codegen, registering fallback values |
patrol-e2e-testing | Writing E2E tests that touch native permissions or dialogs |
code-review | Reviewing a PR, branch, or diff |
| Skill | Loads when you're… |
|---|---|
flutterfire-configure | Adding Firebase to a project, running flutterfire configure |
firebase-auth | Setting up auth, managing auth state, social sign-in |
firebase-cloud-firestore | Designing schemas, CRUD, listeners, pagination |
firebase-database | Syncing real-time data, structuring JSON trees |
firebase-storage | Uploading and downloading files, managing metadata |
firebase-analytics | Logging events, setting user properties |
firebase-crashlytics | Capturing fatal and non-fatal errors |
firebase-messaging | Setting up FCM, handling background messages |
firebase-in-app-messaging | Running in-app campaigns |
firebase-remote-config | Implementing feature flags or A/B tests |
firebase-app-check | Configuring attestation and debug tokens |
firebase-cloud-functions | Calling callable functions, handling errors |
firebase-ai | Generating text or chat with Gemini via firebase_ai |
generate-images-with-firebase-ai | Generating or editing images with a Gemini image model (Nano Banana) |
firebase-data-connect | Writing GraphQL queries against Data Connect |
| Skill | Loads when you're… |
|---|---|
accessibility | Working on a11y, WCAG, screen readers, focus order |
inclusive-design | Handling i18n, global name/address forms, low-end devices |
store-listing-assets | Writing store copy to character limits |
revenuecat-testing | Testing purchases, subscriptions, sandbox flows |
developing-genkit-dart | Building AI agents in Dart with Genkit |
Before skills existed, this repo shipped rule files you pasted into a config, plus pre-merged bundles squeezed under Windsurf's character cap. Both still work and both are still updated, but skills are the recommended path — they load contextually instead of consuming your context window on every request.
Reach for these only if your tool has no skills support, or you want one static file you fully control:
rules/ — six broad foundation files: effective_dart.md, flutter_app_architecture.md, flutter_errors.md, dart_3_updates.md, testing.md, code_review.md. Drop them in your project and reference them by name: "Read @rules/effective_dart.md and follow its conventions." Package-specific guidance (Bloc, Riverpod, Firebase, Mockito…) is skills-only now.combined/ — seven topic bundles, each in a full and an __under_6K variant. Paste one into your global or local rules config and you're done. The trimmed variants stay under 6,000 characters to fit Windsurf's global_rules.md hard limit.GitHub Copilot lives here rather than in the skills section, because it has no SKILL.md support. Three options, in the order Copilot documents them:
combined/ bundle to .github/copilot-instructions.md for repo-wide guidance.rules/ files into .github/instructions/ as <name>.instructions.md, each with applyTo: "**/*.dart" frontmatter, so they only load for Dart files.AGENTS.md, so a bundle pasted there works for Copilot, Codex, and Antigravity at once.Size guidance from each tool's own official documentation, for rule/instruction files and for SKILL.md files (accessed 2026-07-11).
| Tool | Rule file — recommended size | SKILL.md — recommended size |
|---|---|---|
| Claude Code | CLAUDE.md: under 200 lines (soft) | Under 500 lines (soft); description 1,536 chars (hard) |
| Cursor | .mdc rule: under 500 lines (soft) | No numeric limit — "keep focused, move detail to separate files" |
| OpenAI Codex | AGENTS.md: no limit stated | Skill bundle: zip ≤ 50 MB, uncompressed file ≤ 25 MB, ≤ 500 files/version (no per-SKILL.md text limit) |
| Google Antigravity | rule file: 12,000 chars each (hard) | No numeric limit stated |
| Windsurf | global_rules.md: 6,000 chars; .windsurf/rules/*.md: 12,000 chars/file (hard) | No numeric limit — "keeps your context window lean" |
| GitHub Copilot | copilot-instructions.md: ≤ 2 pages (soft, approx.) | Not supported — no repo-level SKILL.md |
Notes:
SKILL.md length recommendation (under 500 lines). Cursor, Windsurf, and Antigravity just say "keep it focused/lean" with no figure; OpenAI documents skill-bundle limits (50 MB zip / 25 MB per file / 500 files) rather than a text length; and GitHub Copilot has no repo-level SKILL.md — it uses copilot-instructions.md plus path-specific *.instructions.md (no size limit stated for the latter).CLAUDE.md in full regardless of length, but notes files over 200 lines "consume more context and reduce adherence"; its auto-memory MEMORY.md loads only the "first 200 lines or 25KB, whichever comes first."docs.windsurf.com → docs.devin.ai) and reference .windsurf/rules and .windsurf/skills.combined/ sets under 6,000 characters to satisfy the strictest hard limit above (Windsurf global_rules.md).Official sources: Claude Code — memory · skills | Cursor — rules · skills | OpenAI Codex — AGENTS.md · skills | Google Antigravity — rules · skills | Windsurf — rules & skills | GitHub Copilot — instructions
Every skill is sourced from official documentation — no personal preferences or subjective interpretations. That's intentional. You're free to alter them to taste, but this repo stays objective by sticking to the source.
One consequence worth knowing: skills can contradict each other, because their sources do. If one package recommends a folder layout and another recommends a different one, you'll see both.
Content is re-fetched from upstream docs on a schedule, so skills track the official guidance as it changes rather than freezing at whatever was true when they were written.
Contributions are welcome:
skills/, or a rule in rules/.Include an official documentation link for anything you add or change. That's the one hard requirement — it's what keeps the repo objective and reviewable. If your source isn't already listed in ATTRIBUTION.md, add it there with its license — and if that license isn't a permissive one, restate the guidance instead of quoting it.
Official documentation these skills are built from:
Flutter — App Architecture · Common Errors · Simple State Management
Dart — Effective Dart · Language tour · Records · Patterns · Pattern types · Branches
State management — Bloc · Riverpod · Provider
Testing — Mockito · Mocktail · Patrol
Firebase — Firebase for Flutter · FlutterFire · Multiple flavors with the FlutterFire CLI
MIT — for this repository's own content: the choice of topics, the trigger descriptions, and the wording and structure of every skill.
The underlying documentation keeps its own terms. Most of it is CC BY 4.0 (Flutter, Dart, Firebase), with code samples under BSD-3 or Apache 2.0, package READMEs under MIT or Apache 2.0, and a few sources — Apple, Google Play, RevenueCat — that aren't openly licensed and are therefore restated as fact rather than copied. ATTRIBUTION.md maps every source to its license and to the skills built on it.
If you redistribute this repo or lift a single skill out of it, keep the source links — that's what the CC BY attribution requirement actually asks for.
name: firebase-auth
description: "Use when setting up auth, managing auth state, implementing email/password or social sign-in, handling auth errors, or managing users."
license: MITThis skill defines how to correctly use Firebase Authentication in Flutter applications.
Use this skill when:
recaptcha-sdk-not-linked for phone auth).flutter pub add firebase_auth
import 'package:firebase_auth/firebase_auth.dart';
Local emulator for testing:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
// ...
}
Use the appropriate stream based on what you need to observe:
| Stream | Fires when |
|---|---|
authStateChanges() | User signs in or out |
idTokenChanges() | ID token changes (including custom claims) |
userChanges() | User data changes (e.g., profile updates) |
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
Create a new account:
try {
final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: emailAddress,
password: password,
);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
Sign in:
try {
final credential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: emailAddress,
password: password,
);
} on FirebaseAuthException catch (e) {
if (e.code == 'invalid-credential') {
// Email enumeration protection enabled (default since Sep 2023):
// replaces 'user-not-found' and 'wrong-password'.
print('Invalid email or password.');
} else if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
user-not-found and wrong-password with invalid-credential. Manage this in the Firebase console under Authentication > Settings.sendPasswordResetEmail() may complete without an error even if the email is not registered. Treat this as expected behavior and do not use password-reset responses to infer whether an email exists.Google Sign-In (native platforms):
Future<UserCredential> signInWithGoogle() async {
final GoogleSignInAccount? googleUser = await GoogleSignIn.instance.authenticate();
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
final credential = GoogleAuthProvider.credential(idToken: googleAuth.idToken);
return await FirebaseAuth.instance.signInWithCredential(credential);
}
Google Sign-In (web):
Future<UserCredential> signInWithGoogle() async {
GoogleAuthProvider googleProvider = GoogleAuthProvider();
googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly');
googleProvider.setCustomParameters({'login_hint': 'user@example.com'});
return await FirebaseAuth.instance.signInWithPopup(googleProvider);
}
signInWithProvider opens a Chrome Custom Tab. If AndroidManifest.xml contains android:taskAffinity="" (Flutter's default), the tab closes when the user switches apps (e.g., to use a password manager), causing a web-context-already-presented error. Remove android:taskAffinity="" to fix this.email and name scopes to present the full first-time sign-in UI (including "Share/Hide email"):
final appleProvider = AppleAuthProvider();
appleProvider.addScope('email');
appleProvider.addScope('name');
revokeTokenWithAuthorizationCode() with the authorization code from userCredential.additionalUserInfo?.authorizationCode.revokeAccessToken() with the access token from userCredential.credential?.accessToken.// Apple platforms (iOS/macOS/web)
final authCode = userCredential.additionalUserInfo?.authorizationCode;
if (authCode != null) {
await FirebaseAuth.instance.revokeTokenWithAuthorizationCode(authCode);
}
// Android
final accessToken = userCredential.credential?.accessToken;
if (accessToken != null) {
await FirebaseAuth.instance.revokeAccessToken(accessToken);
}
Before using phone authentication, ensure platform-specific prerequisites are met:
Phone number sign-in is only supported on real devices and the web. Testing on device emulators is not supported.
iOS: recaptcha-sdk-not-linked error
On iOS, verifyPhoneNumber can throw FirebaseAuthException with code recaptcha-sdk-not-linked when Identity Platform expects reCAPTCHA Enterprise but the native SDK is not linked. This cannot be resolved from Dart — fix it at the native iOS or GCP level:
projects.updateConfig REST API (set recaptchaConfig.phoneEnforcementState to OFF and recaptchaConfig.useSmsTollFraudProtection to false). See the official steps. This reduces fraud protection — prefer linking the SDK.uni_links/app_links or application:openURL: in the iOS runner.try-catch with FirebaseAuthException.e.code to identify specific error types.account-exists-with-different-credential by fetching sign-in methods for the email and guiding users through the correct flow.too-many-requests with retry logic or user feedback.operation-not-allowed by ensuring the provider is enabled in the Firebase console.recaptcha-sdk-not-linked during verifyPhoneNumber is raised by the native Firebase iOS Auth SDK and requires native setup or GCP configuration changes — it cannot be fixed from Dart code alone.// Update profile
await FirebaseAuth.instance.currentUser?.updateProfile(
displayName: "Jane Q. User",
photoURL: "https://example.com/jane-q-user/profile.jpg",
);
// Update email (sends verification to new address first)
await user?.verifyBeforeUpdateEmail("newemail@example.com");
verifyBeforeUpdateEmail() — not updateEmail() — to change a user's email. The email only updates after the user verifies it.linkWithCredential() to connect multiple auth providers to a single account.fetchSignInMethodsForEmail() when handling account linking.FirebaseAuth.instance.signOut() when users exit the app.reauthenticateWithCredential().auth variable to get the signed-in user's UID for access control.Security warning: Avoid SMS-based MFA. SMS is insecure and easy to compromise or spoof.
Platform limitation: Windows does not support MFA. MFA with multiple tenants is not supported on Flutter.
Important: Firebase Dynamic Links is deprecated for email link authentication. Firebase Hosting is now used to send sign-in links.
handleCodeInApp: true in ActionCodeSettings — sign-in must always be completed in the app.SharedPreferences) when sending the sign-in link.
评论 (0)
暂无评论,成为第一个评论者吧!