What happened
specify bundle install cannot install any workflow from a catalog. Every workflow component fails with an error about --dev, even though --dev was never passed and the workflow resolves correctly from the catalog.
$ specify bundle install lean-full-lifecycle
Error: --dev source must be a workflow YAML file, supported archive, or
directory containing workflow.yml: lifecycle-greenfield-bootstrap
Error: Failed to install workflow 'lifecycle-greenfield-bootstrap'.
The same workflow installs fine through the CLI:
$ specify workflow add lifecycle-greenfield-bootstrap
✓ Workflow 'Greenfield Bootstrap' (lifecycle-greenfield-bootstrap) installed
Presets and extensions in the same bundle install without trouble; only workflows fail.
Cause
WorkflowPrimitive.install in src/specify_cli/bundler/services/primitives.py calls the Typer command as a plain Python function:
from ... import workflow_add
with _chdir(self._root):
_delegate_command(
"install", f"workflow '{component.id}'",
lambda: workflow_add(component.id),
)
workflow_add is declared in src/specify_cli/workflows/_commands.py as:
def workflow_add(
source: str = typer.Argument(..., help="Workflow ID, URL, or local path"),
dev: bool = typer.Option(False, "--dev", help="Install from a local workflow YAML file or directory"),
from_url: str | None = typer.Option(None, "--from", help="Install from a custom URL"),
):
Called directly, Typer never binds the parameters, so dev keeps its typer.OptionInfo default. That object is truthy, so the function takes the local-path branch and interprets the workflow id as a filesystem path.
Reproducible in a Python shell:
>>> import inspect
>>> from specify_cli.workflows._commands import workflow_add
>>> d = inspect.signature(workflow_add).parameters["dev"].default
>>> type(d).__name__, bool(d)
('OptionInfo', True)
workflow_remove is unaffected: it declares only a typer.Argument, which the bundler supplies positionally.
Version
Reproduced on v1.0.1 (macOS, Python 3.13). The same code is present on main at the time of writing.
Suggested fix
Pass the options explicitly at both call sites in primitives.py:
lambda: workflow_add(component.id, dev=False, from_url=None),
Extracting the body into a plain function that the Typer command wraps would prevent the whole class of bug, since any future option added to the command would otherwise reintroduce it silently.
Impact
Any bundle that provides workflows cannot be installed as a bundle. The workaround is to install workflows through specify workflow add <id> before specify bundle install, which lets Typer bind dev=False. They are still catalog-sourced, but bundle install then reports them as "already present" and does not attribute them to the bundle, so specify bundle remove leaves them installed.
What happened
specify bundle installcannot install any workflow from a catalog. Every workflow component fails with an error about--dev, even though--devwas never passed and the workflow resolves correctly from the catalog.The same workflow installs fine through the CLI:
Presets and extensions in the same bundle install without trouble; only workflows fail.
Cause
WorkflowPrimitive.installinsrc/specify_cli/bundler/services/primitives.pycalls the Typer command as a plain Python function:workflow_addis declared insrc/specify_cli/workflows/_commands.pyas:Called directly, Typer never binds the parameters, so
devkeeps itstyper.OptionInfodefault. That object is truthy, so the function takes the local-path branch and interprets the workflow id as a filesystem path.Reproducible in a Python shell:
workflow_removeis unaffected: it declares only atyper.Argument, which the bundler supplies positionally.Version
Reproduced on
v1.0.1(macOS, Python 3.13). The same code is present onmainat the time of writing.Suggested fix
Pass the options explicitly at both call sites in
primitives.py:Extracting the body into a plain function that the Typer command wraps would prevent the whole class of bug, since any future option added to the command would otherwise reintroduce it silently.
Impact
Any bundle that provides workflows cannot be installed as a bundle. The workaround is to install workflows through
specify workflow add <id>beforespecify bundle install, which lets Typer binddev=False. They are still catalog-sourced, butbundle installthen reports them as "already present" and does not attribute them to the bundle, sospecify bundle removeleaves them installed.