Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Spec Kit — Administrator & Developer Guide

Generated May 2026 from github/spec-kit at 6bf4ebb

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

Spec Kit is a Python-based CLI toolkit that implements Spec-Driven Development (SDD) by scaffolding project structures, generating slash commands for AI coding agents, and orchestrating a multi-phase development workflow. The architecture is built around four composable subsystems: integrations (agent adapters), extensions (plugin commands and hooks), presets (template customization layers), and workflows (multi-step automation).

The system is designed as a local-first CLI tool with no server component, no database, and no runtime daemon. All state is stored in the filesystem under .specify/ within the project directory.

┌─────────────────────────────────────────────────────────┐
│                    specify CLI (Typer)                    │
│  init │ check │ upgrade │ version                        │
├────────────┬──────────────┬─────────────┬───────────────┤
│ integration│  extension   │   preset    │   workflow    │
│  subsystem │  subsystem   │  subsystem  │   engine      │
├────────────┴──────────────┴─────────────┴───────────────┤
│              CommandRegistrar (agents.py)                 │
│  Renders commands into agent-native formats:             │
│  Markdown │ TOML │ YAML │ Skills                         │
├─────────────────────────────────────────────────────────┤
│                    Filesystem State                       │
│  .specify/  │  .claude/  │  .github/  │  .cursorrules/  │
└─────────────────────────────────────────────────────────┘

Component Inventory

Component Path Role
CLI entry point src/specify_cli/__init__.py Typer app with all commands (5,300+ lines)
Command registrar src/specify_cli/agents.py Renders commands to agent-native formats
Extension system src/specify_cli/extensions.py Extension lifecycle, catalog, hooks, config
Preset system src/specify_cli/presets.py Preset lifecycle, catalog, template resolution
Integration base src/specify_cli/integrations/base.py Abstract base classes for agent integrations
Integration catalog src/specify_cli/integrations/catalog.py Integration discovery and metadata
Integration manifest src/specify_cli/integrations/manifest.py File tracking with SHA-256 hashes
Workflow engine src/specify_cli/workflows/engine.py Step execution, state machine, expression eval
Workflow base src/specify_cli/workflows/base.py Workflow manifest parsing
Workflow catalog src/specify_cli/workflows/catalog.py Workflow discovery
Shell scripts (Bash) scripts/bash/ check-prerequisites.sh, common.sh, create-new-feature.sh, setup-plan.sh
Shell scripts (PowerShell) scripts/powershell/ Same scripts in PowerShell format
Core templates templates/ spec-template.md, plan-template.md, tasks-template.md, checklist-template.md, constitution-template.md
VS Code settings templates/vscode-settings.json Copilot prompt file recommendations and script auto-approve

Technology Stack

Layer Technology
Language Python 3.11+
CLI framework Typer (Click-based)
Terminal UI Rich (panels, tables, trees, live display)
Keyboard input readchar (cross-platform)
JSON parsing json5 (JSONC-compatible)
YAML parsing PyYAML
Version comparison packaging
Platform paths platformdirs
Package manager uv / pip
Build system Hatch (hatchling)

Data Flow: Full SDD Cycle

specify init --integration claude
    │
    ├── Check prerequisites (git, claude CLI)
    ├── Create .specify/ directory structure
    ├── Copy bundled templates and scripts
    ├── Install integration (register commands via CommandRegistrar)
    ├── Auto-install Git extension (if git available)
    ├── Initialize git repo (unless --no-git)
    ├── Copy constitution template to .specify/memory/
    └── Save init-options.json

User runs /speckit.specify in Claude Code
    │
    ├── AI reads spec-template.md (resolved through preset stack)
    ├── Scripts: check-prerequisites.sh --paths-only
    ├── Creates feature branch (Git extension hook: before_specify)
    ├── Generates specs/<branch>/spec.md
    └── Auto-commit (Git extension hook: after_specify, if configured)

/speckit.plan → /speckit.tasks → /speckit.implement
    │
    └── Each phase: check prerequisites → read templates → generate artifact → optional hooks

Note

The workflow engine (workflows/engine.py) can automate this entire cycle with review gates at each step. The built-in speckit workflow requires an integration from copilot, claude, or gemini.

2. System Requirements

Requirement Version Required Notes
Python ≥3.11 Yes Runtime for the CLI
uv Latest Recommended Package management and tool installation
Git Any recent No Required for the Git extension and branching features
AI agent CLI Varies At least one Claude Code, Copilot (VS Code), Gemini CLI, etc.

Python Dependencies

Package Purpose
typer CLI framework (Click-based, with type hints)
rich Terminal formatting (panels, tables, progress trees)
platformdirs Cross-platform config/data directory resolution
readchar Cross-platform keyboard input (arrow key selection)
json5 JSONC parsing (comments and trailing commas)
pyyaml YAML parsing for extensions, presets, workflows, configs
packaging PEP 440 version parsing and comparison

Important

These dependencies are declared in the script header of __init__.py and in pyproject.toml. They are installed automatically when using uv tool install specify-cli.

3. Configuration Reference

Config Files

File Format Location Purpose
init-options.json JSON .specify/ Records CLI flags used during specify init
speckit.manifest.json JSON .specify/ Tracks all files installed by spec-kit with SHA-256 hashes
extension.yml YAML .specify/extensions/<id>/ Extension manifest (schema, commands, hooks, config)
preset.yml YAML .specify/presets/<id>/ Preset manifest (schema, templates, composition)
git-config.yml YAML .specify/extensions/git/ Git extension configuration
catalog-config.json JSON .specify/extensions/ Custom extension catalog sources
preset-catalog-config.json JSON .specify/presets/ Custom preset catalog sources
registry.json JSON .specify/extensions/ Extension registry (installed extensions metadata)
registry.json JSON .specify/presets/ Preset registry (installed presets metadata)
vscode-settings.json JSON .vscode/settings.json VS Code settings (merged, not overwritten)

Environment Variables

Variable Type Default Description Required
SPECKIT_CATALOG_URL String GitHub raw URL Override the built-in extension catalog URL No
SPECKIT_PRESET_CATALOG_URL String GitHub raw URL Override the built-in preset catalog URL No

CLI Flags — specify init

Flag Type Default Description
--integration String None (interactive) AI agent integration to activate
--integration-options String None Options string for the integration
--script sh | ps None (interactive) Script type for shell scripts
--preset String None Preset to install during init
--branch-numbering sequential | timestamp sequential Branch numbering strategy
--here Flag False Init in current directory
--force Flag False Overwrite existing files
--no-git Flag False Skip git init
--ai-skills Flag False Install as agent skills
-V / --version Flag — Show version and exit

Git Extension Configuration (git-config.yml)

# Branch numbering strategy: "sequential" (001, 002, ...) or "timestamp" (YYYYMMDD-HHMMSS)
branch_numbering: sequential

# Commit message used by `git commit` during repository initialization
init_commit_message: "[Spec Kit] Initial commit"

# Auto-commit before/after core commands
auto_commit:
  default: false
  before_clarify:
    enabled: false
    message: "[Spec Kit] Save progress before clarification"
  before_plan:
    enabled: false
    message: "[Spec Kit] Save progress before planning"
  after_specify:
    enabled: false
    message: "[Spec Kit] Add specification"
  after_plan:
    enabled: false
    message: "[Spec Kit] Add implementation plan"
  after_implement:
    enabled: false
    message: "[Spec Kit] Implementation progress"
  # ... (18 hook points total: before/after for 9 core commands)

Tip

Set auto_commit.default: true to enable automatic commits for all commands, then selectively disable specific ones. Each hook point can be individually configured with a custom commit message.

Extension Manifest Schema (extension.yml)

schema_version: "1.0"

extension:
  id: "my-extension"            # Lowercase alphanumeric with hyphens
  name: "My Extension"
  version: "1.0.0"              # Semantic versioning
  description: "Brief description"
  author: "Your Name"
  repository: "https://github.com/..."
  license: "MIT"

requires:
  speckit_version: ">=0.2.0"    # PEP 440 version specifier
  tools:
    - name: "example-tool"
      version: ">=1.0.0"
      required: true

provides:
  commands:
    - name: "speckit.my-extension.example"  # Must follow speckit.<ext>.<cmd> pattern
      file: "commands/example.md"
      description: "Example command"
      aliases: ["speckit.my-extension.ex"]  # Optional aliases
  config:
    - name: "my-config.yml"
      template: "config-template.yml"
      required: false

hooks:
  after_tasks:
    command: "speckit.my-extension.example"
    optional: true              # true = prompt user; false = auto-execute
    prompt: "Run example command?"
    description: "Hook description"

tags:
  - "example"

Important

Extension IDs must be lowercase alphanumeric with hyphens only. Command names must follow the pattern speckit.<extension-id>.<command-name>. Aliases must use the same namespace. Commands that conflict with core or other installed extension commands will be rejected.

Preset Manifest Schema (preset.yml)

schema_version: "1.0"

preset:
  id: "my-preset"
  name: "My Preset"
  version: "1.0.0"
  description: "Brief description"
  author: "Your Name"
  repository: "https://github.com/..."
  license: "MIT"

requires:
  speckit_version: ">=0.1.0"

provides:
  templates:
    - type: "template"          # "template", "command", or "script"
      name: "spec-template"
      file: "templates/spec-template.md"
      description: "Custom spec template"
      replaces: "spec-template"
      strategy: "replace"       # "replace" (default), "prepend", "append", "wrap"

tags:
  - "example"

Composition strategies:

Strategy Behavior
replace Fully replaces the lower-priority template (default)
prepend Places content BEFORE the lower-priority template
append Places content AFTER the lower-priority template
wrap Uses {CORE_TEMPLATE} placeholder; replaced with lower-priority content

Note

Scripts only support replace and wrap strategies. The wrap strategy for scripts uses $CORE_SCRIPT as the placeholder.

4. Deployment & Scaling

Spec Kit is a local CLI tool — there is no server deployment. Distribution is handled through PyPI.

Package Distribution

The package is built with Hatch (hatchling build backend). The pyproject.toml configures:

  • Package name: specify-cli
  • Entry point: specify = "specify_cli:main"
  • Build includes src/specify_cli/ with a core_pack/ directory containing bundled templates, scripts, extensions, presets, and workflows

Wheel Layout

specify_cli/
├── __init__.py          # CLI entry point (5,300+ lines)
├── agents.py            # CommandRegistrar
├── extensions.py        # Extension system
├── presets.py           # Preset system
├── integrations/        # 27+ agent integrations
│   ├── base.py
│   ├── catalog.py
│   ├── manifest.py
│   └── <agent>/__init__.py (one per integration)
├── workflows/           # Workflow engine
│   ├── engine.py
│   ├── base.py
│   ├── catalog.py
│   ├── expressions.py
│   └── steps/           # Step types (command, gate, shell, prompt, etc.)
└── core_pack/           # Bundled assets (templates, scripts, extensions, presets, workflows)

Note

The core_pack/ directory is created at build time by hatchling's force-include configuration. It is not present in source checkouts or editable installs. The code falls back to repo-relative paths in those cases.

5. Operations

Catalog Infrastructure

Spec Kit uses JSON catalogs hosted on GitHub for extension, preset, and workflow discovery:

Catalog URL Purpose
Extension (official) github/spec-kit/main/extensions/catalog.json Bundled extensions (git, selftest)
Extension (community) github/spec-kit/main/extensions/catalog.community.json Community extensions (50+)
Preset (official) github/spec-kit/main/presets/catalog.json Bundled presets (lean)
Preset (community) github/spec-kit/main/presets/catalog.community.json Community presets (11+)
Workflow (official) github/spec-kit/main/workflows/catalog.json Bundled workflows (speckit)
Workflow (community) github/spec-kit/main/workflows/catalog.community.json Community workflows (empty)

Catalogs are fetched via HTTPS (HTTP only allowed for localhost). The cache is stored locally and can be cleared with specify extension catalog clear or equivalent preset commands.

Tip

Organizations can host private catalogs and configure them via catalog-config.json in .specify/extensions/ or .specify/presets/. Each catalog entry supports url, name, priority, install_allowed, and description fields.

File Integrity Tracking

