-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Description
Summary
Introduce a pluggable template system that decouples Spec Kit's artifact templates (spec, plan, tasks, checklist, constitution, etc.) and command templates from the core release, making them discoverable, customizable, and distributable — similar to the extension system. This includes a template catalog that mirrors the multi-catalog pattern proposed in #1707 for extensions.
Problem Statement
Today, templates are hardcoded into the release ZIP and copied verbatim during specify init. This creates several problems:
| Problem | Impact |
|---|---|
| No customization without forking | Organizations must fork the entire repo to modify spec-template.md or plan-template.md — even if they just want to add a "Compliance" section |
| One-size-fits-all artifacts | Healthcare projects, fintech compliance, game development, and microservices all get the same spec/plan/tasks structure |
| Templates can't evolve independently | A community-contributed "SAFe tasks template" or "ADR-based plan template" requires a core PR + release cycle |
| Extensions can't provide templates | The extension system supports commands and hooks but has no way to provide custom artifact templates (e.g., a Jira extension wanting a Jira-aware tasks template) |
| No template composition | Users can't layer modifications (org base + team overrides + project-specific) — it's all-or-nothing replacement |
| Scripts hardcode template paths | create-new-feature.sh and setup-plan.sh reference .specify/templates/spec-template.md and .specify/templates/plan-template.md directly with no resolution mechanism |
Proposed Solution
1. Template Pack Manifest (template-pack.yml)
A template pack is a self-contained, versioned collection of templates with a declarative manifest — mirroring the extension extension.yml pattern:
schema_version: "1.0"
template_pack:
id: "healthcare-compliance" # Unique identifier (lowercase, alphanumeric, hyphens)
name: "Healthcare Compliance Templates"
version: "1.0.0"
description: "HIPAA/SOX-aware spec and plan templates with compliance sections"
author: "healthcare-org"
repository: "https://github.com/healthcare-org/spec-kit-templates-healthcare"
license: "MIT"
requires:
speckit_version: ">=0.1.0"
provides:
templates:
# Artifact templates (scaffolds for spec.md, plan.md, etc.)
- type: "artifact"
name: "spec-template" # Overrides core spec-template.md
file: "templates/spec-template.md"
description: "HIPAA-compliant feature specification with PHI sections"
replaces: "spec-template" # Which core template this overrides (optional)
- type: "artifact"
name: "plan-template"
file: "templates/plan-template.md"
description: "Plan template with compliance review gates"
replaces: "plan-template"
- type: "artifact"
name: "compliance-checklist-template"
file: "templates/compliance-checklist-template.md"
description: "HIPAA compliance checklist (new, does not replace core)"
# No 'replaces' — this is additive
# Command templates (prompts that drive AI agents)
- type: "command"
name: "specify"
file: "commands/specify.md"
description: "Specification command with compliance guidance"
replaces: "specify"
tags: ["healthcare", "hipaa", "compliance", "regulated"]Template types:
artifact— Document scaffolds materialized as files (spec.md, plan.md, tasks.md, checklist.md, constitution.md). These are copied into thespecs/<feature>/directory when creating new features.command— AI agent prompts (the files in.claude/commands/,.github/agents/, etc.). These control how the AI agent produces artifacts.
2. Template Resolution Order
When a script or command needs a template (e.g., create-new-feature.sh needs spec-template.md), the system resolves it through a layered stack:
Priority 1: .specify/templates/overrides/ ← Project-local overrides (manual edits)
Priority 2: .specify/templates/packs/<pack-id>/ ← Installed template packs
Priority 3: .specify/extensions/<ext-id>/templates/ ← Extension-provided templates
Priority 4: .specify/templates/ ← Core templates (shipped with Spec Kit)
A new helper function (resolve_template()) replaces hardcoded paths:
# Before (hardcoded):
TEMPLATE="$REPO_ROOT/.specify/templates/spec-template.md"
# After (resolved):
TEMPLATE=$(resolve_template "spec-template" "$REPO_ROOT")This function walks the priority stack and returns the first match, enabling non-destructive customization.
3. Template Catalog (Dual-Catalog, Multi-Catalog Ready)
Mirrors the extension catalog structure and is designed to integrate with the multi-catalog stack from #1707:
templates/catalog.json (org-curated, empty by default):
{
"schema_version": "1.0",
"updated_at": "2026-02-26T00:00:00Z",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/templates/catalog.json",
"template_packs": {}
}templates/catalog.community.json (community-contributed):
{
"schema_version": "1.0",
"updated_at": "2026-02-26T00:00:00Z",
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/templates/catalog.community.json",
"template_packs": {
"safe-agile": {
"name": "SAFe Agile Templates",
"id": "safe-agile",
"description": "SAFe-aligned spec, plan, and tasks templates with PI planning support",
"author": "agile-community",
"version": "1.0.0",
"download_url": "https://github.com/agile-community/spec-kit-templates-safe/archive/refs/tags/v1.0.0.zip",
"repository": "https://github.com/agile-community/spec-kit-templates-safe",
"license": "MIT",
"requires": { "speckit_version": ">=0.1.0" },
"provides": { "artifact_templates": 3, "command_templates": 2 },
"tags": ["safe", "agile", "pi-planning", "enterprise"],
"verified": false,
"downloads": 0,
"created_at": "2026-02-26T00:00:00Z",
"updated_at": "2026-02-26T00:00:00Z"
}
}
}When #1707 lands, template catalogs slot into the same .specify/extension-catalogs.yml stack (or a parallel .specify/template-catalogs.yml) with the same priority + install_allowed semantics.
4. CLI Commands
# Search for template packs
specify template search [query] [--tag TAG] [--author AUTHOR]
# Install a template pack
specify template add <pack-id>
specify template add --from <url>
specify template add --dev /path/to/local/pack
# List installed template packs
specify template list
# Remove a template pack
specify template remove <pack-id>
# Show which template will be resolved for a given name
specify template resolve <template-name>
# → spec-template: .specify/templates/packs/healthcare-compliance/templates/spec-template.md
# (from: healthcare-compliance v1.0.0, overrides core)
# Initialize with a template pack
specify init --ai claude --template healthcare-compliance5. Extension ↔ Template Integration
Extensions can declare template packs as dependencies or bundle their own templates:
# In extension.yml
provides:
commands:
- name: "speckit.jira.specstoissues"
file: "commands/specstoissues.md"
templates: # NEW: Extensions can provide templates
- type: "artifact"
name: "tasks-template"
file: "templates/tasks-template.md"
description: "Tasks template with Jira issue ID placeholders"
replaces: "tasks-template"Resolution priority with extensions:
Priority 1: .specify/templates/overrides/ ← Project-local
Priority 2: .specify/templates/packs/<pack-id>/ ← Template packs
Priority 3: .specify/extensions/<ext-id>/templates/ ← Extension-provided
Priority 4: .specify/templates/ ← Core defaults
6. Directory Structure
project/
├── .specify/
│ ├── templates/ # Core templates (existing, unchanged)
│ │ ├── spec-template.md
│ │ ├── plan-template.md
│ │ ├── tasks-template.md
│ │ ├── checklist-template.md
│ │ ├── constitution-template.md
│ │ ├── agent-file-template.md
│ │ ├── vscode-settings.json
│ │ ├── commands/ # Core command templates
│ │ │ ├── specify.md
│ │ │ ├── plan.md
│ │ │ ├── tasks.md
│ │ │ └── ...
│ │ ├── overrides/ # (NEW) Project-local overrides
│ │ │ └── spec-template.md # Custom spec for this project
│ │ └── packs/ # (NEW) Installed template packs
│ │ ├── .registry # Track installed packs (JSON)
│ │ └── healthcare-compliance/ # Installed pack
│ │ ├── template-pack.yml # Pack manifest
│ │ ├── templates/
│ │ │ ├── spec-template.md
│ │ │ └── plan-template.md
│ │ └── commands/
│ │ └── specify.md
│ ├── extensions/ # (Existing)
│ └── memory/ # (Existing)
7. Implementation in Python (src/specify_cli/)
New module: templates.py — mirrors extensions.py architecture:
| Class | Responsibility |
|---|---|
TemplatePackManifest |
Load & validate template-pack.yml (regex on id/version, validate template types) |
TemplatePackRegistry |
Track installed packs in .specify/templates/packs/.registry |
TemplatePackManager |
Install/remove/update packs with compatibility checking |
TemplateCatalog |
Fetch/cache/search template catalogs (1-hour TTL, same as extensions) |
TemplateResolver |
Walk priority stack to resolve template name → file path |
The TemplateResolver is the key new concept — it replaces all hardcoded template path lookups.
8. Script Updates
Both bash and PowerShell scripts need a resolve_template helper:
# scripts/bash/common.sh — new function
resolve_template() {
local template_name="$1"
local repo_root="$2"
local base=".specify/templates"
# Priority 1: Project overrides
local override="$repo_root/$base/overrides/${template_name}.md"
[ -f "$override" ] && echo "$override" && return 0
# Priority 2: Installed packs (by registry order)
local packs_dir="$repo_root/$base/packs"
if [ -d "$packs_dir" ]; then
for pack in "$packs_dir"/*/; do
local candidate="$pack/templates/${template_name}.md"
[ -f "$candidate" ] && echo "$candidate" && return 0
done
fi
# Priority 3: Core templates
local core="$repo_root/$base/${template_name}.md"
[ -f "$core" ] && echo "$core" && return 0
return 1
}Acceptance Criteria
-
template-pack.ymlmanifest schema defined and validated (id, version, template types) -
TemplatePackManifest,TemplatePackRegistry,TemplatePackManager,TemplateCatalog,TemplateResolverclasses implemented insrc/specify_cli/templates.py -
specify template search,specify template add,specify template list,specify template removeCLI commands functional -
specify template resolve <name>shows resolved template path with source attribution -
specify init --template <pack-id>installs a template pack during project initialization - Template resolution follows priority stack: overrides → packs → extension-provided → core
-
templates/catalog.jsonandtemplates/catalog.community.jsoncreated with same schema patterns as extension catalogs -
resolve_template()helper added to bothscripts/bash/common.shandscripts/powershell/common.ps1 -
create-new-feature.shandsetup-plan.sh(and PowerShell equivalents) updated to useresolve_template()instead of hardcoded paths - Extensions can declare templates in
extension.ymlunderprovides.templates - Template pack scaffold/template directory created (like
extensions/template/) - Unit tests covering manifest validation, registry persistence, resolution order, catalog search, extension-provided templates
- Documentation: Template Development Guide, Template User Guide, README update
- Compatible with multi-catalog stack design from feat(extensions): support multiple active catalogs simultaneously #1707 (template catalogs can be added to catalog stack)
Out of Scope
- Template inheritance/merging (e.g., "extend core spec-template, add section X") — start with full replacement, consider inheritance in a follow-up
- Template variables/interpolation engine (e.g.,
{{PROJECT_NAME}}substitution) — templates today are static Markdown; keep that for now - Visual template editor / web UI — CLI-only for initial release
- Template versioning with migration (e.g., upgrading from v1 → v2 of a template pack with in-place migration of existing specs) — separate concern
- Catalog authentication / private registry tokens — tracked separately, same as extensions
Design Decisions & Rationale
-
Template packs, not individual templates — A pack bundles related templates (spec + plan + tasks) that are designed to work together. Installing individual templates would create inconsistency between artifacts within the same methodology.
-
Full replacement over inheritance — Template inheritance (inserting sections into a base) is complex and fragile. Full replacement is predictable: you see exactly what you get. Composition can be explored later.
-
Separate from extensions, but interoperable — Templates and extensions serve different purposes (content structure vs. tool integration). Keeping them as separate systems with clear integration points avoids coupling while enabling extensions to provide domain-specific templates.
-
Same catalog architecture — Reusing the dual-catalog pattern (org-curated + community) and targeting compatibility with feat(extensions): support multiple active catalogs simultaneously #1707's multi-catalog stack avoids inventing parallel infrastructure and allows a unified
specify catalogsexperience in the future. -
Resolution over configuration — Instead of requiring users to configure which template to use for each artifact, the system resolves templates by walking a priority stack. Install a pack and it "just works" — no additional configuration needed.
References
- Extension system RFC:
extensions/RFC-EXTENSION-SYSTEM.md - Extension catalog:
extensions/catalog.community.json - Multi-catalog proposal: feat(extensions): support multiple active catalogs simultaneously #1707
- Current template usage in scripts:
scripts/bash/create-new-feature.sh(line 283),scripts/bash/setup-plan.sh(line 40) - Extension manifest:
extensions/template/extension.yml