Flow-level aspect tracing and architecture scanning for Flutter apps.
FlutterGuard connects user actions to async spans, network requests, route transitions, errors, frame metrics, rebuild boundaries, and static architectural risks — all in a single correlated report.
| Not a crash SDK | Not an HTTP inspector | Not a logger |
|---|---|---|
| FlutterGuard doesn't replace Sentry/Crashlytics. It connects runtime behavior into structured traces. | Alice/Charles log request bodies. FlutterGuard records only what happened — method, path, status, duration — attached to your flow. | Debug logs are unstructured and ephemeral. FlutterGuard produces exportable, correlation-first reports. |
FlutterGuard answers questions like:
- "Why did this user action take 2 seconds?" — spans, network, frames
- "Where did the error occur in the lifecycle of this action?" — error within flow context
- "Which files are architectural risks in this project?" — static scan
- "Did a rebuild cascade during this checkout?" — GuardBoundary counters
# pubspec.yaml
dependencies:
flutterguard_flutter: ^0.1.0
flutterguard_dio: ^0.1.0 # if using Diodart pub global activate flutterguard_cli
# OR compile to native binary:
git clone https://github.com/your-org/flutterguard.git
cd flutterguard
dart compile exe packages/flutterguard_cli/bin/flutterguard.dart -o flutterguardimport 'package:flutterguard_flutter/flutterguard_flutter.dart';
void main() {
FlutterGuard.run(
app: MaterialApp(
navigatorObservers: [FlutterGuard.routeObserver],
home: HomePage(),
),
);
}ElevatedButton(
onPressed: () {
FlutterGuard.action('checkout', () async {
// spans auto-attach to this flow
final valid = await FlutterGuard.span('validate_cart', () => validate());
if (valid) {
await FlutterGuard.span('process_payment', () => process());
}
});
},
child: Text('Checkout'),
)final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
dio.interceptors.add(FlutterGuardDioInterceptor());GuardBoundary(
name: 'CheckoutPage',
child: CheckoutView(),
)final report = FlutterGuard.exportMarkdown();
print(report);
final json = FlutterGuard.exportJson();
await File('report.json').writeAsString(json);flutterguard scan --path ./my_projectInitializes all hooks and starts the Flutter app. Must be called before runApp.
FlutterGuard.run(
config: const FlutterGuardConfig(
enabled: true,
collectErrors: true,
collectFrames: true,
collectRoutes: true,
collectBuilds: true,
slowFlowMs: 1000,
jankFrameMs: 16,
maxTraces: 100,
),
app: MyApp(),
);Creates a new flow trace. All spans, network calls, errors, routes, and frame metrics within body are automatically correlated.
await FlutterGuard.action('login', () async {
final token = await auth.login(username, password);
storage.saveToken(token);
}, tags: {'screen': 'login'});Creates a child span under the current flow. If no active flow, executes body directly without recording.
final data = await FlutterGuard.span('fetch_user', () => api.getUser(id));Add to MaterialApp.navigatorObservers. Records push, pop, replace, remove events.
MaterialApp(
navigatorObservers: [FlutterGuard.routeObserver],
// ...
)Wrap any widget to count rebuilds within an active flow.
GuardBoundary(
name: 'ProductList',
child: ProductListView(),
)Returns the current flow trace ID from the Zone, or null.
final traceId = FlutterGuard.currentTraceId;Export all recorded traces as structured reports.
final json = FlutterGuard.exportJson(); // JSON
final md = FlutterGuard.exportMarkdown(); // MarkdownClears all stored traces.
FlutterGuard.reset();FlutterGuardDioInterceptor(
sanitizeHeaders: true,
sanitizeBody: true,
sensitiveKeys: ['authorization', 'password'],
)Default sensitive keys: authorization, cookie, set-cookie, token, password, secret, email, phone
Records method, path, status code, duration, success/failure. Does NOT log request/response bodies.
flutterguard scan [options]
Options:
-p, --path Project path to scan (default: .)
-c, --config Config file path (default: flutterguard.yaml)
-f, --format Output format: json | markdown | both (default: both)
-o, --output Output directory (default: .flutterguard)
--fail-on CI gate threshold: none | high | medium | low (default: none)
--min-score Minimum score 0-100
Output files:
.flutterguard/report.json— machine-readable.flutterguard/report.md— human-readable
include:
- lib/**
- test/**
exclude:
- lib/generated/**
- lib/**.g.dart
- lib/**.freezed.dart
- lib/**.mocks.dart
rules:
large_file:
enabled: true
maxLines: 500
large_class:
enabled: true
maxLines: 300
large_build_method:
enabled: true
maxLines: 80
lifecycle_resource:
enabled: true
boundaries:
- name: cart_module
from: lib/cart/**
forbidden:
- lib/checkout/**
- lib/payment/**GitHub Actions:
- name: FlutterGuard Scan
run: |
dart pub global activate flutterguard_cli
flutterguard scan --path . --fail-on highPre-commit (local):
#!/bin/bash
flutterguard scan --path . --fail-on mediumExit codes: 0 = pass, 1 = gate failed, 2 = error
| Rule | Level | What it detects |
|---|---|---|
large_file |
medium | Files exceeding maxLines (default 500) |
large_class |
medium | Classes exceeding maxLines (default 300) |
large_build_method |
medium | Widget build() methods exceeding maxLines (default 80) |
lifecycle_resource_not_disposed |
high | StreamSubscription, Timer, AnimationController, TextEditingController, ScrollController, FocusNode without matching cancel/dispose |
boundary_import_violation |
high | Imports that violate configured module boundaries |
Scoring: 100 base — 10 per high — 4 per medium — 1 per low (minimum 0)
{
"version": "1.0.0",
"generatedAt": "2026-05-16T12:00:00.000Z",
"projectPath": "/Users/you/my_app",
"score": 85,
"summary": { "high": 1, "medium": 2, "low": 1, "total": 4 },
"staticIssues": [
{
"id": "lifecycle_resource_not_disposed",
"title": "Lifecycle resource not disposed",
"file": "/Users/you/my_app/lib/widgets/player.dart",
"line": 42,
"level": "high",
"message": "AnimationController \"_controller\" in \"PlayerWidget\" may not be properly disposed.",
"suggestion": "Call \"_controller.dispose()\" in the dispose() method.",
"metadata": {
"className": "PlayerWidget",
"resourceType": "AnimationController",
"fieldName": "_controller",
"expectedDisposeCall": "dispose"
}
}
]
}Comprehensive report with sections: Summary, Static Issues (High/Medium/Low), Runtime Flows, and CI Result.
-
FlutterGuard.action()— flow-level trace creation with Zone context -
FlutterGuard.span()— async child spans, auto-correlated -
FlutterGuard.run()— automatic error hooks, frame metrics, route observer -
FlutterGuardRouteObserver— records push/pop/replace/remove -
GuardBoundary— widget rebuild counting -
FlutterGuardDioInterceptor— Dio 5.x HTTP tracing - CLI static scan — 5 rules, YAML config, JSON/Markdown reports
- CI gate —
--fail-onthreshold-based exit codes - Score system — 0-100 based on issue severity
- Demo app — checkout flow with all integrations
- AI-based diagnosis or auto-fix
- DevTools extension
- MQTT, BLE, or Matter protocol tracing
- Riverpod/BLoC/GetX state management adapters
- Full HTTP body inspection
- Crash SDK replacement (Sentry/Crashlytics)
- IDE lint plugin integration
Running the demo checkout flow:
# FlutterGuard Report
**Generated**: 2026-05-16T12:00:00.000Z
**Score**: 100 / 100
## Summary
| Level | Count |
|-------|-------|
| High | 0 |
| Medium | 0 |
| Low | 0 |
| **Total** | **0** |
## Runtime Flows
### submit_order `4b7d261143d5`
- **Status**: success
- **Duration**: 250ms
#### Spans
| Name | Duration | Error |
|------|----------|-------|
| validate_form | 100ms | - |
| request_create_order | 42ms | - |
#### Network
| Method | Path | Status | Duration |
|--------|------|--------|----------|
| POST | /posts | 201 | 42ms |
#### Routes
| Type | From | To |
|------|------|----|
| push | / | OrderResult |
#### Build Boundaries
- **CheckoutPage**: 1 rebuilds
---
| Milestone | Timeline | Focus |
|---|---|---|
| M1 | Current | Flow tracing + static scan MVP |
| M2 | Q3 2026 | Type-accurate lifecycle detection, cycle detection, custom plugins |
| M3 | Q4 2026 | DevTools extension, Sentry bridge, timeline integration |
| M4 | 2027 | Enterprise features, multi-isolate, storage backends |
# Clone and bootstrap
git clone <repo-url>
cd flutterguard
melos bootstrap
# Analyze all packages
melos run analyze
# Run tests
dart test packages/flutterguard_core
dart test packages/flutterguard_dio
dart test packages/flutterguard_cli
flutter test packages/flutterguard_flutter
# Run the tracing API demo
dart run examples/usage_demo/bin/trace_demo.dart
# Scan the demo project
dart pub global activate --source path packages/flutterguard_cli
flutterguard scan --path examples/scan_demoMIT