Skip to content

feat(cli): Embed core template pack in CLI package for air-gapped deployment #1711

@mnriem

Description

@mnriem

Summary

Embed the core template pack (templates, commands, and scripts) inside the specify-cli Python package so that specify init 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.

Proposed Solution

1. Bundle core assets inside the pip package

Ship templates, commands, and scripts as package data within specify-cli:

src/specify_cli/
    __init__.py
    extensions.py
    core_pack/                          # NEW: shipped with pip install
        template-pack.yml               # Standard #1708 manifest
        templates/
            spec-template.md
            plan-template.md
            tasks-template.md
            checklist-template.md
            constitution-template.md
            agent-file-template.md
        commands/
            specify.md
            plan.md
            tasks.md
            implement.md
            ...
        scripts/
            bash/
                create-new-feature.sh
                setup-plan.sh
                common.sh
                check-prerequisites.sh
                update-agent-context.sh
            powershell/
                create-new-feature.ps1
                setup-plan.ps1
                common.ps1
                check-prerequisites.ps1
                update-agent-context.ps1

2. Update pyproject.toml to include non-Python files

[tool.hatch.build.targets.wheel]
packages = ["src/specify_cli"]

[tool.hatch.build.targets.wheel.force-include]
"templates" = "specify_cli/core_pack/templates"
"templates/commands" = "specify_cli/core_pack/commands"
"scripts" = "specify_cli/core_pack/scripts"

3. Add local scaffolding function

New scaffold_from_core_pack() function that replaces download_and_extract_template() as the default init path:

  • Uses importlib.resources to locate bundled assets
  • Copies templates → .specify/templates/
  • Copies scripts (bash or powershell) → .specify/scripts/
  • Generates agent-specific command files (the {SCRIPT} substitution, TOML conversion for Gemini/Qwen, frontmatter transforms for Copilot, etc.)

4. Port agent command generation to Python

The generate_commands() function in create-release-packages.sh (frontmatter parsing, {SCRIPT} placeholder substitution, Markdown → TOML conversion, $ARGUMENTS vs {{args}}) needs a Python equivalent so specify init can generate agent-specific command files at runtime.

5. Keep download as optional fallback

Retain download_and_extract_template() behind a flag (e.g., specify init --from-github) for users who want the latest release without upgrading the CLI.

Acceptance Criteria

  • specify init scaffolds 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
  • specify init --from-github retains current behavior (download from GitHub API)
  • pip install specify-cli includes all core templates, commands, and scripts
  • Existing create-release-packages.sh continues to work (kept for manual ZIP distribution)
  • Air-gapped deployment works: install CLI via pip (from internal PyPI mirror), configure catalogs to internal URLs (feat(extensions): support multiple active catalogs simultaneously #1707), specify init succeeds without external network access

Dependencies

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__.py L677, L1661
  • Release build script: .github/workflows/scripts/create-release-packages.sh
  • generate_commands() shell function: ~60 lines of awk/sed for agent-specific transforms

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions