Magic adapters for the FlutterSDK dev-tooling ecosystem.
Wire Magic's runtime into fluttersdk_dusk (E2E driver) and fluttersdk_telescope (runtime inspector), debug-only with zero release cost.
Documentation · pub.dev · Issues
Alpha Release: part of the Magic ecosystem, under active development. APIs may change before stable. Star the repo to follow progress.
magic_devtools is the Magic adapter layer for fluttersdk_dusk and fluttersdk_telescope. It enriches dusk snapshots and telescope records with Magic-aware context (forms, navigation, controllers, gates, auth, broadcasting, HTTP) so an LLM agent or CI driver sees your app the way Magic sees it.
It is debug-only: you install and wire it under kDebugMode, so release builds tree-shake it entirely and it carries no runtime cost in production. This is exactly why it lives outside magic core; the framework keeps no dev-tooling production dependencies.
Four import barrels:
package:magic_devtools/magic_devtools.dart:MagicDevtoolsis the umbrella one-call wiring:installPre()boots both tool plugins (plus telescope's opt-in exception/dump watchers) beforeMagic.init(),installPost()wires both Magic integrations after it.package:magic_devtools/dusk.dart:MagicDuskIntegrationregisters 14 Magic-aware enrichers into fluttersdk_dusk's snapshot pipeline.package:magic_devtools/telescope.dart:MagicTelescopeIntegrationregisters 5 Magic watchers andMagicHttpFacadeAdapterinto fluttersdk_telescope.package:magic_devtools/preview.dart:MagicPreviewhosts a dev-only component preview catalog via two plain pages (/previewand/preview/:component), tree-shaken from release builds.
magic_devtools and the tooling packages are imported in lib/main.dart (under kDebugMode), so they are regular dependencies, not dev_dependencies; kDebugMode tree-shakes them out of release builds, and because lib/ imports them a dev_dependencies entry would trip the depend_on_referenced_packages lint. This matches how fluttersdk_dusk and fluttersdk_telescope are installed on their own.
dependencies:
magic_devtools: ^0.0.1
fluttersdk_dusk: ^0.0.8 # add if you use dusk
fluttersdk_telescope: ^0.0.4 # add if you use telescopemagic_devtools depends on magic, fluttersdk_dusk, and fluttersdk_telescope directly, so transitive resolution does not happen through magic itself.
Both integrations are debug-only and run in lib/main.dart. The ordering is load-bearing: the dusk/telescope plugin installs before Magic.init() (so the snapshot pipeline is live during Magic boot and the exception watcher catches boot errors), and the Magic integration installs after Magic.init() (its enrichers and adapter resolve Magic primitives through the IoC container).
MagicDevtools collapses the four blocks below into the two halves of that ordering. Keep the kDebugMode guard at the call site: moving it inside the methods would make the call live in release and defeat the tree-shake.
if (kDebugMode) MagicDevtools.installPre(); // dusk + telescope plugins + exception/dump watchers
await Magic.init(configFactories: [...]);
if (kDebugMode) MagicDevtools.installPost(); // MagicTelescopeIntegration + MagicDuskIntegrationReach for the individual barrels below when you need only one tool, or a non-standard telescope watcher set (register extra watchers with TelescopePlugin.registerWatcher after installPre).
if (kDebugMode) {
DuskPlugin.install();
}
await Magic.init(configFactories: [...]);
if (kDebugMode) {
MagicDuskIntegration.install();
}if (kDebugMode) {
TelescopePlugin.install();
}
await Magic.init(configFactories: [...]);
if (kDebugMode) {
MagicTelescopeIntegration.install();
}You can wire either integration on its own, or both together: install each plugin before Magic.init() and each Magic integration after it. The dusk:install and telescope:install Artisan commands wire these blocks into lib/main.dart automatically when magic_devtools is a dependency.
MagicPreview hosts a dev-only component preview catalog: a sidebar of registered components next to each preview rendered in BOTH light and dark, with a global theme toggle bound to wind's WindThemeController. It is reachable only through MagicPreview.registerRoutes(), guarded by kReleaseMode plus const bool.fromEnvironment('PREVIEW_ENABLED', defaultValue: kDebugMode), so the route, the catalog, and every registered PreviewEntry const-fold dead and tree-shake out of release builds.
The router-lock timing is load-bearing: MagicRouter locks its route table on the first routerConfig access, so registration MUST happen in a provider boot() (which runs during the Magic bootstrap lifecycle, before MaterialApp reads routerConfig). Register too late and /preview silently never appears.
class RouteServiceProvider extends ServiceProvider {
RouteServiceProvider(super.app);
@override
Future<void> boot() async {
registerAppRoutes();
if (kDebugMode) {
MagicPreview.register(previewEntries()); // from the generated _previews.g.dart
MagicPreview.registerRoutes();
}
}
}The previews:refresh Artisan command scans *.preview.dart files and regenerates previewEntries() returning a List<PreviewEntry> from a function (never a top-level const, the dart-lang/sdk#33920 retention foot-gun).
| Package | |
|---|---|
| magic | The Laravel experience for Flutter |
| fluttersdk_dusk | E2E driver for LLM agents and CI |
| fluttersdk_telescope | Passive runtime inspector |
git clone https://github.com/fluttersdk/magic_devtools.git
cd magic_devtools && flutter pub get
flutter test && dart analyzeLocal development resolves the magic, fluttersdk_dusk, and fluttersdk_telescope siblings through a gitignored pubspec_overrides.yaml (path entries to the sibling clones). Create one alongside pubspec.yaml:
# pubspec_overrides.yaml (gitignored; local path wiring only)
dependency_overrides:
magic:
path: ../magic
fluttersdk_dusk:
path: ../dusk
fluttersdk_telescope:
path: ../telescopeMIT, see LICENSE for details.
Built with care by FlutterSDK
If magic_devtools helps you, give it a star; it helps others discover it.