The Extension System provides a modular architecture for adding commands and functionality to Spec Kit projects without bloating the core CLI. Extensions are self-contained packages that can register slash commands for AI agents, hook into workflow events, and provide configurable behaviors.
This page covers the overall architecture, components, and data flows of the extension system. For specific topics:
list, add, remove, etc.): see Extension Management CommandsExtensions are ZIP archives or directories containing:
extension.yml manifest describing metadata, commands, hooks, and configuration.md or .toml) for AI agent integrationExtensions install into .specify/extensions/{extension-id}/ and register themselves in .specify/extensions/.registry for tracking enabled/disabled state and metadata.
Key Capabilities:
/speckit.{extension}.* slash commands without modifying coreSources: CHANGELOG.md10-120 src/specify_cli/__init__.py1403-1410
Sources: src/specify_cli/__init__.py1434-1477 src/specify_cli/__init__.py1484-1709 CHANGELOG.md14-28
| Component | Location | Purpose |
|---|---|---|
ExtensionManager | src/specify_cli/extensions.py | Orchestrates installation, removal, enable/disable operations |
ExtensionRegistry | .specify/extensions/.registry | JSON file tracking installed extensions and their state |
ExtensionCatalog | src/specify_cli/extensions.py | Fetches and caches central catalog from GitHub |
HookExecutor | src/specify_cli/extensions.py | Executes lifecycle hooks with condition evaluation |
CommandRegistrar | src/specify_cli/extensions.py | Generates agent-specific command files from templates |
ConfigManager | src/specify_cli/extensions.py | Merges 4-layer configuration cascade |
Sources: CHANGELOG.md15-27 CHANGELOG.md52-59
Every extension requires an extension.yml manifest file defining its metadata, commands, hooks, and configuration defaults.
Key Fields:
id: Must be unique, lowercase, hyphenated (used for directory names)version: Semantic version (MAJOR.MINOR.PATCH) for compatibility checksspec_kit_version: Version constraint (e.g., >=0.1.0, ^0.1.0) validated during installcommands[].file: Path relative to extension root (supports .md and .toml)hooks[].condition: Optional condition expression for conditional executionconfig: Nested defaults merged with project/local/environment configsSources: CHANGELOG.md16-28 CHANGELOG.md78-87
Extensions install into a standardized directory structure within .specify/extensions/.
.specify/
└── extensions/
├── .registry # JSON registry of installed extensions
├── .cache/ # Temporary files
│ ├── catalog.json # Cached extension catalog (1 hour TTL)
│ └── downloads/ # Temporary ZIP downloads
├── {extension-id}/ # Installed extension
│ ├── extension.yml # Manifest
│ ├── commands/ # Command templates
│ │ ├── command1.md
│ │ └── command2.toml
│ ├── {extension-id}-config.yml # Project config (committed)
│ └── local-config.yml # Local config (gitignored)
└── {another-extension-id}/
└── ...
The .registry file tracks all installed extensions:
Registry Operations:
enabled flag controls whether hooks execute and commands are visibleSources: CHANGELOG.md17-18 CHANGELOG.md31-39
Extensions can be installed from three sources: local directories, remote URLs, or the central catalog.
Sources: src/specify_cli/__init__.py1477-1599 CHANGELOG.md19-28
| Method | Flag | Source | Validation | Use Case |
|---|---|---|---|---|
| Catalog | (default) | extensions/catalog.json | Full (signature, version) | Production installs |
| Local Dev | --dev | Local directory path | Manifest only | Extension development |
| Remote URL | --from URL | HTTPS URL (ZIP) | HTTPS + manifest | Custom/private extensions |
Security Constraints:
--from installs show warning about untrusted sourcesSources: src/specify_cli/__init__.py1500-1551 src/specify_cli/__init__.py1519-1526
Extensions register slash commands that AI agents can execute. The CommandRegistrar generates agent-specific command files from templates.
Sources: CHANGELOG.md68-76 src/specify_cli/__init__.py126-229
Command templates use YAML frontmatter for metadata:
Processing Steps:
name, description, args.claude/, .gemini/, etc.).md format.toml with description + prompt fields$ARGUMENTS → {{args}} for TOML agents$ARGUMENTS for Markdown agentsSources: CHANGELOG.md68-76 CHANGELOG.md71-73
Hooks allow extensions to execute logic at specific workflow events without modifying core commands.
Sources: CHANGELOG.md52-59 CHANGELOG.md88-100
Hook Execution:
/speckit.plan)HookExecutor.check_hooks_for_event('post-plan')Condition Syntax:
config.key.path is set: Check if config value existsconfig.key == 'value': Equality checkenv.VAR is set: Environment variable existsenv.VAR != 'value': Environment inequalitySources: CHANGELOG.md88-94 CHANGELOG.md96-100
Extensions use a four-layer configuration cascade with increasing precedence.
Sources: CHANGELOG.md78-87
Layer 1 - Defaults (extension.yml):
Layer 2 - Project ({ext-id}-config.yml):
Layer 3 - Local (local-config.yml):
Layer 4 - Environment:
Final Merged Config:
Access Methods:
ConfigManager.get_config(): Returns full merged config dictConfigManager.get_value('jira.url'): Dot-notation path lookupConfigManager.has_value('sync.auto_create'): Existence checkSources: CHANGELOG.md78-87
Extensions transition through several states during their lifecycle.
Sources: CHANGELOG.md60-67 src/specify_cli/__init__.py1434-1477
| From State | Command | To State | Effect |
|---|---|---|---|
| Not Installed | add | Enabled | Install files, register commands, update registry |
| Enabled | disable | Disabled | Unregister commands, mark disabled in registry |
| Disabled | enable | Enabled | Re-register commands, mark enabled in registry |
| Enabled/Disabled | update | Same | Replace files, preserve config, maintain enabled state |
| Enabled/Disabled | remove | Not Installed | Delete files, unregister commands, remove from registry |
Key Behaviors:
disable: Preserves all files and configuration, only toggles visibilityenable: Re-activates without reinstallationupdate: Preserves configuration across updatesremove: Offers --keep-config flag to preserve configuration filesSources: src/specify_cli/__init__.py1434-1477 CHANGELOG.md60-67
Users discover extensions through the catalog system, which provides search, filtering, and metadata retrieval.
Sources: CHANGELOG.md30-40 src/specify_cli/__init__.py1600-1709
The central catalog is stored in extensions/catalog.json in the spec-kit repository:
Catalog Features:
.specify/extensions/.cache/catalog.json--tag, --author, --verified flagsSources: CHANGELOG.md31-39 src/specify_cli/__init__.py1600-1650
All extension commands are subcommands of specify extension:
| Command | Arguments | Purpose |
|---|---|---|
list | [--available] [--all] | Show installed extensions or catalog |
add | <name> [--dev] [--from URL] | Install extension from catalog, local, or URL |
remove | <name> [--keep-config] [--force] | Uninstall extension |
search | [query] [--tag] [--author] [--verified] | Search extension catalog |
info | <name> | Show detailed extension information |
update | <name> | Update extension to latest version |
enable | <name> | Enable a disabled extension |
disable | <name> | Disable extension without removing |
For detailed command documentation, see Extension Management Commands.
Sources: src/specify_cli/__init__.py1405-1410 CHANGELOG.md19-27 CHANGELOG.md60-67
Refresh this wiki