Repository navigation
Conversation
… init bundle_init called the Typer-decorated bundle_install() without refresh, so refresh kept its typer.Option(False) default, a truthy OptionInfo. A second `specify bundle init <bundle>` then took the explicit-refresh path: it replaced local edits to installed workflows and accepted a changed bundle version that a plain `bundle install` refuses without --refresh. Pass refresh=False explicitly, as github#4284 did for the workflow_add call. Assisted-by: Codex CLI (model: gpt-6-astra, autonomous) Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
There was a problem hiding this comment.
🟢 Approval recommended
The focused fix has targeted regression coverage, with only a non-blocking documentation clarification remaining.
1 open finding
What changed in this PR
Prevents repeated Specify CLI bundle initialization from unintentionally refreshing installed components and overwriting local edits.
Changes:
- Passes
refresh=Falseexplicitly during bundle initialization. - Adds regression coverage for preserved edits, changed-version rejection, and explicit refresh.
- Documents repeat-init behavior and refresh alternatives.
Tests were not rerun; regression results were assessed from the supplied evidence.
| File | Description |
|---|---|
| tests/specify_cli/bundles/test_command_init.py | Tests delegation, preservation, refresh, and version rejection. |
| src/specify_cli/bundles/command_init.py | Explicitly disables implicit refresh. |
| docs/reference/bundles.md | Explains preservation and refresh options. |
🧠 Review effort: Max
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Please address Copilot feedback |
With refresh no longer implied, a repeated `bundle init` goes through the same record check as a plain `bundle install`: a changed bundle version, or a changed or removed owned component, fails until `bundle update` or `bundle install --refresh` applies it. Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
|
Addressed Copilot's docs finding in 335d29f. The Drafted on behalf of @kartsan03 by Claude Code (model: claude-opus-5-5, autonomous), which also made the docs change. |
|
|
||
| Ensures the current directory is a Spec Kit project (initializing it idempotently if needed), then optionally installs the given bundle. Useful as an explicit one-step bootstrap for a new checkout. | ||
|
|
||
| Repeating `bundle init` skips components already installed by the bundle and preserves their local edits. It does not apply manifest changes: as with a normal [`bundle install`](#install-a-bundle), it fails without changing the installed bundle if the manifest changes the recorded bundle version, changes an owned component's version, source, preset priority, or strategy, or removes an owned component. To refresh components or apply such changes, use `bundle update <id>` for a catalog bundle or `bundle install <path> --refresh` for a local source. |
|
Please address Copilot feedback. If not applicable, please explain why |
…ents Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)

Description
Running
specify bundle init <bundle>a second time refreshes the bundle's components that are already installed, even thoughbundle inithas no--refreshoption. A local edit to an installed workflow is silently replaced, and the command exits 0.bundle_initcalls the Typer-decoratedbundle_install()directly (src/specify_cli/bundles/command_init.py:51onmain) without passingrefresh. Sorefreshkeeps its parameter default,typer.Option(False, ...), which is anOptionInfoobject and truthy.install_bundlethen takes the explicit-refresh path (installer.py:119,:175). It's the same option-default pitfall #4284 fixed for theworkflow_addcall. The same truthy value also letsbundle initaccept a changed bundle version that a plainbundle installrefuses without--refresh.This PR passes
refresh=Falseexplicitly frombundle_init. Directbundle installandbundle install --refreshare unchanged.docs/reference/bundles.mdgets one paragraph: repeatingbundle initkeeps installed components as they are, andbundle update/bundle install --refreshare the ways to refresh them.Repro with the first-party
bugfixbundle, offline: init, append a line to.specify/workflows/bugfix/workflow.yml, init again.specify bundle init bundles/bugfix --offlinemain(3238fa9)0 added, 0 already present, 2 refreshed, 0 removed0 added, 2 already presentworkflow.ymlTesting
uv run specify --helpuv sync && uv run pytestNew tests in
tests/specify_cli/bundles/test_command_init.py:bundle_initdelegates tobundle_installwithrefresh=False(and doesn't call it without a bundle).CliRunnerand the realbugfixbundle: a repeatedbundle initkeeps a local edit to the installed workflow (bytes compared, CRLF included) and leaves the registry alone; a plainbundle installdoes the same, andbundle install --refreshstill restores the bundled file.bundle initwith a changed bundle version exits 1 asking for--refresh, and leaves the bundle records and the edited workflow untouched.With only
src/reverted tomain, 3 of the 7 tests in the file fail (the delegation check, the repeated-init case and the changed-version case). With the fix, all 54 tests intest_command_init.py,test_command_install.pyandtest_commands.pypass.Full suite on Linux, Python 3.13: 12093 passed, 374 skipped (
uv sync --extra test, then pytest in that venv, 20m).Ruff 0.15.0 (
ruff check src tests) passes.AI Disclosure
AI disclosure: Two agents, both autonomous, working back and forth. Codex CLI (model: gpt-6-astra, reasoning effort max, autonomous, sandboxed and offline) found this while scouting the bundle commands, wrote the reproduction, and generated the fix, tests and docs paragraph. Claude Code (model: claude-opus-5-5, autonomous) reviewed the change, reran the tests against
mainand the fix, reran the repro with the realspecifyCLI, ran the full suite and lint, and drafted this description. Commits carryAssisted-by:trailers.