Skip to content

fix(build): include specify_cli.bundler.lib in built distribution#3085

Merged
mnriem merged 2 commits into
github:mainfrom
antst:fix/bundler-lib-excluded-by-gitignore
Jun 22, 2026
Merged

fix(build): include specify_cli.bundler.lib in built distribution#3085
mnriem merged 2 commits into
github:mainfrom
antst:fix/bundler-lib-excluded-by-gitignore

Conversation

@antst

@antst antst commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Installing from source (e.g. uv tool install specify-cli --from git+https://github.com/github/spec-kit.git) currently produces a completely broken CLI — every command crashes on startup:

ModuleNotFoundError: No module named 'specify_cli.bundler.lib'
  File ".../specify_cli/__init__.py", line 615, in <module>
    from .commands.bundle import register as _register_bundle_cmds
  File ".../specify_cli/commands/bundle/__init__.py", line 18, in <module>
    from ...bundler.lib.project import (...)

This affects init, check, everything — because commands/bundle/__init__.py is imported at top level in specify_cli/__init__.py, and it imports specify_cli.bundler.lib.project. Introduced together with the specify bundle command (#3070), which added the src/specify_cli/bundler/lib/ package.

Root cause

The package src/specify_cli/bundler/lib/ is tracked in git, but it is missing from the built wheel. The cause is the root .gitignore:

lib/
lib64/

These come from the standard GitHub Python template and are meant to ignore a top-level build/virtualenv lib directory. Because the patterns are unanchored, they also match the source package src/specify_cli/bundler/lib/. Hatchling applies .gitignore patterns as build-exclusion rules, so it silently drops bundler/lib from the wheel even though the files are tracked.

Sibling packages (bundler/models/, bundler/services/, …) are unaffected because only the directory literally named lib matches the pattern.

Reproduction (current main)

$ uv build --wheel
$ unzip -l dist/specify_cli-*.whl | grep -c 'bundler/lib/'
0          # bundler/lib is absent
$ unzip -l dist/specify_cli-*.whl | grep -c 'bundler/services/'
10         # siblings are present

Fix

Anchor the patterns to the repository root so they only match the intended top-level build artifacts:

-lib/
-lib64/
+/lib/
+/lib64/

This preserves the original intent (ignore a root-level lib/lib64 build/venv dir) while no longer excluding the source package.

Verification (with this change)

$ uv build --wheel
$ unzip -l dist/specify_cli-*.whl | grep 'bundler/lib/'
  specify_cli/bundler/lib/__init__.py
  specify_cli/bundler/lib/project.py
  specify_cli/bundler/lib/versioning.py
  specify_cli/bundler/lib/yamlio.py

# install the built wheel into a fresh venv:
$ specify --version
specify 0.11.4.dev0
$ specify bundle --help
 Usage: specify bundle [OPTIONS] COMMAND [ARGS]...
 Discover, install, and author Spec Kit bundles

The CLI now loads, and specify bundle works.

Alternative considered: a Hatchling force-include/artifacts entry for bundler/lib. Anchoring the .gitignore patterns was chosen because it fixes the actual root cause (an over-broad ignore pattern), covers both the sdist and wheel targets, and protects any future source directory that happens to be named lib.

The root .gitignore carried unanchored `lib/` and `lib64/` patterns from the
standard GitHub Python template (intended to ignore a top-level build/venv
`lib` directory). Being unanchored, they also match the source package
`src/specify_cli/bundler/lib/`.

Hatchling applies .gitignore patterns as build-exclusion rules, so the
`bundler/lib` package (project.py, versioning.py, yamlio.py) was silently
dropped from the built wheel even though it is tracked in git. Since
commands/bundle/__init__.py imports `specify_cli.bundler.lib.project` at module
load, any install built from source (e.g. `uv tool install --from git+...`)
crashed on startup with:

    ModuleNotFoundError: No module named 'specify_cli.bundler.lib'

which broke the entire CLI — every command, including `specify init`.

Anchor the patterns to the repo root (`/lib/`, `/lib64/`) so they only match
the intended top-level build artifacts and no longer exclude the source package.
Copilot AI review requested due to automatic review settings June 22, 2026 08:56
@antst antst requested a review from mnriem as a code owner June 22, 2026 08:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mnriem mnriem requested a review from Copilot June 22, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

Empty commit to re-dispatch a wedged CodeQL run that never started,
unblocking code scanning merge protection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mnriem mnriem requested a review from Copilot June 22, 2026 15:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

@mnriem mnriem merged commit a4c86b3 into github:main Jun 22, 2026
11 checks passed
@mnriem

mnriem commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants