* feat(presets): add opt-in constitution-sync preset Follow-up to #3790, which removed the consistency-propagation pass from the core /constitution command in favor of runtime resolution. Teams that treat materialized plan/spec/tasks templates as reviewed, committed artifacts lost the auto-sync of amended constitutional guidance on a non-forced upgrade. Add a bundled, opt-in `constitution-sync` preset that restores that behavior via a wrap-strategy override of speckit.constitution (composes on {CORE_TEMPLATE} so it stays forward-compatible). It only writes into the project's own .specify/templates scaffolds and installed command files, never into stack-owned template layers. - presets/constitution-sync/: preset.yml (requires >=0.14.4), wrap command, README documenting the tension between auto-propagation and the resolution stack - presets/catalog.json: bundled entry - docs/upgrade.md: document the 0.14.4 behavior change and the opt-in - tests/test_presets.py: structural + composition coverage (TestConstitutionSyncPreset) Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * fix(presets): ship constitution-sync in wheel, clarify scope guard, assert composition Address review feedback on #3873: - pyproject.toml: force-include presets/constitution-sync into the wheel's core_pack so `_locate_bundled_preset` resolves it in a released install; the bundled advertisement was otherwise unshippable. - tests/contract/test_wheel_bundled_presets.py: new contract test asserting every bundled preset in presets/catalog.json is force-included (guards lean too). - commands/speckit.constitution.md: explicitly state the propagation section supersedes the core Scope Guard, which otherwise says dependent templates are not modified here. - tests/test_presets.py: assert resolve_content substitutes {CORE_TEMPLATE} and the effective command embeds both the core body and the sync pass. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * test(presets): parse frontmatter as YAML in constitution-sync wrapper test Address review feedback on #3873: assert `strategy: wrap` structurally by parsing the Markdown frontmatter as YAML (instead of a substring match that could false-positive on body text), and assert {CORE_TEMPLATE} in the body section only. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(presets): reframe constitution-sync README around behavior and caveats Rework the preset's user-facing docs to describe what it does, what it does not do, and the caveats you take on — rather than leading with version/origin history. The preset stack is the project's forward direction, so the README no longer positions this as "restoring pre-0.14.4 behavior." Also make the edit-in-place vs. composition conflict explicit and consistent across the wrapper command and docs: propagation into command files/templates that are provided or wrapped by a preset/extension is clobbered on stack reconciliation (integration use/upgrade, preset/extension install/remove), so the wrapper restricts propagation to project-local artifacts the team owns. - README: forward-looking "What it does / does not do / When to use / Caveats" - speckit.constitution.md: step 4 no longer hand-edits composed command files; closing caveat covers command files too - docs/upgrade.md: note the composition-model conflict in the opt-in section - tests: assert the updated closing-caveat wording Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(presets): tweak constitution-sync README default-behavior wording Phrase the default-behavior note as "the current version of Spec Kit" and rewrap the opening paragraph. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(presets): keep emphasis spans on one line in constitution-sync README Avoid **bold** spans broken across soft line breaks (runtime resolution, reviewed committed artifacts) so they render consistently. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(presets): refocus constitution-sync README on what it restores Reframe the intro around what the preset restores and what the user opts into, rather than describing current Spec Kit default behavior. Be honest that propagation was removed deliberately (duplicates the source of truth, fights composition) and this preset knowingly reintroduces it and its tradeoffs. Minor flow fixes (comma splice, terse bullet). Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(upgrade): de-pin version from /constitution behavior-change section The upgrade guide always describes the latest version, so hard-pinning "0.14.4" in the heading and "Starting in 0.14.4" in the body added no value. Keep the #3790 provenance link and the "no longer propagates" framing; the machine-readable version gate stays in preset.yml. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e * docs(upgrade): clarify non-breaking nuance and presets direction Note that the /constitution scope change is only noticeable if you relied on the old edit-in-place behavior, and add the forward-looking framing: presets and extensions — not in-place file edits — are how Spec Kit now governs, versions, and audits shared assets across repositories. Assisted-by: GitHub Copilot (model: Claude Opus 4.8, supervised) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: afa7c1d2-147b-4f62-a6fc-a2cc824cfa3e
Presets
Presets are stackable, priority-ordered collections of template and command overrides for Spec Kit. They let you customize both the artifacts produced by the Spec-Driven Development workflow (specs, plans, tasks, checklists, constitutions) and the commands that guide the LLM in creating them — without forking or modifying core files.
How It Works
When Spec Kit needs a template (e.g. spec-template), it walks a resolution stack:
.specify/templates/overrides/— project-local one-off overrides.specify/presets/<preset-id>/templates/— installed presets (sorted by priority).specify/extensions/<ext-id>/templates/— extension-provided templates.specify/templates/— core templates shipped with Spec Kit
If no preset is installed, core templates are used — exactly the same behavior as before presets existed.
Template resolution happens at runtime — although preset files are copied into .specify/presets/<id>/ during installation, Spec Kit walks the resolution stack on every template lookup rather than merging templates into a single location.
For detailed resolution and command registration flows, see ARCHITECTURE.md.
Command Overrides
Presets can also override the commands that guide the SDD workflow. Templates define what gets produced (specs, plans, constitutions); commands define how the LLM produces them (the step-by-step instructions).
Unlike templates, command overrides are applied at install time. When a preset includes type: "command" entries, the commands are registered into all detected agent directories (.claude/commands/, .gemini/commands/, etc.) in the correct format (Markdown or TOML with appropriate argument placeholders). When the preset is removed, the registered commands are cleaned up.
Quick Start
# Search available presets
specify preset search
# Install a preset from the catalog
specify preset add healthcare-compliance
# Install from a local directory (for development)
specify preset add --dev ./my-preset
# Install with a specific priority (lower = higher precedence)
specify preset add healthcare-compliance --priority 5
# List installed presets
specify preset list
# See which template a name resolves to
specify preset resolve spec-template
# Get detailed info about a preset
specify preset info healthcare-compliance
# Remove a preset
specify preset remove healthcare-compliance
Stacking Presets
Multiple presets can be installed simultaneously. The --priority flag controls which one wins when two presets provide the same template (lower number = higher precedence):
specify preset add enterprise-safe --priority 10 # base layer
specify preset add healthcare-compliance --priority 5 # overrides enterprise-safe
specify preset add pm-workflow --priority 1 # overrides everything
Presets override by default, they don't merge. If two presets both provide spec-template with the default replace strategy, the one with the lowest priority number wins entirely. However, presets can use composition strategies to augment rather than replace content.
Composition Strategies
Presets can declare a strategy per template to control how content is combined. The name field identifies which template to compose with in the priority stack, while file points to the actual content file (which can differ from the convention path templates/<name>.md):
provides:
templates:
- type: "template"
name: "spec-template"
file: "templates/spec-addendum.md"
strategy: "append" # adds content after the core template
| Strategy | Description |
|---|---|
replace (default) |
Fully replaces the lower-priority template |
prepend |
Places content before the resolved lower-priority template, separated by a blank line |
append |
Places content after the resolved lower-priority template, separated by a blank line |
wrap |
Content contains {CORE_TEMPLATE} placeholder (or $CORE_SCRIPT for scripts) replaced with the lower-priority content |
Supported combinations:
| Type | replace |
prepend |
append |
wrap |
|---|---|---|---|---|
| template | ✓ (default) | ✓ | ✓ | ✓ |
| command | ✓ (default) | ✓ | ✓ | ✓ |
| script | ✓ (default) | — | — | ✓ |
Multiple composing presets chain recursively. For example, a security preset with prepend and a compliance preset with append will produce: security header + core content + compliance footer.
Catalog Management
Presets are discovered through catalogs. By default, Spec Kit uses the official and community catalogs:
Note
Community presets are independently created and maintained by their respective authors. Maintainers only verify that catalog entries are complete and correctly formatted — they do not review, audit, endorse, or support the preset code itself. Review preset source code before installation and use at your own discretion.
# List active catalogs
specify preset catalog list
# Add a custom catalog
specify preset catalog add https://example.com/catalog.json --name my-org --install-allowed
# Remove a catalog
specify preset catalog remove my-org
Creating a Preset
See scaffold/ for a scaffold you can copy to create your own preset.
- Copy
scaffold/to a new directory - Edit
preset.ymlwith your preset's metadata - Add or replace templates in
templates/ - Test locally with
specify preset add --dev . - Verify with
specify preset resolve spec-template
Environment Variables
| Variable | Description | Default |
|---|---|---|
SPECKIT_PRESET_CATALOG_URL |
Override the full catalog stack with a single URL (replaces all defaults) | Built-in default stack |
GH_TOKEN / GITHUB_TOKEN |
GitHub token for authenticated requests to GitHub-hosted URLs (raw.githubusercontent.com, github.com, api.github.com, codeload.github.com). Required when your catalog JSON or preset ZIPs are hosted in a private GitHub repository. |
None |
Example: Using a private GitHub-hosted catalog
# Authenticate with a token (gh CLI, PAT, or GITHUB_TOKEN in CI)
export GITHUB_TOKEN=$(gh auth token)
# Search a private catalog added via `specify preset catalog add`
specify preset search my-template
# Install from a private catalog
specify preset add my-template
The token is attached automatically to requests targeting GitHub domains. Non-GitHub catalog URLs are always fetched without credentials.
Configuration Files
| File | Scope | Description |
|---|---|---|
.specify/preset-catalogs.yml |
Project | Custom catalog stack for this project |
~/.specify/preset-catalogs.yml |
User | Custom catalog stack for all projects |
Future Considerations
The following enhancements are under consideration for future releases:
- Structural merge strategies — Parsing Markdown sections for per-section granularity (e.g., "replace only ## Security").
- Conflict detection —
specify preset lint/specify preset doctorfor detecting composition conflicts.