Spec Kit Extension System Architecture and Publishing Guide
The Spec Kit extension system is a modular plug-in architecture built on seven core components—ExtensionManifest, ExtensionRegistry, ExtensionManager, CommandRegistrar, HookExecutor, ExtensionCatalog, and ConfigManager—that enables third-party commands, configuration schemas, and lifecycle hooks without core framework modifications.
The github/spec-kit repository implements this extension system to provide a clean separation between core functionality and community contributions. Developers can distribute new capabilities through GitHub releases and the community catalog while the system handles compatibility checks, command registration, and layered configuration management automatically.
Core Architecture Components
The Spec Kit extension system architecture centers on seven specialized classes defined in src/specify_cli/extensions.py, each handling a distinct lifecycle phase.
ExtensionManifest
The ExtensionManifest class parses and validates the extension.yml file (schema version 1.0) according to the specification in EXTENSION-API-REFERENCE.md. Located at src/specify_cli/extensions.py#L39-L78, it guarantees correct IDs, semantic versions, required fields, command definitions, and hook blocks before any installation proceeds.
ExtensionRegistry
ExtensionRegistry (src/specify_cli/extensions.py#L164-L244) maintains a JSON database at .specify/extensions/.registry tracking every installed extension's metadata. It handles add, remove, and list queries while persisting version, source, hash, and registered command names to disk.
ExtensionManager
The ExtensionManager (src/specify_cli/extensions.py#L258-L508) orchestrates the full extension lifecycle. It performs compatibility checks against the current Spec Kit version using packaging.specifiers, copies source directories into .specify/extensions/<extension-id>/, and manages clean removal while optionally preserving *-config.yml files.
CommandRegistrar
CommandRegistrar (src/specify_cli/extensions.py#L845-L985) converts extension-provided command definitions into agent-specific formats. It rewrites placeholders like $ARGUMENTS into agent-specific tokens and writes final command files to per-agent locations such as .claude/commands/ or .gemini/commands/, using the AGENT_CONFIG dictionary defined in src/specify_cli/__init__.py.
HookExecutor
The HookExecutor (src/specify_cli/extensions.py#L1025-L1057) registers and executes event hooks defined in the manifest (after_tasks, before_commit, etc.). It injects hook definitions into the project-level .specify/extensions.yml and manages their deregistration during uninstallation.
ExtensionCatalog
ExtensionCatalog (src/specify_cli/extensions.py#L969-L1070) functions as the remote catalog client. It fetches catalog.json (or the community variant catalog.community.json) from GitHub, caches results under .specify/extensions/.cache, and provides search helpers used by the specify extension search CLI command.
ConfigManager
The ConfigManager (src/specify_cli/extensions.py#L1240-L1310) merges layered configuration sources—defaults, project settings, local overrides, and environment variables—exposing get_config() for full dictionaries and get_value() for dot-notation access to specific settings.
Extension Installation Lifecycle
When running specify extension install, the ExtensionManager executes a six-phase process:
-
Manifest validation –
ExtensionManifestvalidates theextension.ymlstructure and required fields. -
Compatibility verification –
ExtensionManager.check_compatibility()ensures the extension'srequires.speckit_versionrange matches the current installation using semantic versioning specifiers. -
File deployment – The entire source directory copies into
.specify/extensions/<extension-id>/. -
Command registration –
CommandRegistrarscansprovides.commands, rewrites front-matter, adjusts script paths, and writes files like.claude/commands/speckit.myext.mycmd.md. -
Hook registration –
HookExecutor.register_hooks()injects definitions into.specify/extensions.yml. -
Registry persistence –
ExtensionRegistry.add()records the installation metadata.
During removal via specify extension remove, the manager reverses these steps, with optional preservation of configuration files.
Publishing Extensions to the Community Catalog
Publishing a Spec Kit extension requires five specific steps:
-
Repository creation – Create a public GitHub repository following the directory layout specified in
EXTENSION-PUBLISHING-GUIDE.md. -
Manifest authoring – Write a valid
extension.ymlcontaining fields:id,name,version,requires.speckit_version,provides.commands, optionalhooks,tags, anddefaults. Reference the schema inEXTENSION-API-REFERENCE.md. -
Release tagging – Tag a semantic version (
git tag vX.Y.Z && git push origin vX.Y.Z) and publish a GitHub Release. The generated zip URL (e.g.,https://github.com/your-org/spec-kit-myext/archive/refs/tags/v1.0.0.zip) serves as the distribution endpoint. -
Catalog submission – Fork
github/spec-kit, editextensions/catalog.community.jsonto insert metadata including download URL and version requirements, and updateextensions/README.mdto list the extension in the Available Extensions table. Submit a pull request against the upstream repository. -
Verification – Maintainers execute automated manifest validation and URL accessibility checks, followed by manual security and functionality reviews. Upon approval,
verified: trueis set, making the extension appear inspecify extension search --verifiedresults.
Programmatic Extension Management
The Spec Kit extension system exposes Python APIs for automation and integration workflows.
Installing from a Local Directory
from pathlib import Path
from specify_cli.extensions import ExtensionManager
project_root = Path.cwd()
manager = ExtensionManager(project_root)
# Assumes `my-extension/` contains a valid extension.yml
manifest = manager.install_from_directory(
source_dir=Path("my-extension"),
speckit_version="0.1.0",
register_commands=True
)
print(f"Installed {manifest.id} v{manifest.version}")
Installing from a Remote ZIP Archive
from pathlib import Path
from specify_cli.extensions import ExtensionCatalog, ExtensionManager
project_root = Path.cwd()
catalog = ExtensionCatalog(project_root)
# Download the zip for extension ID "jira"
zip_path = catalog.download_extension("jira")
manager = ExtensionManager(project_root)
manifest = manager.install_from_zip(zip_path, speckit_version="0.1.0")
print(f"Installed {manifest.id} from {zip_path}")
Registering Commands for Specific Agents
from pathlib import Path
from specify_cli.extensions import CommandRegistrar, ExtensionManifest
registrar = CommandRegistrar()
manifest = ExtensionManifest(Path("my-extension/extension.yml"))
registered = registrar.register_commands_for_agent(
agent_name="claude",
manifest=manifest,
extension_dir=Path("my-extension"),
project_root=Path.cwd()
)
print("Claude commands registered:", registered)
Accessing Layered Configuration
from pathlib import Path
from specify_cli.extensions import ConfigManager
cfg = ConfigManager(project_root=Path.cwd(), extension_id="jira")
full_cfg = cfg.get_config()
print(full_cfg["connection"]["url"]) # Merged from defaults → env
print(cfg.get_value("features.enabled")) # Dot-notation shortcut
Summary
- The Spec Kit extension system architecture comprises seven specialized classes handling manifests, registries, lifecycle management, command translation, hook execution, remote catalogs, and configuration.
- Installation follows a strict six-phase validation and registration process that ensures compatibility before modifying the project structure.
- Extensions publish through GitHub Releases and community catalog pull requests, with automated verification ensuring quality and security.
- All core functionality resides in
src/specify_cli/extensions.py, with documentation inEXTENSION-API-REFERENCE.mdandEXTENSION-PUBLISHING-GUIDE.md. - The system supports programmatic installation from local directories, remote ZIP archives, and provides layered configuration management with dot-notation access.
Frequently Asked Questions
How does the Spec Kit extension system validate extension compatibility?
The ExtensionManager.check_compatibility() method uses the packaging.specifiers library to compare the current Spec Kit version against the requires.speckit_version range defined in the extension's extension.yml manifest. This check occurs before any files are copied to prevent incompatible installations.
Where are extension commands stored after registration?
The CommandRegistrar class writes agent-specific command files to per-agent directories such as .claude/commands/ or .gemini/commands/. It rewrites placeholders like $ARGUMENTS into agent-specific tokens using the AGENT_CONFIG dictionary defined in src/specify_cli/__init__.py, ensuring commands match each agent's expected format and location.
What is the purpose of the ExtensionCatalog class?
ExtensionCatalog (src/specify_cli/extensions.py#L969-L1070) fetches remote extension metadata from catalog.community.json, caches it locally under .specify/extensions/.cache, and provides search and download functionality. It enables the specify extension search command and handles ZIP downloads from GitHub release URLs during remote installations.
How do I submit a new extension to the verified community catalog?
Create a public GitHub repository with a valid extension.yml, tag a semantic version release, then fork github/spec-kit and submit a pull request modifying extensions/catalog.community.json and extensions/README.md. Maintainers will verify the manifest schema, test URL accessibility, and perform security reviews before setting verified: true in the catalog entry.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →