Skip to content

feat(cli): add specify extension init scaffolding command#1929

Open
mvanhorn wants to merge 1 commit intogithub:mainfrom
mvanhorn:osc/feat-extension-init-scaffolding
Open

feat(cli): add specify extension init scaffolding command#1929
mvanhorn wants to merge 1 commit intogithub:mainfrom
mvanhorn:osc/feat-extension-init-scaffolding

Conversation

@mvanhorn
Copy link
Contributor

Description

Add a specify extension init <name> subcommand that scaffolds a new extension directory from the built-in template (extensions/template/), substituting user-provided metadata into all placeholder values.

The extension ecosystem has 23+ community extensions published to the catalog, each manually created by copying extensions/template/ and hand-editing 7 files. Every other stage of the extension lifecycle has CLI support (search, add, remove, enable, disable, update, set-priority, catalog management) - except creation. This closes that gap.

What it does:

  • Copies extensions/template/ to spec-kit-<name>/ in the current or specified directory
  • Substitutes placeholders: extension ID, display name, author, description, repository URL, date
  • Validates extension ID format (lowercase, hyphen-separated, ^[a-z][a-z0-9]*(-[a-z0-9]+)*$)
  • Replaces EXAMPLE-README.md as the new README.md
  • Optionally initializes a git repo (--no-git to skip)
  • Prompts interactively when CLI args are omitted
  • Prints a next-steps panel matching the style of specify init

Usage:

specify extension init my-linter
specify extension init my-linter --author "Jane Doe" --description "Lint spec files"
specify extension init my-linter --output ~/projects --no-git

This command does NOT require a spec-kit project - you can scaffold an extension anywhere, then test it with specify extension add --dev /path/to/extension.

The template source is resolved from the installed package first (works in wheel/air-gapped), falling back to the source tree layout.

Testing

  • Ran existing tests with pytest - all 810 existing tests pass
  • Added 23 new test cases in tests/test_extension_init.py:
    • Extension ID validation (10 tests): valid names, uppercase rejection, special chars, leading numbers, empty strings
    • Title case conversion (3 tests)
    • Template discovery (2 tests)
    • CLI integration (8 tests): full scaffold, placeholder substitution, invalid name rejection, existing directory rejection, --no-git, README replacement, next-steps output, date substitution
  • Tested locally: specify extension init my-test --no-git produces a working extension directory with all placeholders replaced

AI Disclosure

  • I did use AI assistance (describe below)

This contribution was developed with AI assistance (Claude Code). The implementation follows existing patterns from the specify init command and extension add subcommand.

Add a new `specify extension init <name>` subcommand that scaffolds
a ready-to-develop extension directory from the built-in template.
Substitutes extension metadata (ID, name, author, description,
repository URL, date) into all template files.

The extension ecosystem has 23+ community extensions, all manually
created by copying extensions/template/. This command completes the
extension authoring lifecycle - every other stage (search, add,
remove, enable, disable, update, catalog management) already has
CLI support.

Features:
- Extension ID validation (lowercase, hyphen-separated)
- Interactive prompts when CLI args are omitted
- --output flag for custom output directory
- --no-git flag to skip git initialization
- Replaces EXAMPLE-README.md as the new README.md
- Prints next-steps guidance panel

Includes 23 pytest test cases covering validation, placeholder
substitution, CLI integration, and edge cases.
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.

1 participant