make:plugin
Scaffold a new dowel plugin skeleton under packages/<name>/ (or a
custom target directory). Produces a fully wired, immediately testable plugin package
in a single command.
On this page
Basic Usage#
dart run dowel make:plugin <name>
<name> must be a valid Dart package name: snake_case, starts with a lowercase
letter, contains only [a-z0-9_]. Writes to <projectRoot>/packages/<name>/ by
default and enrolls the new plugin into the parent Flutter app's pub workspace when
one is detected.
Synopsis#
make:plugin {name} {--path=} {--target=} {--magic} {--bootstrap-command=}
| Argument / Option | Description |
|---|---|
name |
Plugin package name in snake_case (required). |
--path=<dir> |
Target directory. Takes precedence over --target when both are set. |
--target=<dir> |
Target directory (alias for --path). |
--magic |
Scaffold a magic-aware plugin: adds install.yaml, Magic ServiceProvider, install/uninstall commands, and the magic dep to pubspec.yaml. Entirely optional. |
--bootstrap-command=<cmd> |
Override the default bootstrap command name (default: <commandPrefix>:install). |
Two Modes#
Generic mode (default)#
Running without --magic produces a Magic-free plugin. Stubs sourced from
assets/stubs/make_plugin/generic/:
pubspec.yaml, bin/<name>.dart, lib/cli.dart, lib/<name>.dart,
lib/src/<name>_dowel_provider.dart, test/<name>_dowel_provider_test.dart,
README.md.
The generic plugin exposes a single DowelServiceProvider subclass with an empty
mcpTools() override. No dependency on magic or any other framework is added.
Magic mode (--magic)#
When --magic is passed (or auto-detected because magic:install is in the running
registry), four generic stubs are replaced by variants from
assets/stubs/make_plugin/magic/ (pubspec.yaml, cli.dart, runtime.dart,
provider.dart), and six additional files are written from the same directory:
| Stub | Written to |
|---|---|
install_command.dart |
lib/src/commands/install_command.dart |
uninstall_command.dart |
lib/src/commands/uninstall_command.dart |
install.yaml |
install.yaml |
config_stub.dart |
assets/stubs/install/<name>_config.dart.stub |
install_command_test.dart |
test/cli/install_command_test.dart |
service_provider.dart |
lib/src/<name>_service_provider.dart |
Magic mode wires a ManifestInstaller-compatible install.yaml manifest, a
Magic-aware ServiceProvider, and install/uninstall commands with test
scaffolds. The parent app's plugin:install can then resolve the manifest
automatically.
8-Phase Pipeline#
-
Validate name. Reject empty or non-snake_case names with an actionable error. Mirrors Dart's pubspec
name:rule. -
Resolve target directory. Flag precedence:
--pathwins over--target; both override the default<projectRoot>/packages/<name>/. -
Spawn
flutter create --template=package. Lays down the baseline package:pubspec.yaml,LICENSE,CHANGELOG.md,.gitignore,.metadata,analysis_options.yaml,lib/<name>.dart,test/<name>_test.dart,README.md. -
Render generic stubs. Seven files from
assets/stubs/make_plugin/generic/overwriteflutter create's defaults. Placeholders ({{ name }},{{ pascalName }},{{ dowelPath }},{{ commandPrefix }}) are substituted at render time. In magic mode, four stubs are sourced fromassets/stubs/make_plugin/magic/instead. -
Render magic add-ons (magic mode only). Six additional files from
assets/stubs/make_plugin/magic/are written. The{{ magicPath }}placeholder (relative path to themagicpackage root) is only available in this phase. -
Detect parent Flutter app.
WorkspaceEnroller.detectParentFlutterAppwalks up from the target directory looking for a parent Flutter apppubspec.yaml. -
Enroll in workspace (when parent detected). Adds
resolution: workspaceto the plugin'spubspec.yamland appends the plugin's relative path to the parent app'sworkspace:list. -
Print success banner. Reports the scaffolded path,
cd <target> && dart pub get && dart test, and whether the parent app'spubspec.yamlwas modified.
Output Layout#
packages/<name>/
├── bin/
│ └── <name>.dart # CLI entry point
├── lib/
│ ├── <name>.dart # Runtime barrel
│ ├── cli.dart # CLI barrel
│ └── src/
│ ├── <name>_dowel_provider.dart # DowelServiceProvider subclass
│ ├── <name>_service_provider.dart # [magic] Magic ServiceProvider
│ └── commands/
│ ├── install_command.dart # [magic]
│ └── uninstall_command.dart # [magic]
├── assets/stubs/install/
│ └── <name>_config.dart.stub # [magic] config template
├── test/
│ ├── <name>_dowel_provider_test.dart
│ └── cli/
│ └── install_command_test.dart # [magic]
├── install.yaml # [magic] ManifestInstaller manifest
├── pubspec.yaml
└── README.md
Items without [magic] are present in both modes.
Examples#
Generic plugin at the default location:
dart run dowel make:plugin magic_logger
Writes to packages/magic_logger/. Strips the magic_ prefix:
commandPrefix=logger, bootstrap command defaults to logger:install.
Magic-aware plugin:
dart run dowel make:plugin magic_logger --magic
Same layout plus install.yaml, service_provider.dart, install/uninstall commands,
a config stub, and the magic path dependency in pubspec.yaml.
Plugin at a custom path:
dart run dowel make:plugin my_analytics --path=/workspace/plugins/my_analytics
Writes to the absolute path. Workspace enrollment still runs: if a parent Flutter app is found above that path, the plugin is enrolled.
Workspace Enrollment#
When the target directory lives inside or adjacent to a Flutter application,
WorkspaceEnroller walks the directory tree upward. On finding a parent
pubspec.yaml that declares a Flutter dependency:
- The plugin's
pubspec.yamlgainsresolution: workspace. - The parent app's
pubspec.yamlgains aworkspace:entry pointing to the plugin's relative path.
After enrollment, a single flutter pub get in the parent app resolves all workspace
members together. When no parent Flutter app is detected, the plugin is left as a
standalone package and the success banner reports the outcome.
Related Documentation#
- make:command: scaffold a single
DowelCommandsubclass inside an existing consumer project or plugin. - plugins:refresh: regenerate
lib/app/_plugins.g.dartfrom.dowel/plugins.jsonafter manually editing the registry. - plugin:install: register a third-party plugin (resolves
install.yamlmanifests produced bymake:plugin --magic).