agentleFS
theyoungastronautstheyoungastronauts/polaris/skills/verify-flutter/SKILL.md

verify-flutter

Skill4 starsChanged 3 months agoMITView on GitHub

Flutter verification checklist — Riverpod, Freezed, Dio, pagination, contract alignment.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run through each section. Flag issues as PASS, WARN, or FAIL.

    line 14

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Skill: Verify Flutter

Purpose

Systematic verification checklist for Flutter/Dart code following the conventions in flutter-patterns.md. Used by the reviewer agent after code execution.

Verification Process

Run through each section. Flag issues as PASS, WARN, or FAIL.

1. Project Structure

  • Feature-based organization: features/{name}/models|services|providers|screens|widgets
  • Core infrastructure in core/ (api, error, router, theme, providers, utils, widgets)
  • File naming follows snake_case.dart convention
  • Generated files co-located (.freezed.dart, .g.dart next to source)
  • No orphan files outside the expected structure

2. Models

  • Freezed with json_serializable — @freezed class with _$ mixin
  • const Model._() private constructor for custom getters
  • factory Model.fromJson() and generated toJson()
  • @JsonKey(name: ...) for snake_case API fields
  • @JsonKey(includeToJson: false) for server-managed fields (id, created_at)
  • factory Model.empty() for form initialization
  • bool get exists for create-vs-update logic
  • Codegen is up to date (build_runner build produces no changes)
  • Model shapes match API response (compare to integration summary)

3. Services

  • Abstract interface defines the contract (abstract class {Feature}Service)
  • Concrete implementation per backend ({Feature}ServiceDjango implements {Feature}Service)
  • save() combines create + update using model.exists
  • No Either/fpdart — errors thrown as typed Failure
  • One service per feature, one implementation per backend

4. Providers

  • @riverpod codegen used everywhere (no hand-written providers)
  • @riverpod (lowercase, auto-dispose) for reads — detail, service binding
  • @Riverpod(keepAlive: true) for forms and auth state
  • AsyncNotifier for stateful operations (forms, paginated lists)
  • Functional providers for simple reads (detail, service binding)
  • AsyncValue.guard() wraps async calls
  • ref.invalidate() called on related providers after mutations
  • Form providers own TextEditingControllers and GlobalKey<FormState>

5. Screens

  • Screens extend BaseScreen
  • Static route() method returns the path string
  • ref.watch() in body() for reactive data, ref.read() for actions
  • AsyncValue.when() handles loading/error/data states
  • context.mounted checked after async operations before navigation

6. Widgets

  • Extracted when exceeding ~40 lines or reused
  • One widget per file in widgets/
  • const constructors with all final fields
  • Composition over inheritance (except BaseScreen)
  • ConsumerWidget only when the widget needs ref
  • No deep nesting — sub-widgets extracted at 3-4 levels
  • Data passed as constructor params, not fetched inside leaf widgets

7. API Client

  • Single Dio instance (no per-request construction)
  • Timeouts configured (connectTimeout, receiveTimeout)
  • Auth interceptor injects Bearer token from session
  • Token refresh handled in interceptor (not scattered across services)
  • 401 response clears session token
  • LogInterceptor gated behind kDebugMode
  • No raw print() statements
  • DioException caught and mapped to typed Failure

8. Auth

  • flutter_secure_storage for token persistence (not SharedPreferences)
  • Session provider is keepAlive: true
  • Auth provider uses AsyncValue<User?> — null means logged out
  • Router watches auth provider and rebuilds on state changes
  • Auth guard redirects unauthenticated users to login
  • Logout clears both session state and secure storage

9. Error Handling

  • Sealed Failure class hierarchy (not generic Exception)
  • Subtypes: ServerFailure, NetworkFailure, AuthFailure, ValidationFailure
  • ValidationFailure carries fieldErrors map
  • Services throw typed failures, not raw exceptions
  • Providers surface errors via AsyncValue.error
  • UI uses ref.listen() or AsyncValue.when() to display errors
  • No swallowed exceptions — every catch block surfaces or rethrows

10. Forms

  • Form provider extends AsyncNotifier with keepAlive: true
  • load(Model) populates controllers from existing data
  • reset() clears state and controllers
  • submit() validates form, calls service, invalidates related providers
  • GlobalKey<FormState> for validation
  • Loading state shown during submission
  • Error messages displayed on failure
  • Form widget uses ConsumerWidget with ref.read() for notifier, ref.watch() for state

11. Lists

  • Paginated list uses AsyncNotifier with page controls
  • Infinite scroll uses PagingController from infinite_scroll_pagination
  • PaginatedResponse<T> model with canLoadMore getter
  • Filtering and ordering passed as query parameters through service
  • RefreshIndicator for pull-to-refresh
  • Empty state shown when no results

12. Testing

  • flutter test passes with no failures
  • mocktail for mocking (not mockito)
  • Service providers overridden in tests — Dio never mocked directly
  • Widget tests wrap with ProviderScope + MaterialApp
  • Tests assert behavior (what user sees), not implementation
  • Business logic has unit tests (services, providers)
  • Key widgets have widget tests

13. Code Quality

  • dart analyze passes with no issues
  • No commented-out code
  • No debug print() statements
  • Imports organized (dart, package, relative)
  • Consistent naming (camelCase variables, PascalCase classes, snake_case files)
  • require_trailing_commas lint enabled and followed

Output

Produce a verification-report.md:

# Verification Report: [Feature/Phase]
Date: [date]
Reviewer: Claude (automated)

## Summary: [PASS/WARN/FAIL]

## Details
### Project Structure: [PASS/WARN/FAIL]
- [notes]

### Models: [PASS/WARN/FAIL]
- [notes]

### Services: [PASS/WARN/FAIL]
- [notes]

...

## Issues Found
1. [FAIL] Description + suggested fix
2. [WARN] Description + recommendation

## Recommended Actions
- [ ] Fix: ...
- [ ] Consider: ...

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.