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:

  1. Manifest validationExtensionManifest validates the extension.yml structure and required fields.

  2. Compatibility verificationExtensionManager.check_compatibility() ensures the extension's requires.speckit_version range matches the current installation using semantic versioning specifiers.

  3. File deployment – The entire source directory copies into .specify/extensions/<extension-id>/.

  4. Command registrationCommandRegistrar scans provides.commands, rewrites front-matter, adjusts script paths, and writes files like .claude/commands/speckit.myext.mycmd.md.

  5. Hook registrationHookExecutor.register_hooks() injects definitions into .specify/extensions.yml.

  6. Registry persistenceExtensionRegistry.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:

  1. Repository creation – Create a public GitHub repository following the directory layout specified in EXTENSION-PUBLISHING-GUIDE.md.

  2. Manifest authoring – Write a valid extension.yml containing fields: id, name, version, requires.speckit_version, provides.commands, optional hooks, tags, and defaults. Reference the schema in EXTENSION-API-REFERENCE.md.

  3. 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.

  4. Catalog submission – Fork github/spec-kit, edit extensions/catalog.community.json to insert metadata including download URL and version requirements, and update extensions/README.md to list the extension in the Available Extensions table. Submit a pull request against the upstream repository.

  5. Verification – Maintainers execute automated manifest validation and URL accessibility checks, followed by manual security and functionality reviews. Upon approval, verified: true is set, making the extension appear in specify extension search --verified results.

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 in EXTENSION-API-REFERENCE.md and EXTENSION-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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →