This page provides a deep dive into the internal architecture of Spec Kit's extension system. It covers the implementation details of core classes (ExtensionManager, CommandRegistrar, HookExecutor, ConfigManager), data flow patterns, and the 4-layer configuration hierarchy.
For information about using extensions as an end user, see 7.1 Using Extensions For details on developing extensions, see 7.3 Developing Extensions For catalog management, see 7.2 Extension Catalogs
The extension system is built around five primary classes that handle different aspects of the extension lifecycle:
Title: Extension System Component Interaction
Sources: src/specify_cli/extensions/__init__.py328-685
The ExtensionManager class is the primary coordinator for extension operations. It orchestrates installation, removal, and updates by delegating to specialized components.
| Method | Purpose |
|---|---|
install_from_directory() | Install extension from local path, validate compatibility, copy files, register commands/hooks src/specify_cli/extensions/__init__.py439-514 |
install_from_zip() | Extract ZIP safely (Zip Slip prevention), delegate to install_from_directory() src/specify_cli/extensions/__init__.py516-557 |
remove() | Unregister commands/hooks, backup configs, delete extension directory src/specify_cli/extensions/__init__.py623-685 |
list_installed() | Query registry and return extension metadata with counts src/specify_cli/extensions/__init__.py559-586 |
get_extension() | Load and parse manifest for specific extension src/specify_cli/extensions/__init__.py588-604 |
Key attributes:
project_root: Path to project directory src/specify_cli/extensions/__init__.py346-347extensions_dir: Resolves to .specify/extensions/ src/specify_cli/extensions/__init__.py349-350registry: Instance of ExtensionRegistry src/specify_cli/extensions/__init__.py355-356Sources: src/specify_cli/extensions/__init__.py328-685
The ExtensionManifest class validates and parses extension.yml files according to a strict schema.
Title: ExtensionManifest Validation Pipeline
Validation rules:
"1.0" src/specify_cli/extensions/__init__.py161^[a-z0-9-]+$) src/specify_cli/extensions/__init__.py204-208packaging.version.Version) src/specify_cli/extensions/__init__.py211-214speckit.{extension}.{command} src/specify_cli/extensions/__init__.py51Sources: src/specify_cli/extensions/__init__.py158-245 tests/test_extensions.py210-234
The ExtensionRegistry manages persistent metadata about installed extensions in .specify/extensions/.registry (JSON format) src/specify_cli/extensions/__init__.py247-251
Data structure:
Key methods:
| Method | Behavior | Use Case |
|---|---|---|
add() | Creates new entry with installed_at timestamp src/specify_cli/extensions/__init__.py304-326 | Initial installation |
update() | Merges new metadata, preserves installed_at src/specify_cli/extensions/__init__.py328-349 | Enable/disable, metadata updates |
restore() | Replaces entry completely (including timestamp) src/specify_cli/extensions/__init__.py351-362 | Rollback after failed update |
get() | Returns deep copy of entry src/specify_cli/extensions/__init__.py289-294 | Safe read access |
list() | Returns deep copy of all entries src/specify_cli/extensions/__init__.py282-287 | Prevent mutation |
Sources: src/specify_cli/extensions/__init__.py247-365
The installation process follows a multi-stage pipeline with validation, file copying, and integration steps:
Title: Extension Installation Sequence
Key security and integrity measures:
Path.resolve() and Path.relative_to().packaging.specifiers.SpecifierSet.tasks or specify src/specify_cli/extensions/__init__.py221-236Sources: src/specify_cli/extensions/__init__.py465-583
The CommandRegistrar class (defined in src/specify_cli/agents.py46-52) writes extension commands to AI agent directories, handling the diversity of agent-specific formats and conventions.
The AGENT_CONFIGS dictionary is derived from the INTEGRATION_REGISTRY src/specify_cli/agents.py22-43 which serves as the single source of truth for all supported agents.
Title: Bridge - CommandRegistrar to Code Entities
Sources: src/specify_cli/agents.py22-66
Title: CommandRegistrar Data Flow
Context annotation: Extension commands include metadata comments to track the source:
Path Normalization: The CommandRegistrar includes rewrite_project_relative_paths to ensure that scripts and templates referenced in commands are correctly pointed to the .specify/ directory structure within a generated project src/specify_cli/agents.py175-198
Sources: src/specify_cli/agents.py199-254 src/specify_cli/extensions/__init__.py730-818
The HookExecutor manages lifecycle hooks that extensions can register for events like after_tasks, after_implement, etc.
Hooks are stored in .specify/extensions.yml src/specify_cli/extensions/__init__.py1554-1558 This file also maintains a list of installed extensions to ensure proper cleanup and alphabetical sorting.
Title: Hook Execution Lifecycle
Sources: src/specify_cli/extensions/__init__.py1547-1922
The ConfigManager class implements a hierarchical configuration resolution system with four layers.
Title: Bridge - Config System to Code Entities
The get_config() method merges layers in the following order src/specify_cli/extensions/__init__.py1410-1431:
extension.yml under config.defaults..specify/extensions/{ext-id}/{ext-id}-config.yml..specify/extensions/{ext-id}/local-config.yml.SPECKIT_{EXT_ID}_.Recursive merge behavior:
Sources: src/specify_cli/extensions/__init__.py1348-1545
Extensions can include a .extensionignore file (gitignore-compatible syntax) to exclude files during installation src/specify_cli/extensions/__init__.py367-370
The _load_extensionignore() method returns a callable compatible with shutil.copytree(ignore=...) src/specify_cli/extensions/__init__.py384-429
Key features:
/) src/specify_cli/extensions/__init__.py418-419.extensionignore itself is always excluded src/specify_cli/extensions/__init__.py401pathspec.GitIgnoreSpec for pattern matching src/specify_cli/extensions/__init__.py403Sources: src/specify_cli/extensions/__init__.py367-429
The extension system uses three persistence mechanisms:
File: .specify/extensions/.registry
Metadata is managed via ExtensionRegistry methods like add() and update(), which serialize the internal state to JSON src/specify_cli/extensions/__init__.py247-365
File: .specify/extensions.yml
Managed by HookExecutor, this file tracks installed extensions and their registered hooks src/specify_cli/extensions/__init__.py1554-1558
Structure:
.specify/extensions/ext-id/: Primary extension files..specify/extensions/.backup/ext-id/: Configuration backups created during removal src/specify_cli/extensions/__init__.py676-684.specify/extensions/.cache/downloads/: Cached extension ZIP files src/specify_cli/extensions/__init__.py849Sources: src/specify_cli/extensions/__init__.py247-365 src/specify_cli/extensions/__init__.py1547-1668
The extension system uses a typed exception hierarchy:
| Exception | Purpose |
|---|---|
ExtensionError | Base exception for all extension-related errors src/specify_cli/extensions/__init__.py104-107 |
ValidationError | Raised when manifest or configuration validation fails src/specify_cli/extensions/__init__.py110-113 |
CompatibilityError | Raised when extension is incompatible with the environment src/specify_cli/extensions/__init__.py116-119 |
Refresh this wiki