This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Flutter Skill is a bridge that connects AI Agents to running Flutter applications via the Dart VM Service Protocol. It enables agents to inspect UI structure, perform actions (tap, scroll, enter text), and verify visual changes.
# Activate the CLI globally (from this repo)
dart pub global activate --source path .
# Run the CLI directly without global activation
dart run bin/flutter_skill.dart <command>
# Launch a Flutter app with auto-setup (adds dependency + patches main.dart)
flutter_skill launch /path/to/flutter_project
# Inspect interactive widgets in running app
flutter_skill inspect
# Perform actions
flutter_skill act tap "button_key"
flutter_skill act enter_text "field_key" "text value"
# Run integration tests (uses mock Flutter app)
dart run test/integration_test.dartThe codebase has two main parts:
1. Target App Library (lib/flutter_skill.dart)
FlutterSkillBinding- Registers VM Service extensions in the Flutter app- Extensions:
ext.flutter.flutter_skill.interactive,.tap,.enterText,.scroll - Target apps call
FlutterSkillBinding.ensureInitialized()in main.dart
2. CLI/Server Tools (lib/src/)
lib/src/drivers/- Framework-specific app driversapp_driver.dart- AbstractAppDriverinterface (connect, tap, screenshot, etc.)flutter_driver.dart-FlutterSkillClient implements AppDriver— VM Service clientnative_driver.dart- Native OS-level interaction (macOS Accessibility API, adb)drivers.dart- Barrel export
lib/src/discovery/- VM Service auto-discoveryunified_discovery.dart- Smart multi-strategy discovery orchestratorprocess_based_discovery.dart- Discovers apps from running Flutter processesdtd_service_discovery.dart- DTD-based discoveryquick_port_check.dart- Parallel port scanningdiscovery.dart- Barrel export
lib/src/cli/- CLI command implementations (launch, inspect, act, server, setup)lib/src/diagnostics/- Error reporting- MCP Server mode (
cli/server.dart) - JSON-RPC interface for IDEs like Cursor
Entry Points:
bin/flutter_skill.dart- Main CLI entry point, routes to subcommandsbin/server.dart- Standalone MCP server entry point
Connection Flow:
launchrunsflutter run, captures VM Service URI from stdout- URI saved to
.flutter_skill_urifor subsequent commands FlutterSkillClientconnects via WebSocket, finds main isolate- Commands invoke registered extensions on the running app
Backward Compatibility:
lib/src/flutter_skill_client.dartis a re-export shim pointing todrivers/flutter_driver.dart
lib/flutter_skill.dart- The binding that target apps importlib/src/drivers/app_driver.dart- Abstract driver interface for multi-framework supportlib/src/drivers/flutter_driver.dart- VM Service client wrapper (FlutterSkillClient)lib/src/discovery/unified_discovery.dart- Smart VM Service discoverylib/src/cli/setup.dart- Auto-patches pubspec.yaml and main.darttest/bin/flutter- Mock flutter CLI for integration tests
CRITICAL: ALWAYS use the release script. NEVER bump versions or commit/tag/push manually.
When the user asks to release a new version, run:
./scripts/release.sh X.Y.Z "Brief description"Example:
./scripts/release.sh 0.9.9 "C++ desktop automation SDK"The script handles everything: version bumps across all files, CHANGELOG entry, git commit, tag, and push — which triggers GitHub Actions to auto-publish to pub.dev, npm, VSCode, JetBrains, Homebrew, Scoop, MCP Registry, and GitHub Release.
Never do any of these steps manually (no sed version bumps, no git tag, no git push --tags, no gh release create) unless the script explicitly fails and you explain why to the user first.
-
Prepare CHANGELOG
- If there's a
RELEASE_NOTES_vX.Y.Z.md, extract key points - Add concise entry to
CHANGELOG.md(at the top) - Follow existing format: version, description, features, docs
- If there's a
-
Update Version Numbers
pubspec.yaml- version: X.Y.Zlib/src/cli/server.dart- const String _currentVersion = 'X.Y.Z'packaging/npm/package.json- "version": "X.Y.Z"vscode-extension/package.json- "version": "X.Y.Z"intellij-plugin/build.gradle.kts- version = "X.Y.Z"intellij-plugin/src/main/resources/META-INF/plugin.xml- X.Y.ZREADME.md- flutter_skill: ^X.Y.Z
-
Commit and Tag
First confirm the release will be cut from
origin/main— the tag is what triggers the release workflow, so a tag that is not onmainpublishes from a commit nobody can see. This is how v0.9.24 and v0.9.36 shipped the wrong tree.git fetch origin main git rev-parse main origin/main # must print the same SHA twice git add -A git commit -m "chore: Release vX.Y.Z\n\n<description>" git tag vX.Y.Z # --atomic, never `--tags`: without it a rejected branch update still lets # the tag through, and CI then publishes from an orphaned commit. git push --atomic origin main refs/tags/vX.Y.Z
-
Verify
- Check GitHub Actions: https://github.com/ai-dashboad/flutter-skill/actions
- Verify auto-publish to: pub.dev, npm, VSCode, JetBrains, Homebrew
Follow Semantic Versioning:
MAJOR.MINOR.PATCH(e.g., 0.3.1)- PATCH (0.3.0 → 0.3.1): Bug fixes, optimizations, small improvements
- MINOR (0.3.0 → 0.4.0): New features, backward-compatible changes
- MAJOR (0.x.x → 1.0.0): Breaking changes, major refactor
See RELEASE_PROCESS.md for:
- Detailed manual steps
- Troubleshooting
- Special release scenarios
- Post-release checklist
CRITICAL: For ANY Flutter app testing, ALWAYS use flutter-skill MCP tools, NEVER use Dart MCP.
| User Request | Tool to Use | DO NOT USE |
|---|---|---|
| Test Flutter app | flutter-skill |
❌ Dart MCP |
| Launch app | launch_app with --vm-service-port=50000 |
❌ mcp__dart__launch_app |
| Get logs | get_logs |
❌ mcp__dart__get_app_logs |
| Hot reload | hot_reload |
❌ mcp__dart__hot_reload |
| Inspect UI | inspect |
❌ mcp__dart__get_widget_tree |
| Tap/swipe/screenshot | tap, swipe, screenshot |
❌ Dart MCP (lacks these) |
- ✅ Complete UI automation: tap, swipe, screenshot, input
- ✅ VM Service protocol: Full access to app internals
- ✅ All testing needs: Lifecycle + UI + debugging in ONE tool
- ✅ 100% capability: vs Dart MCP's ~40%
Dart MCP limitations:
- ❌ No tap/click
- ❌ No swipe/scroll
- ❌ No screenshot
- ❌ No text input
- ❌ Read-only inspection
- ❌ Only ~40% of testing needs
Flutter 3.x Auto-Configuration:
The launch_app tool automatically adds --vm-service-port=50000 for Flutter 3.x compatibility.
You don't need to specify it manually!
# ✅ Simplest usage (auto-configured)
launch_app(
project_path: ".",
device_id: "iPhone 16 Pro"
)
# Automatically becomes: flutter run -d "iPhone 16 Pro" --vm-service-port=50000
# ✅ With custom VM Service port (if needed)
launch_app(
project_path: ".",
device_id: "iPhone 16 Pro",
extra_args: ["--vm-service-port=8888"] # Custom port
)
# ❌ Wrong - Don't use Dart MCP for Flutter testing
mcp__dart__launch_app(...) # ❌ Don't use thisNote: Since v0.3.2+, --vm-service-port=50000 is auto-added by default.
If you still see "Found DTD URI but no VM Service URI" error (rare):
- ✅ Check if the app is using a custom Flutter version
- ✅ Verify the Flutter output logs for any VM Service errors
- ✅ Try specifying a custom port:
extra_args: ["--vm-service-port=8888"] - ❌ DO NOT switch to Dart MCP for Flutter testing
The error should be extremely rare now that auto-configuration is enabled.
- Do not include "Co-Authored-By: Claude" in commit messages
- Always update CHANGELOG.md when releasing
- Keep release notes concise but informative
- Test on all platforms before major releases
- CRITICAL: For Flutter testing, ALWAYS use flutter-skill, NEVER Dart MCP
IMPORTANT: All documentation and code comments MUST be in English.
- All code comments (inline comments, doc comments, TODO comments)
- All documentation files (README.md, CHANGELOG.md, etc.)
- All error messages and log output in code
- All variable names, function names, class names
- All commit messages
- All PR descriptions and issue comments
lib/src/discovery/dtd_service_discovery.dart- Chinese commentslib/src/cli/server.dart- Chinese in tool descriptionstest/flutter_skill_complete_test.dart- Chinese test output
- Write all comments in English
- Use English for all user-facing strings
- Keep consistent terminology with existing English documentation