Claude Android Ninja
Drjacky/claude-android-ninja
Build and migrate Android apps with Kotlin, Jetpack Compose, MVVM, Hilt, Room 3 (KSP, SQLiteDriver, Flow/suspend DAOs), Navigation3, and multi-module Gradle.
A skill your agent uses when building, structuring, testing or optimizing a Flutter app — feature-first layering, Riverpod 3 or Bloc, typed gorouter, freezed models, a dio data layer, Material 3…
$ npx skills add ericrisco/rsc-harness --skill flutter -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ericrisco/rsc-harness flutter --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/flutter .claude/skills/flutter && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .claude/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ericrisco/rsc-harness/tree/main/skills/flutterType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ericrisco/rsc-harness --skill flutter -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ericrisco/rsc-harness flutter --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/flutter .agents/skills/flutter && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .agents/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill flutter -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ericrisco/rsc-harness flutter --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/flutter .cursor/skills/flutter && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .cursor/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ericrisco/rsc-harness.git --path skills/flutter--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ericrisco/rsc-harness --skill flutter -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ericrisco/rsc-harness flutter --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/flutter .gemini/skills/flutter && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .gemini/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ericrisco/rsc-harness flutterInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ericrisco/rsc-harness --skill flutter -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/flutter .github/skills/flutter && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .github/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill flutter -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ericrisco/rsc-harness flutter --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/flutter .opencode/skills/flutter && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "flutter" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/flutter into .opencode/skills/flutter/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "flutter", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
flutterA skill your agent uses when building, structuring, testing or optimizing a Flutter app — feature-first layering, Riverpod 3 or Bloc, typed gorouter, freezed models, a dio data layer, Material 3…
Flutter is an agent skill from ericrisco/rsc-harness. Use when building, structuring, testing or optimizing a Flutter app — feature-first layering, Riverpod 3 or Bloc, typed gorouter, freezed models, a dio data layer, Material 3, jank hunting, widget/golden tests. Targets Flutter 3.44 / Dart 3.12. NOT React Native (that is react-native), NOT Compose Multiplatform (that is compose-multiplatform).
Its SKILL.md is about 4.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 11 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/architecture-and-state.md`).
It sits in Mobile, covering Cross-platform mobile apps. It works with Flutter, Dart, Jetpack Compose and React Native. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.
Read from SKILL.md and the folder at commit 92fde8f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
Shell commands in SKILL.md call:
flutterFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Flutter loads about 4.4k tokens when it runs, and up to ~19k if it reads all its reference files. Until then it costs about 89 tokens; SKILL.md has 1,164 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from ericrisco/rsc-harness at commit 92fde8f, republished under its MIT licence (© ericrisco). 1,164 words, ~4,353 tokens.
.claude/skills/flutter/SKILL.md (or your agent's skills folder). This skill also uses 8 other files; get the full folder from GitHub.The opinionated default stack for a production Flutter app: feature-first + layered folders,
Riverpod 3 with codegen for shared/async state, a typed go_router, freezed immutable
models, a dio data layer, and explicit Result<T, Failure> error modeling — all on Material 3.
Escape hatches are first-class: Bloc/Cubit instead of Riverpod when the team already runs Bloc,
and raw http/get_it are allowed — but pick one of each per app, never mix two. Pinned versions
this skill targets: Flutter 3.44 / Dart 3.12, Riverpod 3.0, go_router 17.2.x
(+ go_router_builder 4.3.x), freezed 3.x / json_serializable, dio 5.x, mocktail 1.x.
⚠️ SDD new-feature gate — read this first. If this skill fired on a new, non-trivial feature or behaviour change and there is no approved spec + plan under
02-DOCS/wiki/sdd/, STOP — do not write feature code yet. Hand off to../specify/SKILL.mdfirst: it runs brainstorm → spec → plan → tasks before any code, then routes back here once the plan is approved. Build here directly only for a genuinely one-line / low-risk change. Method:../sdd/SKILL.md.
This skill owns the pubspec.yaml subproject and nothing else in the repo. Hand off when the UI is
Compose Multiplatform (compose-multiplatform), SwiftUI/native iOS (swift-ios) or React Native
(react-native); when the work is on a FastAPI/Go/Next.js sibling in the same monorepo (use that
skill). For a pure Dart server/CLI with no widget tree, general Dart applies but skip the
UI/nav/perf references. For a single-file throwaway sample, say architecture is overkill and do not
impose layering.
Around the edges: harness owns the workspace 01-TOOLS/02-DOCS layer and flavor secrets; fastapi,
go and nextjs build the backends this app talks to; secure-coding reviews token handling and
deep-link validation; deployment handles store/CI release; design owns the Material 3 token system.
| Situation | Do this | Not that |
|---|---|---|
| Ephemeral UI state (checkbox, slider, anim) | setState / ValueNotifier locally | a global provider |
| Shared / async state | Riverpod @riverpod Notifier/AsyncNotifier | scattered setState across pages |
| Team already on Bloc | Cubit (simple) / Bloc (event-sourced) | mixing Bloc + Riverpod in one app |
| Multi-state async | AsyncValue / sealed state | bool isLoading + bool isError flags |
| Navigation | one typed go_router | mixing Navigator.push with declarative routes |
| Errors at domain boundary | Result<T, Failure> / sealed | leaking DioException / raw throw to UI |
| Models / DTOs | @freezed abstract class … with _$Name | hand-written mutable classes |
| Cross-feature data | repository behind an interface | widgets calling dio/DB directly |
lib/
main.dart # bootstrap (shared)
main_dev.dart # flavored entrypoint -> runApp(const App(flavor: Flavor.dev))
main_prod.dart
app.dart # MaterialApp.router + ProviderScope wiring
src/
features/
cart/
presentation/ # widgets, screens, Riverpod consumers
domain/ # entities, repository interfaces, Result/Failure (zero Flutter imports)
data/ # DTOs, dio data sources, repository impls
common/
router/ # typed go_router + guards
theme/ # ColorScheme.fromSeed, ThemeExtension tokens
network/ # dio client + interceptors
errors/ # Result, Failure sealed types
widgets/ # shared reusable widgetsDependencies point inward — presentation → domain ← data; domain/ has zero Flutter imports.
See references/architecture-and-state.md for the full layering contract and a worked cart feature.
Null safety — never reach for !:
// BAD — bang crashes in prod when user is null
final n = user!.name;
// GOOD — null-aware + fallback
final n = user?.name ?? 'Unknown';
// GOOD — if-case pattern promotes the binding
if (user case User(:final name)?) {
greet(name);
}
// GOOD — switch expression over a nullable is exhaustive
final label = switch (user) {
User(:final name) => name,
null => 'Guest',
};late — only for guaranteed-before-first-access, prefer late final:
// BAD — defers a null error to runtime
late String id;
// OK — initialized in initState before any access
late final AnimationController _c;Records + destructuring for concurrent multi-return (parallel, not sequential):
// Runs both requests at once; .wait is the Dart 3 record concurrency extension.
final (user, count) = await (repo.user(), repo.count()).wait;Sealed + exhaustive switch eliminates impossible states:
sealed class JobState {}
final class JobIdle extends JobState {}
final class JobRunning extends JobState { const JobRunning(this.pct); final double pct; }
final class JobDone extends JobState { const JobDone(this.url); final String url; }
Widget build(JobState s) => switch (s) {
JobIdle() => const Text('Idle'),
JobRunning(:final pct) => LinearProgressIndicator(value: pct),
JobDone(:final url) => Link(url),
}; // compiler errors if a variant is unhandledasync-gap guard after every await that precedes a context/ref use:
// In a State<T>:
await repo.save();
if (!context.mounted) return;
context.go('/done');
// Inside a Notifier (Riverpod 3):
await repo.save();
if (!ref.mounted) return;
ref.invalidate(listProvider);
// Fire-and-forget must be explicit, not a silently-dropped Future:
unawaited(analytics.log('checkout'));Streams belong in a StreamBuilder, never a manual .listen() in build:
// BAD — leaks a subscription on every rebuild
@override
Widget build(BuildContext context) { stream.listen(_onData); return const SizedBox(); }Extension types give zero-cost ID type-safety so the compiler rejects raw strings:
extension type UserId(String value) {}
extension type OrderId(String value) {}
void loadUser(UserId id) { /* ... */ }
// loadUser('o_42'); // BAD — compile error: String is not a UserId
loadUser(const UserId('u_7')); // GOODIsolates push CPU-bound work off the UI thread:
final parsed = await Isolate.run(() => heavyParse(jsonBig));Error modeling → references/architecture-and-state.md; isolates deep dive → references/performance.md.
// Sync Notifier — list mutation. (Function providers for async reads and
// AsyncNotifier guarded mutation -> references/architecture-and-state.md.)
@riverpod
class CartNotifier extends _$CartNotifier {
@override
List<CartItem> build() => const [];
void add(CartItem item) => state = [...state, item];
void remove(String id) => state = state.where((i) => i.id != id).toList();
}Render AsyncValue with an exhaustive switch; scope rebuilds with .select():
final view = switch (ref.watch(productsProvider)) {
AsyncData(:final value) => ProductList(value),
AsyncError(:final error) => ErrorView(error),
_ => const CircularProgressIndicator(),
};
final count = ref.watch(cartNotifierProvider.select((items) => items.length));ref.watch rebuilds on change; ref.read is for callbacks only; ref.listen is for side-effects.
Riverpod 3 unifies Notifier/AsyncNotifier, merges autoDispose/family into the single @riverpod
annotation, exposes one Ref type, and adds automatic retry, a Mutation API, and @Riverpod(keepAlive: true).
Legacy StateProvider/ChangeNotifierProvider live in package:riverpod/legacy.dart — not for new code.
Wrap the app root in ProviderScope. Codegen, Mutation, family-as-arg, persistence and the DI graph →
references/architecture-and-state.md. Testing → references/testing.md.
Cubit for simple state, Bloc (event → state) for complex/event-sourced flows.
sealed class AuthState {}
final class AuthInitial extends AuthState {}
final class AuthLoading extends AuthState {}
final class AuthAuthed extends AuthState { const AuthAuthed(this.user); final User user; }
final class AuthFailed extends AuthState { const AuthFailed(this.message); final String message; }
class AuthCubit extends Cubit<AuthState> {
AuthCubit(this._repo) : super(AuthInitial());
final AuthRepository _repo;
Future<void> login(String email, String password) async {
emit(AuthLoading());
final res = await _repo.login(email, password);
emit(res.fold((u) => AuthAuthed(u), (f) => AuthFailed(f.message)));
}
}
// UI:
BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) => switch (state) {
AuthInitial() || AuthLoading() => const CircularProgressIndicator(),
AuthAuthed(:final user) => HomeView(user),
AuthFailed(:final message) => ErrorView(message),
},
);// BAD — a Bloc that depends on another Bloc
CartBloc(this.authBloc);
// GOOD — share the repository, not the Bloc
CartBloc(this.cartRepo);Pick one per app, never both. Full event-driven Bloc, BlocObserver, and hydrated_bloc →
references/architecture-and-state.md.
_build*() methods — enables const, element reuse and
RepaintBoundary granularity. Use const everywhere; ValueKey in lists, never UniqueKey in build.Theme.of(context):final theme = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6750A4), brightness: Brightness.light),
);
// BAD color: Colors.blue
// GOOD color: Theme.of(context).colorScheme.primary@TypedGoRoute<HomeRoute>(path: '/', routes: [TypedGoRoute<DetailRoute>(path: 'detail/:id')])
class HomeRoute extends GoRouteData with $HomeRoute {
const HomeRoute();
@override
Widget build(BuildContext context, GoRouterState state) => const HomeScreen();
}
final router = GoRouter(
routes: $appRoutes,
refreshListenable: authListenable,
redirect: (context, state) => authGuard(context, state),
);
const DetailRoute(id: '7').go(context); // typed navigation, no magic stringsSlivers, adaptive/responsive, deep links, StatefulShellRoute, design tokens and a11y →
references/ui-and-navigation.md.
final dio = Dio(BaseOptions(
baseUrl: const String.fromEnvironment('API_URL'),
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 30),
));
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) async {
final token = await secureStorage.read(key: 'auth_token');
if (token != null) options.headers['Authorization'] = 'Bearer $token';
handler.next(options);
},
onError: (error, handler) async {
final isRetry = error.requestOptions.extra['_isRetry'] == true; // one-shot guard
if (!isRetry && error.response?.statusCode == 401 && await refreshToken()) {
error.requestOptions.extra['_isRetry'] = true;
return handler.resolve(await dio.fetch(error.requestOptions));
}
handler.next(error);
},
));// GOOD — boundary returns a mapped Result; UI cannot crash on a wire error
Future<Result<Cart, Failure>> getCart();
// BAD — leaks DioException into widgets
Future<Cart> getCart(); // throws DioException to the UIDTOs are freezed/json_serializable and mapped via CartDto.toDomain(); DTO ≠ entity. Full
repository + Result/Failure + caching → references/architecture-and-state.md.
// Unit — Riverpod 3 container helper.
final container = ProviderContainer.test();
final cart = container.read(cartNotifierProvider);
// Widget — override the controller with a fake.
await tester.pumpWidget(ProviderScope(
overrides: [cartControllerProvider.overrideWith(FakeCartController.new)],
child: const MaterialApp(home: CartScreen()),
));
// Golden — deterministic pixel comparison.
await expectLater(find.byType(CartCard), matchesGoldenFile('goldens/cart_card.png'));Every async state transition has a test (loading → data, loading → error). pumpAndSettle hangs on
infinite animations (spinners) — use an explicit pump(const Duration(milliseconds: 300)) there. Full
pyramid, repository tests, blocTest, golden determinism and coverage → references/testing.md.
const + extract-to-class so only the changing subtree rebuilds.RepaintBoundary around independently-animating subtrees; ListView.builder for long lists.cacheWidth/cacheHeight to decode-at-size; cached network images with placeholder/error..select() / BlocSelector / buildWhen.flutter run --profile; DevTools → "Track Widget Rebuilds", raster vs UI thread.Rebuild/paint/jank workflow, isolates and build flavors → references/performance.md.
flutter_localizations + gen_l10n (set generate: true, add l10n.yaml); one
ARB file per locale, strings read type-safely through AppLocalizations.of(context).{count, plural, =0{…} =1{…} other{…}}), never an
if (count == 1) ladder in Dart.EdgeInsetsDirectional/AlignmentDirectional (auto-mirrors); mirror directional icons, never
logos or numbers. Format numbers/dates/currency with intl NumberFormat/DateFormat (locale-aware), never by hand.flutter pub outdated. In a multi-package repo, melos orchestrates bootstrap/scripts and package:
encapsulation (public API via lib/<pkg>.dart, internals under lib/src/, enforced by implementation_imports).ARB + ICU plurals, RTL geometry, locale-aware formatting, pub points/pana, melos and workspace
encapsulation → references/i18n-and-dependencies.md.
FlutterError.onError + PlatformDispatcher.instance.onError + ErrorWidget.builder wired to Crashlytics/Sentry.--dart-define / --dart-define-from-file; tokens in secure storage (Keychain / EncryptedSharedPreferences), never plaintext.analysis_options.yaml: strict-casts / strict-inference / strict-raw-types + flutter_lints or very_good_analysis.flutter_localizations + ARB (ICU plurals, RTL-safe geometry, locale-aware intl formatting);
a11y (48px targets, Semantics, contrast ≥ 4.5:1).pubspec.lock committed for apps, flutter pub outdated audited on a cadence,
dependencies vetted by pub points before adding.print() → dart:developer log().scripts/verify.sh, run inside the Flutter project (format / codegen / analyze / tests).| Anti-pattern | Why it fails / do instead |
|---|---|
user! to unwrap | bang crashes in prod; use ?./?? or an if-case pattern. |
_buildHeader() helper methods | extract to a const widget class — enables element reuse + const propagation. |
setState at the top of the page | rebuilds the whole subtree; scope it or .select(). |
Navigator.push mixed into go_router for one screen | one router; mixing breaks deep links + back stack. |
context used after an await | guard context.mounted / ref.mounted; a stale context crashes. |
hardcoded Colors.blue | use colorScheme; hardcoding breaks dark mode + theming. |
ListView(children: [...]) for a feed | use .builder; the concrete form builds all children eagerly. |
catch (e) on everything | use on-typed clauses; never catch Error (it is a bug). |
raw DioException.toString() shown to the user | map to a Failure with a localized message. |
print() for logging | use dart:developer log() — has levels and can be filtered. |
In a project with a 02-DOCS/ layer (the harness wiki), this app's decisions
live in 02-DOCS/wiki/stack/flutter.md, indexed in 02-DOCS/wiki/index.md. Read it first and stay
consistent. Missing or stale? Write the real choices there — state management (Riverpod/Bloc), the
architecture layers, routing, the Material 3 token system, codegen setup — index it, and bump its
Updated date in the same change a convention changes, so the next agent inherits it instead of
re-deriving it. No 02-DOCS/ layer? Skip silently: technical conventions are recorded, not gated,
so never block the task on this.
© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 8 other files (scripts, references) in skills/flutter of ericrisco/rsc-harness.
Open the folder on GitHubat commit 92fde8f
Flutter next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Flutter this skillericrisco/rsc-harness | 156 | — | ~4.4k | Automated safety check: Pass | MIT | |
| Claude Android NinjaDrjacky/claude-android-ninja | 124 | — | ~5.2k | Automated safety check: Pass | Apache-2.0 | |
| SimdeckNativeScript/SimDeck | 152 | — | ~3.6k | Automated safety check: Pass | MIT | |
| Oma Mobilefirst-fluke/oh-my-agent | 1.3k | — | ~1.6k | Automated safety check: Pass | MIT | |
| Mobile Developeraiskillstore/marketplace | 430 | 6 repos | ~2.3k | Automated safety check: Pass | None | |
| Developing Mobile Appstelagod/code-abyss | 244 | — | ~258 | Automated safety check: Pass | MIT |
Drjacky/claude-android-ninja
Build and migrate Android apps with Kotlin, Jetpack Compose, MVVM, Hilt, Room 3 (KSP, SQLiteDriver, Flow/suspend DAOs), Navigation3, and multi-module Gradle.
NativeScript/SimDeck
A skill your agent uses for simulator lifecycle, app install/launch, live viewing, UI inspection, touch/keyboard automation, screenshots, recordings, logs, pasteboard, hardware controls, and…
first-fluke/oh-my-agent
Mobile specialist for Flutter, React Native, and cross-platform mobile development.
aiskillstore/marketplace
Develop React Native, Flutter, or native mobile apps with modern architecture patterns.
telagod/code-abyss
Mobile development knowledge reference covering iOS (SwiftUI), Android (Jetpack Compose), React Native, and Flutter.
borghei/Claude-Skills
A skill your agent uses when the user asks to "build a mobile app", "scaffold React Native project", "create SwiftUI views", "set up Jetpack Compose", "optimize mobile performance", "configure Expo…
ericrisco/rsc-harness
A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…
ericrisco/rsc-harness
A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…
ericrisco/rsc-harness
A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…
ericrisco/rsc-harness
A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…
ericrisco/rsc-harness
A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…
ericrisco/rsc-harness
A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.
Works with
Categories
A skill your agent uses when building, structuring, testing or optimizing a Flutter app — feature-first layering, Riverpod 3 or Bloc, typed gorouter, freezed models, a dio data layer, Material 3…. Flutter is an agent skill from ericrisco/rsc-harness. Use when building, structuring, testing or optimizing a Flutter app — feature-first layering, Riverpod 3 or Bloc, typed gorouter, freezed models, a dio data layer, Material 3, jank hunting, widget/golden tests.
Flutter fits situations like: optimizing a Flutter app — feature-first layering; A dio data layer; widget/golden tests.
Run `npx skills add ericrisco/rsc-harness --skill flutter -a claude-code`. Or copy the skill folder (skills/flutter in ericrisco/rsc-harness) into .claude/skills/flutter in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ericrisco/rsc-harness --skill flutter -a codex`. Or copy the skill folder (skills/flutter in ericrisco/rsc-harness) into .agents/skills/flutter in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill flutter -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/flutter, .gemini/skills/flutter, .github/skills/flutter and .opencode/skills/flutter in your project.
Going by SKILL.md and its folder, Flutter needs a shell for the scripts in its folder and the command-line tools its instructions call (flutter). Our summary lists: A Bash shell.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Flutter is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.4k tokens (SKILL.md is roughly 17k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 15k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Flutter: Claude Android Ninja (Drjacky/claude-android-ninja, 124 stars), Simdeck (NativeScript/SimDeck, 152 stars), Oma Mobile (first-fluke/oh-my-agent, 1.3k stars) and Mobile Developer (aiskillstore/marketplace, 430 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 156 GitHub stars. The repository holds 229 skills in this directory. The repository was last updated on October 6, 2026.
Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.