-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Description
Summary
Embed the core template pack (templates, commands, and scripts) inside the specify-cli Python package so that specify init --offline can scaffold projects entirely from local assets without calling the GitHub API. This eliminates the last hardcoded external network dependency and enables air-gapped deployment.
Problem Statement
After #1707 (multi-catalog) and #1708 (pluggable templates with scripts), every network touchpoint in Spec Kit becomes configurable — except one:
specify init always calls https://api.github.com/repos/github/spec-kit/releases/latest to fetch and download a release ZIP. This is hardcoded in download_template_from_github() (__init__.py L677) and cannot be redirected to an internal server.
On an air-gapped network where extension and template catalogs point at internal HTTPS servers (#1707, #1708), specify init still fails because it can't reach api.github.com.
Implemented Solution (PR #1803)
1. Bundle core assets inside the pip package
Ship templates, commands, scripts, and release scripts as package data within specify-cli via pyproject.toml force-include:
[tool.hatch.build.targets.wheel.force-include]
"templates" = "specify_cli/core_pack/templates"
"templates/commands" = "specify_cli/core_pack/commands"
"scripts/bash" = "specify_cli/core_pack/scripts/bash"
"scripts/powershell" = "specify_cli/core_pack/scripts/powershell"
".github/workflows/scripts/create-release-packages.sh" = "specify_cli/core_pack/release_scripts/create-release-packages.sh"
".github/workflows/scripts/create-release-packages.ps1" = "specify_cli/core_pack/release_scripts/create-release-packages.ps1"2. --offline opt-in flag
By default, specify init continues to download from GitHub (unchanged behavior). The new --offline flag opts in to using bundled assets:
# Default — downloads from GitHub:
specify init my-project --ai claude
# Opt-in offline — uses bundled assets, no network access:
specify init my-project --ai claude --offlineIf --offline is specified but bundled assets can't be found or scaffolding fails, the CLI errors out with a clear message rather than silently falling back to a network download.
3. Offline scaffolding via release script (scaffold_from_core_pack)
_locate_core_pack()— finds bundled core_pack directory (wheel install) or returns None_locate_release_script()— finds the platform-appropriate release script; on Windows, probespwshthenpowershellviashutil.which()scaffold_from_core_pack()— invokes the bundledcreate-release-packages.sh(or.ps1) in a temp directory to generate the exact same output as the GitHub release ZIPs, then copies the result to the project directory
This guarantees byte-for-byte parity with the GitHub release ZIPs because both paths use the exact same script.
4. Wheel published as release asset
release.yml: wheel build step runs after release packages are generatedcreate-github-release.sh:specify_cli-VERSION-py3-none-any.whlattached to every release
5. Shell script improvements
GENRELEASES_DIRoverridable via environment variable for test isolationvalidate_subset()hardened against glob metacharacter injection
Acceptance Criteria
-
specify init --offlinescaffolds a complete project from embedded assets with no network calls - All supported agents produce correct command files (Markdown, TOML, agent.md) from embedded command templates
- Default
specify init(without--offline) retains current GitHub-download behavior -
pip install specify-cliincludes all core templates, commands, and scripts - Existing
create-release-packages.shcontinues to work (kept for release ZIP distribution) - Air-gapped deployment works: install wheel offline →
specify init --offlinesucceeds without external network access - Byte-for-byte parity verified for all 21 agents between offline scaffold and release script ZIPs
Dependencies
- feat(extensions): support multiple active catalogs simultaneously #1707 — Multi-catalog support (redirectable catalog URLs)
- feat(presets): Pluggable preset system with catalog, resolver, and skills propagation #1708 — Pluggable template system with
type: "script"support (template pack manifest design)
Out of Scope
- Removing release ZIPs entirely (kept as supplementary distribution for non-pip users)
- Private PyPI mirror setup documentation (org-specific)
- Catalog mirroring tooling
References
- Current GitHub API dependency:
src/specify_cli/__init__.pyL677, L1661 - Release build script:
.github/workflows/scripts/create-release-packages.sh - PR: feat(cli): embed core pack in wheel for offline/air-gapped deployment #1803