The IntegrationManifest system (in integrations/manifest.py) tracks every file installed by spec-kit:

  • Files are recorded with SHA-256 hashes
  • On uninstall, only unmodified files are removed
  • Modified files are preserved (unless --force is used)
  • Empty parent directories are cleaned up after file removal
  • Path traversal attacks are blocked (no ../ or absolute paths)
  • Symlinks are treated as modified files (skipped without --force)

Note

The manifest is stored at .specify/speckit.manifest.json. Each integration and extension maintains its own manifest for clean uninstall behavior.

Version Checking

The specify upgrade command checks the GitHub Releases API (https://api.github.com/repos/github/spec-kit/releases/latest) for newer versions. Version comparison uses the packaging library for PEP 440 compliance.

6. Performance

Spec Kit is a scaffolding tool — performance characteristics are dominated by I/O (file copying, git operations) rather than computation.

Key performance notes:

  • The init command copies bundled assets from the wheel's core_pack/ directory, avoiding network requests
  • Extension/preset installation from catalogs requires one HTTPS fetch per catalog, with local caching
  • The CommandRegistrar renders commands into agent-native formats at install time, not at command execution time
  • The workflow engine executes steps sequentially with optional gate pauses
  • Template resolution (PresetResolver) walks the priority stack once per resolve call, merging composition layers

Tip

For large teams, consider pre-populating .specify/ directories in project templates or monorepo scaffolds to avoid per-developer initialization costs.

7. Security

Catalog URL Validation

All catalog URLs must use HTTPS. HTTP is only permitted for localhost (development/testing). This is enforced by ValidationError in both ExtensionCatalog and PresetCatalog.

if parsed.scheme != "https":
    if parsed.scheme == "http" and parsed.hostname in ("localhost", "127.0.0.1"):
        pass  # Allowed for local development
    else:
        raise ValidationError(f"Catalog URL must use HTTPS (got {parsed.scheme}://)")

ZIP Archive Safety

Extension and preset installation from ZIP files includes path traversal protection:

  • All archive members are checked for .. path components
  • Absolute paths in ZIP entries are rejected
  • The extraction uses a safe path validation before writing
if '..' in member or os.path.isabs(member):
    raise ValidationError(f"Unsafe path in ZIP archive: {member} (potential path traversal)")

Extension Command Namespace Isolation

Extensions must use their own namespace for commands: speckit.<extension-id>.<command>. The system rejects:

  • Commands that conflict with core command namespaces
  • Commands that conflict with other installed extensions
  • Duplicate command names or aliases within a manifest

Integration Manifest Integrity

The manifest system prevents:

  • Recording files outside the project root (path traversal via ../)
  • Recording files with absolute paths
  • Uninstalling files that have been modified (hash mismatch)
  • Symlink-based attacks (symlinks are treated as modified)

Warning

Extension hooks can execute arbitrary commands within the AI agent context. Review extension manifests before installation, especially hooks with optional: false (auto-execute without prompting).

Version Compatibility

Extensions and presets declare a requires.speckit_version constraint using PEP 440 version specifiers. Installation is blocked if the running spec-kit version doesn't satisfy the constraint:

Extension requires spec-kit >=0.7.0, but 0.6.2 is installed.
Upgrade spec-kit with: uv tool install specify-cli --force

Caution

The --force flag on extension remove and integration uninstall deletes files even if they've been modified. Use with care in shared repositories.

8. Developer Internals

Repository Structure

github/spec-kit/
├── src/specify_cli/            # Main package
│   ├── __init__.py             # CLI commands (5,300+ lines, Typer app)
│   ├── agents.py               # CommandRegistrar — multi-format command renderer
│   ├── extensions.py           # Extension system (2,600+ lines)
│   ├── presets.py              # Preset system (3,000+ lines)
│   ├── integrations/           # 27+ agent integrations
│   │   ├── __init__.py         # INTEGRATION_REGISTRY population
│   │   ├── base.py             # IntegrationBase, MarkdownIntegration, TomlIntegration, SkillsIntegration
│   │   ├── catalog.py          # IntegrationCatalogEntry, IntegrationDescriptor
│   │   ├── manifest.py         # IntegrationManifest (file tracking + SHA-256)
│   │   ├── claude/__init__.py  # Claude Code integration
│   │   ├── copilot/__init__.py # GitHub Copilot integration
│   │   └── ...                 # One module per integration
│   └── workflows/
│       ├── __init__.py
│       ├── base.py             # WorkflowManifest parsing
│       ├── catalog.py          # Workflow discovery
│       ├── engine.py           # WorkflowEngine — step execution
│       ├── expressions.py      # Template expression evaluation
│       └── steps/              # Step type implementations
│           ├── command/        # Command step (run a slash command)
│           ├── gate/           # Gate step (approve/reject)
│           ├── shell/          # Shell step
│           ├── prompt/         # Prompt step
│           ├── if_then/        # Conditional branching
│           ├── switch/         # Multi-branch conditional
│           ├── while_loop/     # While loop
│           ├── do_while/       # Do-while loop
│           ├── fan_out/        # Parallel fan-out
│           └── fan_in/         # Parallel fan-in (join)
├── extensions/
│   ├── git/                    # Bundled Git extension
│   ├── selftest/               # Bundled self-test extension
│   └── template/               # Extension development template
├── presets/
│   ├── lean/                   # Bundled Lean preset
│   ├── scaffold/               # Preset development scaffold
│   └── self-test/              # Bundled self-test preset
├── workflows/
│   └── speckit/                # Bundled Full SDD Cycle workflow
├── integrations/               # Integration catalog JSON files
├── templates/                  # Core command templates
├── scripts/
│   ├── bash/                   # Bash helper scripts
│   └── powershell/             # PowerShell helper scripts
├── tests/
│   ├── integrations/           # Integration tests (39 files, 264K chars)
│   ├── extensions/             # Extension tests
│   ├── hooks/                  # Hook test fixtures
│   ├── test_workflows.py
│   ├── test_presets.py
│   ├── test_extensions.py
│   └── ...
├── docs/                       # DocFX documentation source
├── media/                      # Logos, screenshots, GIFs
├── newsletters/                # Community newsletters
├── pyproject.toml              # Package configuration
├── AGENTS.md                   # Agent context file
├── CITATION.cff                # Citation metadata
└── .zenodo.json                # Zenodo deposit metadata

Architecture Deep Dive

CommandRegistrar (agents.py)

The CommandRegistrar is the bridge between Spec Kit's template system and the diverse formats required by AI coding agents. It renders a single command definition into multiple agent-native formats:

  • Markdown: Standard .md files with YAML frontmatter (Claude, Copilot agent mode, Windsurf, most agents)
  • TOML: .toml files with description and prompt fields (Gemini, Tabnine)
  • YAML: .yaml files with title and prompt fields (Goose)
  • Skills: Directory-based layout with SKILL.md files containing structured frontmatter (Claude skills, Copilot skills, Cursor, Codex, Kimi, Trae, Agy)

Key methods:

Method Purpose
parse_frontmatter() Extract YAML frontmatter from markdown content
render_frontmatter() Serialize frontmatter dict back to YAML
render_markdown_command() Render for Markdown-format agents
render_toml_command() Render for TOML-format agents
render_yaml_command() Render for YAML-format agents
render_skill_command() Render for Skills-format agents
register_commands() Write command files to agent directory
register_commands_for_all_agents() Register across all detected agent directories
unregister_commands() Remove previously registered command files
write_copilot_prompt() Write companion .prompt.md files for Copilot

The registrar also handles agent-specific post-processing:

  • Claude: Injects disableModelInvocation: false and hook command notes into skill frontmatter
  • Copilot: Injects mode: agent into skill frontmatter
  • Cursor: Upserts .mdc frontmatter with alwaysApply: false
  • Forge: Reformats command names from dotted to hyphenated (e.g., speckit.specify → speckit-specify)

Integration System (integrations/)

Each integration is a Python class inheriting from one of four base classes:

Base Class Format Agents
MarkdownIntegration .md with frontmatter Windsurf, Amp, Auggie, Bob, CodeBuddy, iFlow, Junie, Kilocode, Kiro, opencode, Pi, Qoder, Qwen, Roo, SHAI, Vibe
TomlIntegration .toml files Gemini, Tabnine
YamlIntegration .yaml files Goose
SkillsIntegration Skill directories Claude, Codex, Cursor, Kimi, Trae, Agy

Special integrations with custom logic:

  • copilot: Supports both agent mode (.md files with companion .prompt.md) and skills mode (directory-based). Manages .vscode/settings.json merging
  • claude: Skills layout with disableModelInvocation flag, BOM stripping for context files, argument hints in frontmatter
  • forge: Custom command name formatting (dotted → hyphenated), parameter placeholder support
  • generic: Requires --commands-dir option; no agent config folder assumed

The INTEGRATION_REGISTRY is populated at import time by scanning all integration modules. Each integration's key must match its CLI tool name.

Extension System (extensions.py)

The extension system is the largest module (2,600+ lines) and provides:

Core classes:

Class Purpose
ExtensionManifest Parses and validates extension.yml
ExtensionRegistry JSON-backed registry of installed extensions
ExtensionManager Install, remove, list, compatibility checking
ExtensionCatalog Fetch/cache/search catalogs, download ZIPs
CommandRegistrar Extension-specific command registration
ConfigManager Extension config file management
HookExecutor Event-driven hook system

Validation rules enforced by ExtensionManifest:

  • Schema version must be "1.0"
  • Extension ID: lowercase alphanumeric with hyphens only
  • Version: valid semantic version
  • Must provide at least one command or hook
  • Command names must follow speckit.<ext-id>.<cmd> pattern
  • Aliases must use the same extension namespace
  • No conflict with core command namespaces
  • No conflict with other installed extensions' commands

Hook lifecycle:

The HookExecutor supports these event points:

before_constitution, after_constitution
before_specify, after_specify
before_clarify, after_clarify
before_plan, after_plan
before_tasks, after_tasks
before_implement, after_implement
before_checklist, after_checklist
before_analyze, after_analyze
before_taskstoissues, after_taskstoissues

Hooks with optional: true prompt the user before execution. Hooks with optional: false execute automatically.

Preset System (presets.py)

The preset system (3,000+ lines) mirrors the extension system architecture but adds template composition:

Core classes:

Class Purpose
PresetManifest Parses and validates preset.yml
PresetRegistry JSON-backed registry of installed presets
PresetManager Install, remove, list, compatibility checking
PresetCatalog Fetch/cache/search catalogs, download ZIPs
PresetResolver Multi-layer template resolution with composition

Template resolution order (highest to lowest priority):

  1. Installed presets (by priority number, lowest = highest priority)
  2. Extension-provided commands (via manifest)
  3. Core templates (bundled in .specify/templates/)

Composition execution in PresetResolver.resolve_content():

  1. Collect all layers for the requested template
  2. Start with the lowest-priority layer's content
  3. Walk up the priority stack, applying each layer's strategy:
    • replace: discard everything below, use this layer
    • prepend: concatenate this layer + lower content
    • append: concatenate lower content + this layer
    • wrap: replace {CORE_TEMPLATE} in this layer with lower content

Workflow Engine (workflows/)

The workflow engine supports YAML-defined automation with these step types:

Step Type Module Purpose
command steps/command/ Execute a spec-kit slash command
gate steps/gate/ Pause for human review (approve/reject)
shell steps/shell/ Execute a shell command
prompt steps/prompt/ Prompt the user for input
if_then steps/if_then/ Conditional branching
switch steps/switch/ Multi-branch conditional
while_loop steps/while_loop/ While loop
do_while steps/do_while/ Do-while loop
fan_out steps/fan_out/ Parallel execution
fan_in steps/fan_in/ Join parallel branches

The expressions.py module handles template expression evaluation (e.g., {{ inputs.spec }}, {{ steps.specify.output }}).

Module Reference

src/specify_cli/__init__.py (5,300+ lines)

The monolithic CLI module contains all Typer commands organized into groups:

Command Group Commands
Top-level init, check, version, upgrade
integration list, install, uninstall, switch, upgrade
preset list, add, remove, search, resolve, info, set-priority, enable, disable
preset catalog list, add, remove
extension list, add, remove, search, info, update, enable, disable, set-priority
extension catalog list, add, remove
workflow run, resume, status, list, add, remove, search, info
workflow catalog list, add, remove

Key utility functions:

Function Purpose
_locate_core_pack() Find bundled assets in wheel or source checkout
_locate_bundled_extension() Find a bundled extension by ID
_locate_bundled_preset() Find a bundled preset by ID
_locate_bundled_workflow() Find a bundled workflow by ID
_install_shared_infra() Install scripts and templates with manifest tracking
ensure_executable_scripts() Set POSIX execute bits on .sh files
ensure_constitution_from_template() Copy constitution template to memory directory
check_tool() Check if a tool is installed (special handling for Claude local paths)
select_with_arrows() Interactive arrow-key selection UI using Rich Live
merge_json_files() Polite deep merge for JSON/JSONC files
save_init_options() / load_init_options() Persist and restore init configuration

src/specify_cli/agents.py

The CommandRegistrar class (620+ lines) with two distinct implementations:

  1. Core CommandRegistrar (agents.py): Used during specify init to register core command templates
  2. Extension CommandRegistrar (extensions.py:1412): Extends the core registrar for extension command registration

Both share parse_frontmatter() and render_frontmatter() but differ in how they handle agent-specific rendering.

src/specify_cli/extensions.py (2,600+ lines)

Major classes and their line counts:

Class Start Line Purpose
ExtensionManifest 119 Manifest parsing with full validation
ExtensionRegistry 360 JSON-backed installed extension tracking
ExtensionManager 597 Install/remove lifecycle
CommandRegistrar 1412 Extension command registration
ExtensionCatalog 1502 Catalog fetch/cache/search/download
ConfigManager 2026 Extension config file management
HookExecutor 2225 Event-driven hook system

src/specify_cli/presets.py (3,000+ lines)

Major classes and their line counts:

Class Start Line Purpose
PresetManifest 117 Manifest parsing with template type and strategy validation
PresetRegistry 296 JSON-backed installed preset tracking
PresetManager 527 Install/remove lifecycle
PresetCatalog 1786 Catalog fetch/cache/search/download
PresetResolver 2307 Multi-layer template resolution with composition

Code Patterns and Conventions

File operations: Atomic writes via tempfile.NamedTemporaryFile + os.replace() for JSON files. Existing file permissions and ownership are preserved where possible.

Error handling: Custom exception hierarchies per subsystem:

  • Extensions: ExtensionError → ValidationError, CompatibilityError
  • Presets: PresetError → PresetValidationError, PresetCompatibilityError

Registry pattern: Both extensions and presets use a JSON-backed registry with add/remove/update/restore/get/list operations. The registry persists to .specify/<subsystem>/registry.json.

Manifest pattern: IntegrationManifest uses SHA-256 hashing for file change detection. Files are recorded at install time and verified at uninstall.

Catalog pattern: Both subsystems use the same catalog architecture: HTTPS fetch → JSON parse → local cache → search/filter. Catalogs support priority ordering and multi-source configuration.

Version checking: Uses packaging.version.Version for PEP 440 compliance. The version_satisfies() function handles specifier ranges like >=0.7.0,<1.0.0.

CLI argument handling: Typer with Click-based commands. The --integration-options flag is parsed as a shell-style string using shlex.

Testing Strategy

The test suite (39 integration test files, 264K chars) is organized by subsystem:

Test Area Files Focus
tests/integrations/ 39 All 27 integrations with base class test mixins
tests/extensions/ 1 Git extension tests
tests/test_workflows.py 1 Workflow engine tests
tests/test_presets.py 1 Preset system tests
tests/test_extensions.py 1 Extension system tests
tests/test_cli_version.py 1 Version command tests
tests/test_check_tool.py 1 Tool detection tests
tests/test_merge.py 1 JSON merge tests
tests/test_upgrade.py 1 Upgrade command tests
tests/test_branch_numbering.py 1 Branch naming tests
tests/test_registrar_path_traversal.py 1 Security: path traversal prevention
tests/test_agent_config_consistency.py 1 Config alignment tests
tests/test_timestamp_branches.py 1 Timestamp branch format tests
tests/test_extension_skills.py 1 Extension skills rendering tests

Test mixins for integrations:

  • MarkdownIntegrationTests — 20+ tests for Markdown-format agents
  • SkillsIntegrationTests — 25+ tests for Skills-format agents
  • TomlIntegrationTests — 20+ tests for TOML-format agents
  • YamlIntegrationTests — 15+ tests for YAML-format agents

Each integration's test class inherits the appropriate mixin and runs the full suite against that specific agent adapter.

Potential Improvements

Based on the codebase analysis:

  1. __init__.py is 5,300+ lines — a single monolithic file containing all CLI commands. Splitting into cli_init.py, cli_integration.py, cli_extension.py, cli_preset.py, cli_workflow.py would improve maintainability.

  2. No formal plugin interface for step types — workflow step types are discovered by module name convention. A registry pattern (like integrations use) would make this more extensible.

  3. Duplicate catalog logic — ExtensionCatalog and PresetCatalog share nearly identical URL validation, fetch, cache, and search logic. A base Catalog class would reduce duplication.

  4. No dependency file detected — the AST extractor found 0 dependency files, suggesting pyproject.toml parsing isn't being picked up. Dependencies are declared in the script header comment block.

  5. Community catalog contribution workflow — currently requires manual PR to add JSON entries. A CLI command like specify extension publish could automate validation and PR creation.

Contributing

The project uses:

  • License: MIT
  • Build system: Hatch (hatchling)
  • Test framework: pytest with tmp_path fixtures
  • Linting: markdownlint-cli2 (configured in .markdownlint-cli2.jsonc)
  • Citation: CITATION.cff and .zenodo.json for academic referencing
  • Documentation: DocFX (build with cd docs && docfx docfx.json --serve)

To develop locally:

git clone https://github.com/github/spec-kit.git
cd spec-kit
uv sync
uv run pytest

Extension development:

  1. Copy extensions/template/ to a new directory
  2. Edit extension.yml with your extension ID, commands, and hooks
  3. Create command files in commands/
  4. Test locally with specify extension add <id> --dev
  5. Publish to GitHub and submit a PR to extensions/catalog.community.json

Preset development:

  1. Copy presets/scaffold/ to a new directory
  2. Edit preset.yml with your preset ID and templates
  3. Create template files with optional composition strategies
  4. Test locally with specify preset add <id> --dev
  5. Publish and submit a PR to presets/catalog.community.json

9. Integration Points

Git Integration (Bundled Extension)

The Git extension is auto-installed during specify init when Git is detected. It provides:

  • Feature branch creation with sequential (001, 002, …) or timestamp (YYYYMMDD-HHMMSS) numbering
  • 18 lifecycle hooks (before/after for 9 core commands)
  • Configurable auto-commit with per-command messages
  • Branch validation and remote detection
  • Configuration via .specify/extensions/git/git-config.yml

VS Code Integration

When Copilot is the selected integration, Spec Kit manages .vscode/settings.json:

{
    "chat.promptFilesRecommendations": {
        "speckit.constitution": true,
        "speckit.specify": true,
        "speckit.plan": true,
        "speckit.tasks": true,
        "speckit.implement": true
    },
    "chat.tools.terminal.autoApprove": {
        ".specify/scripts/bash/": true,
        ".specify/scripts/powershell/": true
    }
}

The merge is "polite" — existing keys are never overwritten, only new keys are added.

Agent Context Files

Each integration writes to a context file that the AI agent reads:

Integration Context File
Claude CLAUDE.md
Copilot .github/copilot-instructions.md
Generic AGENTS.md
Others Agent-specific (e.g., .cursorrules, .goose/config.yaml)

A managed section delimited by <!-- SPECKIT START --> / <!-- SPECKIT END --> is upserted into these files. BOM characters are stripped during processing.

Shell Script Integration

The bundled scripts in .specify/scripts/ provide project-level utility:

Script Purpose
check-prerequisites.sh / .ps1 Validate feature directory, spec, plan, tasks existence
common.sh / .ps1 Shared functions: find repo root, resolve feature paths, JSON escape
create-new-feature.sh / .ps1 Create a new feature branch and directory structure
setup-plan.sh / .ps1 Set up the planning phase prerequisites

Scripts support --json, --require-tasks, --include-tasks, and --paths-only flags.

Note

On POSIX systems, ensure_executable_scripts() automatically sets execute bits on .sh files during init. On Windows, this is a no-op.