What happened
specify bundle install installs an extension without scaffolding the config templates the extension declares in provides.config. Installing the same extension with specify extension add does scaffold them.
Extension manifest:
provides:
config:
- name: github-lifecycle-config.yml
template: config-template.yml
After specify extension add --dev <path>:
Config scaffolded:
• .specify/extensions/github-lifecycle/github-lifecycle-config.yml
After specify bundle install <bundle-id>, with the same extension resolved from a catalog:
$ ls .specify/extensions/github-lifecycle/
CHANGELOG.md README.md commands config-template.yml extension.yml scripts
The template is present, but the config file it is meant to produce is not.
Cause
ExtensionManager.scaffold_config is called from the extension add command flow in src/specify_cli/extensions/_commands.py:
# Scaffold config templates automatically
deployed, skipped, failed = manager.scaffold_config(manifest.id)
ExtensionPrimitive in src/specify_cli/bundler/services/primitives.py calls install_from_directory / install_from_zip directly and never calls scaffold_config, so the bundler path skips it.
Version
Reproduced on v1.0.1 (macOS, Python 3.13).
Impact
An extension installed as part of a bundle silently has no configuration. Any command or script that reads the config finds nothing, and the difference is invisible unless the user compares the two install paths. It also means an extension behaves differently depending on how it was installed, which makes bundle installation not equivalent to installing its components individually.
Suggested fix
Call scaffold_config from ExtensionPrimitive after install, and surface the same deployed/skipped/failed reporting the command flow produces.
Related
The naming rule enforced by _target_follows_preserved_convention (a config target must be a top-level *-config.yml or *-config.local.yml) is not documented in EXTENSION-API-REFERENCE.md. A manifest that declares any other target name is accepted at publish time and silently never scaffolds, reporting only Warning: Config templates not scaffolded: <name> with no explanation of the constraint. Documenting the rule, or naming it in that warning, would make the failure self-explanatory.
What happened
specify bundle installinstalls an extension without scaffolding the config templates the extension declares inprovides.config. Installing the same extension withspecify extension adddoes scaffold them.Extension manifest:
After
specify extension add --dev <path>:After
specify bundle install <bundle-id>, with the same extension resolved from a catalog:The template is present, but the config file it is meant to produce is not.
Cause
ExtensionManager.scaffold_configis called from theextension addcommand flow insrc/specify_cli/extensions/_commands.py:ExtensionPrimitiveinsrc/specify_cli/bundler/services/primitives.pycallsinstall_from_directory/install_from_zipdirectly and never callsscaffold_config, so the bundler path skips it.Version
Reproduced on
v1.0.1(macOS, Python 3.13).Impact
An extension installed as part of a bundle silently has no configuration. Any command or script that reads the config finds nothing, and the difference is invisible unless the user compares the two install paths. It also means an extension behaves differently depending on how it was installed, which makes bundle installation not equivalent to installing its components individually.
Suggested fix
Call
scaffold_configfromExtensionPrimitiveafter install, and surface the same deployed/skipped/failed reporting the command flow produces.Related
The naming rule enforced by
_target_follows_preserved_convention(a config target must be a top-level*-config.ymlor*-config.local.yml) is not documented inEXTENSION-API-REFERENCE.md. A manifest that declares any other target name is accepted at publish time and silently never scaffolds, reporting onlyWarning: Config templates not scaffolded: <name>with no explanation of the constraint. Documenting the rule, or naming it in that warning, would make the failure self-explanatory.