diff --git a/.github/ISSUE_TEMPLATE/preset_submission.yml b/.github/ISSUE_TEMPLATE/preset_submission.yml index a5c3d02e06..331b87ebce 100644 --- a/.github/ISSUE_TEMPLATE/preset_submission.yml +++ b/.github/ISSUE_TEMPLATE/preset_submission.yml @@ -9,7 +9,7 @@ body: Thanks for contributing a preset! This template helps you submit your preset to the community catalog. **Before submitting:** - - Review the [Preset Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md) + - Review the [Preset Publishing Guide](https://github.github.io/spec-kit/presets/publishing.html) - Ensure your preset has a valid `preset.yml` manifest - Create a GitHub release with a version tag (e.g., v1.0.0) - Test installation from the release archive: `specify preset add --from ` diff --git a/README.md b/README.md index 1f2983081c..5dc14f59e5 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ Spec Kit combines ready-to-use processes with composable mechanisms: | Connect a process to an external tool or service | [Extension](https://github.github.io/spec-kit/extensions/overview.html) | | React to coding-agent lifecycle events | [Extension runtime event](https://github.github.io/spec-kit/extensions/api.html#extension-runtime-events) | | Run extension commands before or after Spec Kit commands | [Extension hook](https://github.github.io/spec-kit/extensions/api.html#hook-configuration) | -| Adapt templates, commands, terminology, or methodology | [Preset](https://github.github.io/spec-kit/reference/presets.html) | -| Enforce organizational or regulatory standards | [Preset](https://github.github.io/spec-kit/reference/presets.html) | +| Adapt templates, commands, terminology, or methodology | [Preset](https://github.github.io/spec-kit/presets/overview.html) | +| Enforce organizational or regulatory standards | [Preset](https://github.github.io/spec-kit/presets/overview.html) | | Override a template for one project | [Project-local override](https://github.github.io/spec-kit/guides/customization.html#project-local-overrides-and-resolution) | | Automate prompts, commands, gates, and shell tasks | [Workflow](https://github.github.io/spec-kit/reference/workflows.html) | | Modify an installed workflow without forking it | [Workflow overlay](https://github.github.io/spec-kit/reference/workflows.html#workflow-overlays) | diff --git a/docs/README.md b/docs/README.md index b6250153d2..07f06135b9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,6 +39,12 @@ To build the documentation locally: - `extensions/developing.md` - Extension authoring guide - `extensions/api.md` - Extension manifest, API, hook, and runtime event contracts - `extensions/publishing.md` - Extension publishing and catalog submission guide +- `presets/overview.md` - Preset user guide +- `presets/cli.md` - Preset management CLI reference +- `presets/developing.md` - Preset authoring and local testing guide +- `presets/api.md` - Manifest, composition, and lifecycle reference +- `presets/catalogs.md` - Preset catalog configuration, schemas, and trust +- `presets/publishing.md` - Preset publishing and catalog submission guide - `community/extensions.md` - Community extension listing - `integrations/index.md` - Integration directory and shared setup guidance - `integrations/cli.md` - Shared integration management CLI reference diff --git a/docs/community/overview.md b/docs/community/overview.md index e098c6f974..f46a6ca2e0 100644 --- a/docs/community/overview.md +++ b/docs/community/overview.md @@ -51,7 +51,7 @@ Community projects that extend, visualize, or build on Spec Kit — including VS To publish your own work, follow the [Extension Publishing Guide](../extensions/publishing.md), -the [Presets Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md), +the [Presets Publishing Guide](../presets/publishing.md), the [Community Bundles guide](bundles.md), or the [Community Workflow Step Types guide](workflow-steps.md). For help choosing a component type, see [Customize Spec Kit](../guides/customization.md). diff --git a/docs/community/presets.md b/docs/community/presets.md index 14ed5d1fde..271f4eee82 100644 --- a/docs/community/presets.md +++ b/docs/community/presets.md @@ -50,4 +50,4 @@ The following community-contributed presets customize how Spec Kit behaves — o | VS Code Ask Questions | Enhances the clarify command to use `vscode/askQuestions` for batched interactive questioning. | 1 command | — | [spec-kit-presets](https://github.com/fdcastel/spec-kit-presets) | | Workflow Preset | Behavior-first specification, design artifacts, and agent-native handoff orchestration — adds requirement-phase behavior drafts, formal BDD/UIF/behavior contracts, optional design artifacts, and scoped implementation handoffs with Core Agent, Vertical Planner Agent, and Worker Agent modes | 22 templates, 8 commands | — | [spec-kit-workflow-preset](https://github.com/bigsmartben/spec-kit-workflow-preset) | -To build and publish your own preset, see the [Presets Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md). +To build and publish your own preset, see the [Presets Publishing Guide](../presets/publishing.md). diff --git a/docs/docfx.json b/docs/docfx.json index 4adc745b30..1992ca15d4 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -10,6 +10,7 @@ "extensions/*.md", "guides/*.md", "integrations/*.md", + "presets/*.md", "reference/*.md", "install/*.md" ] diff --git a/docs/guides/customization.md b/docs/guides/customization.md index 3b049ad84d..cef79bb22d 100644 --- a/docs/guides/customization.md +++ b/docs/guides/customization.md @@ -69,8 +69,8 @@ illustrates how extensively the terminology can change. Multiple presets can be stacked with priorities. See [community presets](../community/presets.md) for examples and the -[preset reference](../reference/presets.md) for installation, composition -strategies, and precedence. +[preset guide](../presets/overview.md) for stacking and composition, and the +[CLI reference](../presets/cli.md) for installation and management. ## Project-local overrides and resolution @@ -90,7 +90,7 @@ stack every time they invoke a command. Removing an overriding component restores the surviving command layer through reconciliation. With no customizations, the core defaults apply. The -[file resolution reference](../reference/presets.md#file-resolution) is the +[file resolution reference](../presets/api.md#file-resolution) is the authoritative guide to paths, priorities, and prepend/append/wrap composition. ## Bundles: role-based setups diff --git a/docs/index.md b/docs/index.md index 36a8269f20..ddf3f28444 100644 --- a/docs/index.md +++ b/docs/index.md @@ -76,7 +76,7 @@ Including entirely different processes: - **MAQA** — multi-agent orchestration with quality assurance gates - **Fiction Book Writing** — novels and long-form fiction, from story bible to submission -Presets →   +Presets →   Extensions →   Workflows →   Bundles → diff --git a/docs/integrations/index.md b/docs/integrations/index.md index a457670826..198e119e94 100644 --- a/docs/integrations/index.md +++ b/docs/integrations/index.md @@ -63,7 +63,7 @@ specify integration switch none > [!IMPORTANT] > Do not manually edit Spec Kit-generated agent commands or skills. Maintain -> customizations in reviewed [presets](../reference/presets.md) or +> customizations in reviewed [presets](../presets/overview.md) or > [project-local overrides](../guides/customization.md#project-local-overrides-and-resolution). > Before committing, use > [`specify integration status`](cli.md#report-integration-status) to verify diff --git a/docs/presets/api.md b/docs/presets/api.md new file mode 100644 index 0000000000..6264472741 --- /dev/null +++ b/docs/presets/api.md @@ -0,0 +1,243 @@ +# Preset API reference + +This reference defines the preset manifest, composition and delivery rules, +and installed state. The CLI reference documents terminal commands; the +developing guide walks through creating a package. + +## Manifest + +A preset has a UTF-8 `preset.yml` whose root is a YAML mapping. + +| Field | Required | Contract | +| --- | --- | --- | +| `schema_version` | Yes | String `"1.0"` | +| `preset` | Yes | Metadata mapping | +| `preset.id` | Yes | String matching `[a-z0-9-]+` | +| `preset.name` | Yes | Human-readable string | +| `preset.version` | Yes | Quoted string accepted by Python `packaging.version.Version` | +| `preset.description` | Yes | Description string | +| `preset.author` | No | Author metadata | +| `preset.repository` | No | Repository URL metadata | +| `preset.license` | No | License metadata | +| `requires` | Yes | Requirements mapping | +| `requires.speckit_version` | Yes | Non-empty string; checked as a PEP 440 specifier during installation | +| `requires.extensions` | No | List of extension IDs or dependency mappings | +| `provides` | Yes | Contribution mapping | +| `provides.templates` | Yes | Non-empty list of contribution mappings, including commands and scripts | +| `tags` | No | Discovery tags; use a list of lowercase strings | + +Use descriptive, letter-leading, lowercase-hyphenated IDs and `X.Y.Z` +versions for published presets. The community submission contract is +stricter than the runtime manifest validator: it requires an ID matching +`[a-z][a-z0-9-]*`, a numeric `X.Y.Z` version, and repository, documentation, +license, and release information. Runtime metadata validation alone is not +proof that a preset meets catalog submission requirements. + +Quote versions and constraints: YAML values such as `version: 1.0` are +numbers, not version strings. Incompatible Spec Kit versions or invalid +Spec Kit specifiers fail installation. + +### Contribution fields + +Every item in `provides.templates` uses this shape: + +```yaml +provides: + templates: + - type: "template" + name: "spec-template" + file: "templates/spec-addendum.md" + description: "Adds team requirements" + strategy: "append" +``` + +| Field | Required | Contract | +| --- | --- | --- | +| `type` | Yes | `template`, `command`, or `script` | +| `name` | Yes | Logical artifact name; not the source filename | +| `file` | Yes | Relative path within the preset, with no parent traversal | +| `description` | No | Contribution description | +| `strategy` | No | Defaults to `replace`; accepted strings are normalized to lowercase | + +Template and script names use lowercase letters, digits, and hyphens. +Command names additionally permit dots; use names such as `speckit.specify` +or `speckit.myext.report`. Duplicate `(name, type)` pairs are rejected, +although different types can share a name. + +The manifest's `file` is authoritative when an artifact is declared. A +missing or non-file declared path does not fall back to a different +conventional file in that same preset. Keep all declared files present: +manifest structural validation is not a complete package-content check. +Legacy lookup can use conventional paths when a manifest is absent or does +not declare the requested name. + +### Extension dependencies + +```yaml +requires: + speckit_version: ">=0.9.0" + extensions: + - "companion-extension" + - id: "other-extension" + version: ">=1.2.0,<2" + required: false +``` + +A bare ID means required with no version constraint. Mapping entries +require an `id` matching `[a-z0-9-]+`; optional `version` must be a non-empty +valid PEP 440 specifier, and `required` must be a boolean, defaulting to +`true`. Exact pins, exclusions, and upper bounds are valid. + +Dependencies are advisory, not automatically installed. After installation, +the CLI warns about required extensions that are missing, have corrupt +registry entries, have missing files, are disabled, or have a comparable +version that does not satisfy the constraint. Missing or disabled +capabilities remain unavailable. A version mismatch does not disable the +extension; it can still run and behave differently than expected. + +Optional dependencies are never warned about. Unparseable or missing +recorded versions are uncomparable, not reported as mismatches. An extension +directory admitted by the resolver without a registry entry is treated as +available, but has no recorded version to compare. An unreadable extension +registry prevents this post-install dependency inspection; no warning is +not proof that dependencies were verified. + +Declare dependencies in the manifest, not just a catalog entry: `--dev` and +`--from` do not consult catalogs. A self-contained namespaced replacement +command is still delivered without its similarly named extension. + +## File resolution + +Each `(name, type)` is evaluated independently: + +```mermaid +flowchart TD + A["Requested artifact"] --> B["Project-local override"] + B --> C["Enabled presets: priority, then ID"] + C --> D["Enabled extensions: priority, then ID"] + D --> E["Core defaults"] +``` + +Within the preset and extension layers, lower priority numbers win, then +alphabetical IDs break ties. Disabled entries are excluded. Safe +unregistered extension directories participate at implicit priority `10`; +disabled, corrupt, or missing registered extensions are not re-admitted as +unregistered contributions. + +| Type | Project-local override | Conventional preset subdirectory | +| --- | --- | --- | +| Template | `.specify/templates/overrides/.md` | `templates/`, with legacy root lookup | +| Command | `.specify/templates/overrides/.md` | `commands/` | +| Script | `.specify/templates/overrides/scripts/.` | `scripts/` | + +Core lookup includes project defaults and packaged core assets, or the +repository assets for editable/source installations. Command lookup can +map `speckit.` to the core `.md` filename. This allows composing +against core commands even when a project does not have a +`.specify/templates/commands/` copy. + +### Composition strategies + +| Type | `replace` | `prepend` | `append` | `wrap` | +| --- | --- | --- | --- | --- | +| Template | Default | Supported | Supported | `{CORE_TEMPLATE}` | +| Command | Default | Supported | Supported | `{CORE_TEMPLATE}` | +| Script | Default | Not supported | Not supported | `$CORE_SCRIPT` | + +A highest-precedence `replace` layer wins entirely. Otherwise, resolution +finds the nearest lower `replace` base and applies only the layers above it, +bottom-up. Prepend and append separate the two contents with a blank line. +The wrapper placeholder is replaced with the effective lower content, +which may already contain other preset customizations. + +Without a `replace` base, composition cannot produce output. Command +registration warns and skips an uncomposable command rather than requiring +an extension based solely on its namespace. A wrapper missing its required +placeholder raises a preset validation error during composition. + +Composed command bodies do not embed every layer's YAML frontmatter. +Resolution uses the highest-priority available frontmatter and inherits +`scripts`, `agent_scripts`, and `argument-hint` from the base when absent. +The internal `strategy` key is removed from composed output. The active +integration then renders the result in its supported command or skill +format. + +## Command and skill lifecycle + +Installation copies preset files into `.specify/presets//` and records +the preset before composing its commands. Initial registration and +post-install reconciliation materialize the effective stack, so install +order does not determine the final winning command. + +For initialized projects, delivery targets the recorded active integration +only. Skills mode emits skills rather than a second command representation +for command-backed integrations; native skill integrations use their +native format. The generic integration does not register preset overrides. +Switching with `specify integration use ` or `switch ` rescaffolds +enabled presets for the newly active integration. + +Legacy projects with no `init-options.json` retain detection-based command +registration. An existing but corrupt or malformed options file does not +trigger that all-agent fallback. + +Removal cleans up recorded outputs and reconciles surviving preset, +extension, override, or core contributions. It can restore affected command +or skill outputs in previously active integration directories recorded by +the removed preset as well as the current integration. Enable, disable, and +priority changes update resolution state but do not themselves rescaffold +already delivered commands or skills. + +The constitution lifecycle is distinct from agent command delivery. By +default the constitution is resolved by the constitution command, not +rewritten on every stack change. With `constitution-sync` enabled, guarded +reconciliation uses generated-content provenance to avoid overwriting an +authored constitution. + +## Installed state + +| Location | Role | +| --- | --- | +| `.specify/presets//preset.yml` | Installed manifest | +| `.specify/presets//` | Copied package files | +| `.specify/presets/.registry` | JSON registry with `schema_version: "1.0"` and a `presets` mapping | +| `.specify/presets/.cache/` | Catalog cache and download working files | +| `.specify/memory/.constitution-template.json` | Generated constitution provenance when materialized | + +Registry metadata records the version, manifest hash, enabled state, +priority, installation timestamp, source, and registered command/skill +outputs. Modern output tracking maps integration keys to lists of names; +legacy skill tracking can be a flat list. Treat this as CLI-managed state, +not the package manifest or the stable JSON inspection API. + +Catalog installs record `{"kind":"catalog","catalog":""}` provenance. +Local directories, direct URLs, and locally bundled installs are recorded +as local rather than as a reusable download URL. Registry updates preserve +the existing `installed_at`; remove-then-add replacement creates a new one. + +## Implementation map + +The Python implementation is the +[`src/specify_cli/presets/` package](https://github.com/github/spec-kit/tree/main/src/specify_cli/presets): +`_manifest.py` validates manifests; `_registry.py` tracks installations; +`_manager.py`, `_manager_commands.py`, and `_manager_skills.py` own lifecycle +and output reconciliation; `_resolver.py` resolves and composes content; +`_catalog.py` and `_catalog_versions.py` handle discovery and releases. +`command_*.py` modules and `catalog/command_*.py` expose the CLI. + +Shared command rendering lives in +[`agents.py`](https://github.com/github/spec-kit/blob/main/src/specify_cli/agents.py) +and the integration packages. Bash `resolve_template` / +`resolve_template_content` and PowerShell `Resolve-Template` / +`Resolve-TemplateContent` in the respective `common` scripts expose template +resolution to shell consumers. Agent command and skill materialization is +handled in Python, not independently by each agent. + +## See also + +- [Preset overview](overview.md) +- [CLI reference and JSON output](cli.md) +- [Developing presets](developing.md) +- [Catalog schemas and configuration](catalogs.md) +- [Publishing presets](publishing.md) +- [Artifact inventory and composition stacks](../reference/artifacts.md) +- [Integration management](../integrations/cli.md) diff --git a/docs/presets/catalogs.md b/docs/presets/catalogs.md new file mode 100644 index 0000000000..02093a3e86 --- /dev/null +++ b/docs/presets/catalogs.md @@ -0,0 +1,226 @@ +# Preset catalogs + +Catalogs discover presets and select releases for ID-based installation. +Their priorities order catalog sources, independently of the installed +preset priorities that determine artifact resolution. + +## Discovery and trust + +The built-in stack contains: + +| Name | Source | Default permission | +| --- | --- | --- | +| `default` | [First-party preset catalog](https://github.com/github/spec-kit/blob/main/presets/catalog.json) | Installation allowed | +| `community` | [Community preset catalog](https://github.com/github/spec-kit/blob/main/presets/catalog.community.json) | Discovery only | + +Community presets are independently maintained. Maintainers check catalog +entries for completeness and format, not the safety or quality of the +preset code. They do not review, audit, endorse, or support that code. +Users must vet a preset's source before installation and use. + +> [!IMPORTANT] +> A project's `.specify/preset-catalogs.yml` can point `add` and `search` at a +> catalog you did not choose. Run `specify preset catalog list` in unfamiliar +> projects and inspect install-allowed sources. Project configuration and +> `install_allowed: true` are not evidence of code review. Only permit +> installation from catalogs you own or have vetted; leave unfamiliar and +> community sources discovery-only. + +After vetting a community release, an explicit `specify preset add --from +` installs that archive without catalog lookup. This is a +source choice, not a bypass that makes unreviewed content safe. + +## Catalog configuration + +The first usable configuration level supplies the whole stack; project and +user entries do not automatically augment the defaults: + +| Order | Source | +| --- | --- | +| First | `SPECKIT_PRESET_CATALOG_URL` environment variable | +| Next | Project `.specify/preset-catalogs.yml` | +| Next | User `~/.specify/preset-catalogs.yml` | +| Last | Built-in `default` and `community` catalogs | + +The environment variable selects one catalog named `custom` with +installation allowed. Use it only with a vetted source. A config file with +no valid catalog entries falls through to the next level; malformed YAML +or invalid configured URLs/priorities raise validation errors rather than +silently selecting another source. + +Example project configuration: + +```yaml +catalogs: + - name: "my-org-presets" + url: "https://catalog.example.com/presets.json" + priority: 5 + install_allowed: true + description: "Our vetted presets" +``` + +| Entry field | Meaning | +| --- | --- | +| `url` | HTTPS catalog URL; loopback HTTP is allowed for local development | +| `name` | Source name displayed by the CLI and used for provenance | +| `priority` | Lower numbers are checked first | +| `install_allowed` | Whether ID-based installation is permitted; default `false` | +| `description` | Optional source description | + +Use the CLI to manage project entries: + +```bash +specify preset catalog list +specify preset catalog add https://catalog.example.com/presets.json \ + --name my-org-presets --priority 5 --install-allowed +specify preset catalog remove my-org-presets +``` + +Only use `--install-allowed` after vetting the source. Omitting it adds a +discovery-only catalog. Adding the first project entry replaces the implicit +built-in stack; explicitly include other sources if you still need them. +The user-level file is configured separately, not by `catalog add`. + +## Entry schema + +Catalog JSON has a `schema_version` field and a `presets` object keyed by +preset ID. The following illustrates a downloadable current release for a +private catalog; replace the example URLs and digest before use: + +```json +{ + "schema_version": "1.0", + "updated_at": "2026-11-03T00:00:00Z", + "presets": { + "team-traceability": { + "id": "team-traceability", + "name": "Team Traceability", + "description": "Adds team traceability requirements to specifications", + "author": "Example Team", + "version": "2.0.0", + "download_url": "https://github.com/example/team-traceability/archive/refs/tags/v2.0.0.zip", + "sha256": "<64 hexadecimal digits for this archive>", + "repository": "https://github.com/example/team-traceability", + "documentation": "https://github.com/example/team-traceability/blob/main/README.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.9.0" + }, + "provides": { + "templates": 1, + "commands": 0, + "scripts": 0 + }, + "tags": ["traceability", "governance"], + "created_at": "2026-11-03", + "updated_at": "2026-11-03" + } + } +} +``` + +Catalog `provides` holds contribution counts, unlike the manifest's +`provides.templates` list. Keep metadata consistent with the published +manifest. `bundled: true` can describe a first-party preset shipped inside +Spec Kit; such an entry may have no download URL and requires the matching +packaged files rather than a network download. + +Single-version legacy entries remain valid. Current releases may omit +`sha256`; when present, the digest is checked before installation. +Community submission automation computes and records the downloaded +archive's digest even when the submitter did not provide one. + +## Historical releases + +To advertise older releases, add a `releases` mapping keyed by version: + +```json +{ + "version": "2.0.0", + "download_url": "https://example.com/team-traceability-2.0.0.zip", + "sha256": "<64 hexadecimal digits for the current archive>", + "releases": { + "1.5.0": { + "download_url": "https://example.com/team-traceability-1.5.0.zip", + "sha256": "<64 hexadecimal digits for the older archive>", + "requires": {"speckit_version": ">=0.8.0"}, + "provides": {"templates": 1, "commands": 0, "scripts": 0} + } + } +} +``` + +This is the release-related portion of one entry, not a complete catalog. +Each historical record needs its own HTTPS archive URL (or loopback HTTP +for development) and a 64-digit SHA-256 digest. Digests may have a +case-insensitive `sha256:` prefix and surrounding whitespace; other +algorithm prefixes are rejected. + +Optional historical `requires` and `provides` describe that release; they +do not inherit the current release's values when absent. Shared metadata +such as name, description, and catalog permissions is inherited. +Historical `requires.extensions` uses the manifest's string-or-mapping +dependency format. Do not put `id`, `version`, nested `releases`, or internal +`_catalog_name` / `_install_allowed` fields inside a historical record. + +Version keys must be distinct, including PEP 440-equivalent spellings, and +cannot repeat the current version. Duplicate JSON keys are rejected before +parsing can discard a release record. + +```bash +specify preset info team-traceability --versions +specify preset add team-traceability --version 1.5.0 +``` + +Available versions list the current release first, then historical versions +in descending order. Exact release selection checks the downloaded +manifest's ID and version before modifying installed presets. + +The community catalog remains discovery-only and need not publish release +histories. Bundle pin resolution is a separate capability; adding preset +release records alone does not make bundle pins installable. + +## Lookup and failure behavior + +Catalogs are checked in ascending priority order. The highest-precedence +entry for an ID supplies both its release metadata and install permission. +A lower-priority source cannot provide a missing historical version or +override a discovery-only decision. + +For exact ID lookup, malformed or oversized catalogs encountered before a +winning entry fail resolution. A malformed lower-priority source cannot +block an already found higher-priority entry. A non-object entry fails an +exact lookup for its own ID, but all-catalog searches skip that entry and +retain other valid ones. + +Searches across all sources still fail on malformed catalogs. Historical +release validation applies to winning entries; invalid history from a +shadowed entry does not block a valid higher-priority replacement. +Unreachable sources can be skipped when another source is readable. If +every source fails, lookup, including `info --versions`, reports the fetch +error rather than claiming no versions exist. + +## Cache and private sources + +Catalogs are cached for one hour in `.specify/presets/.cache/`. The default +catalog retains legacy `catalog.json` and `catalog-metadata.json` filenames; +other sources use URL-hashed cache filenames. Cache payloads undergo the +same shape validation as network responses; unreadable or invalid cached +content triggers a fetch. + +Private catalog and archive requests use the shared opt-in authentication +configuration in `~/.specify/auth.json`. A token environment variable by +itself does not enable authentication. Configure only the hosts authorized +to receive credentials; the authentication reference covers GitHub CLI, +token, enterprise, and other supported providers. Do not put credentials in +catalog JSON or source URLs. + +## See also + +- [Preset overview](overview.md) +- [Catalog CLI commands](cli.md#catalog-management) +- [Manifest API](api.md) +- [Publishing and community submission](publishing.md) +- [Cross-component catalog guidance](../reference/catalogs.md) +- [Catalog and download authentication](../reference/authentication.md) +- [Community presets](../community/presets.md) diff --git a/docs/presets/cli.md b/docs/presets/cli.md new file mode 100644 index 0000000000..fd0b97a3fc --- /dev/null +++ b/docs/presets/cli.md @@ -0,0 +1,266 @@ +# Preset CLI reference + +All `specify preset` commands require a project initialized with `specify init`. +Run inside that project, or set `SPECIFY_INIT_DIR` to the project root. +Use `specify preset --help` or a subcommand's `--help` for usage. + +## Search available presets + +```bash +specify preset search [query] +``` + +| Option | Description | +| --- | --- | +| `--tag ` | Filter by tag | +| `--author ` | Filter by author | + +Searches the active catalogs. Without a query, lists all available presets. +Discovery-only results are visible but cannot be installed by ID. + +## Install a preset + +```bash +specify preset add +specify preset add --version +specify preset add --dev +specify preset add --from +``` + +| Option | Description | +| --- | --- | +| `--dev ` | Copy a local source directory | +| `--from ` | Download a `.zip`, `.tar.gz`, or `.tgz` archive | +| `--version ` | Select an exact release from the winning catalog; ID installs only | +| `--priority ` | Resolution priority, a positive integer; default `10`, lower wins | + +Choose one source form. Without `--version`, ID installation first uses a +locally bundled preset when available, otherwise the advertised current +catalog release. Direct URL installs do not consult catalogs. An already +installed preset must be removed or updated before reinstalling; `add` has no +`--force` option. + +`--version` requires a preset ID and cannot be combined with `--from` or +`--dev`. A requested release absent from the winning catalog is an error; +lower-priority catalogs cannot supply it. Discovery-only catalogs cannot +install any release. Version-specific catalog installs verify the archive's +`preset.yml` ID and version before modifying installed presets. Historical +releases require a SHA-256 digest, verified on download; legacy current +releases may omit it. A bundled release without a download URL can only be +selected when that matching ID and version are present in the installed +Spec Kit package. + +The source is copied into `.specify/presets//`, respecting +[`.presetignore`](developing.md#exclude-development-files-with-presetignore). +Preset command contributions are registered for the active integration in +its selected command or skill format. The generic integration does not +register preset overrides. Required extension dependencies produce warnings +when unmet, not installation failures or automatic dependency installation. + +Download URLs must use HTTPS with a hostname; HTTP is allowed only for +`localhost`, `127.0.0.1`, or `::1`. Archives must contain `preset.yml` at their +root or inside one top-level directory. + +## Update a preset + +```bash +specify preset update [--from ] [--dev ] [--priority ] +``` + +Replaces an installed preset by running the normal `remove` operation, then +the normal `add` operation. Without an explicit source, add uses its usual +bundled and catalog lookup. This is not a version comparison or an in-place +patch. `update` does not accept `--version`. + +> [!WARNING] +> Update is destructive. If removal succeeds and replacement installation +> fails, the previous preset has already been removed. There is no source +> preflight, staging, rollback, automatic repair, or recovery transaction. + +Before removing anything, the command rejects combined `--from` and `--dev`, +empty source arguments, priorities below `1`, and an ID that is not installed. +Beyond those checks, it does not inspect the replacement source in advance. +With `--from` or `--dev`, the replacement manifest's ID is not checked against +the requested ID before removal, so a different preset can be installed +instead. + +If add fails, the command reports a copy-pastable `specify preset add` retry +command containing the replacement source and priority. On Windows, that +command is formatted for PowerShell. + +A successful update re-enables the preset, recreates `installed_at`, and +removes local modifications within the installed preset directory. The +replacement priority defaults to `10`; pass `--priority` to choose another +value. An explicit `--from` or `--dev` is an intentional source change rather +than reuse of recorded catalog provenance. + +If constitution synchronization is enabled, both normal remove and add +reconciliation passes run. A failed replacement can leave the generated +constitution reconciled against the stack without the removed preset. The +generated-file guard still protects a hand-edited constitution. There is no +update-specific optimization to suppress rewrites when the final content is +unchanged. + +## Remove a preset + +```bash +specify preset remove +``` + +Deletes the installed preset and its registry entry, cleans up recorded +command and skill outputs, and reconciles affected names against the +surviving stack. Removal can also restore outputs in previously active +integration directories recorded by that preset; it is not limited to +deleting files in the current integration. + +## List installed presets + +```bash +specify preset list +specify preset list --json +``` + +Lists installed presets with versions, descriptions, contribution counts, +priorities, and enabled status. Output includes disabled presets and is +ordered by precedence: lowest priority number first, then preset ID +alphabetically. + +`--json` writes exactly one JSON array to stdout and exits `0` on success. +Every item has these keys: + +| Key | Value | +| --- | --- | +| `id`, `name`, `description`, `version` | Preset identity and metadata | +| `author` | Author or `null` when absent | +| `priority` | Resolution priority | +| `enabled` | Whether the preset participates in resolution | +| `source` | `{"kind":"local"}` or `{"kind":"catalog","catalog":""}` | +| `provides` | Counts named `commands`, `templates`, and `scripts` | + +Local, legacy, and malformed provenance is reported as `{"kind":"local"}`. +The `source` object describes where the preset was installed from, not a +contribution's position in the resolution stack. + +Runtime failures after option parsing write exactly one `{"error":"..."}` +object to stderr and exit `1`, without success output. Usage errors with +the raw `--json` token present also use that JSON error shape on stderr, +preserving their usage exit code, normally `2`. Without `--json`, including +for help, human-readable behavior is unchanged. + +## Preset info + +```bash +specify preset info +specify preset info --versions +specify preset info --json +``` + +Human-readable output describes an installed preset first, otherwise an +available catalog entry, including metadata, tags, and contributions where +available. + +`--versions` consults the catalog, not the installed preset. It lists the +advertised current version first, then historical versions in descending +version order, even for discovery-only entries. Listing versions does not +make them installable. + +`--json` describes one installed preset, matched by ID, and writes one JSON +object to stdout. It has the same `id`, `name`, `description`, `version`, +`author`, `priority`, `enabled`, and `source` keys as `list --json`. +Instead of `provides` counts, it has `commands`, `templates`, and `scripts` +arrays. Each array preserves manifest declaration order and contains: + +| Key | Value | +| --- | --- | +| `name` | Logical contribution name | +| `description` | Description, or `""` when absent or empty | +| `source` | `{"layer":"preset","presetId":""}` identifying the contributing preset | +| `sourcePath` | Manifest `file` path, relative to the installed preset | +| `strategy` | `replace`, `prepend`, `append`, or `wrap`; `replace` if omitted | + +`--json` cannot be combined with `--versions` (usage error, exit `2`). +A preset that is not installed, including one only in a catalog, or a +missing project produces one JSON error object on stderr and exits `1`. +Usage errors preserve their usage exit code as with `list --json`. + +## Resolve a file + +```bash +specify preset resolve spec-template +specify preset resolve speckit.specify +``` + +Accepts an extensionless template name or a dot-separated command name. +Names use lowercase letters, digits, and hyphens; command segments must be +non-empty. This command does not offer a script-type selector. + +Shows the highest-priority layer's path and source. If output is composed, +it also shows the contributing composition chain, starting at its effective +base. The displayed path is not a file containing the final composed output. +Invalid composition produces a warning; a missing name is reported as not +found. For all artifact kinds and hidden layers, use the separate +[artifact reference](../reference/artifacts.md). + +## Enable or disable a preset + +```bash +specify preset enable +specify preset disable +``` + +Changes whether an installed preset participates in subsequent resolution. +Repeating the current state succeeds without changing it. + +Previously registered commands and skills remain in place. Disabling is +useful for comparing template and script behavior, but it does not withdraw +already delivered overrides from an agent. Use removal when those outputs +need to stop taking effect. Constitution reconciliation runs when +`constitution-sync` is enabled. + +## Set preset priority + +```bash +specify preset set-priority +``` + +Changes an installed preset's resolution priority. The value must be a +positive integer; lower numbers take precedence, with alphabetical ID +ordering for ties. This updates the registry and opted-in constitution +reconciliation; it does not itself rescaffold command and skill outputs. + +## Catalog management + +```bash +specify preset catalog list +specify preset catalog add --name +specify preset catalog remove +``` + +`list` shows active sources, priorities, and installation permissions. +`add` writes the project's `.specify/preset-catalogs.yml`; `remove` removes +a named entry from that project configuration. + +| `catalog add` option | Description | +| --- | --- | +| `--name ` | Required catalog name | +| `--priority ` | Default `10`; lower numbers are checked first | +| `--install-allowed / --no-install-allowed` | Permit ID installs; default discovery-only | +| `--description ` | Optional description | + +Re-adding the same named catalog with identical settings succeeds without +rewriting configuration. Different settings for the same name are rejected; +remove the entry first or choose another name. + +> [!IMPORTANT] +> A project's `.specify/preset-catalogs.yml` can select an install-allowed +> catalog you did not choose. Inspect `catalog list` in unfamiliar projects. +> Only enable installation for catalogs you own or have vetted; never treat +> `install_allowed` as evidence that preset code has been reviewed. + +## See also + +- [Preset overview](overview.md) +- [Developing presets](developing.md) +- [API reference](api.md) +- [Catalog configuration, schemas, and trust](catalogs.md) +- [Publishing presets](publishing.md) diff --git a/docs/presets/developing.md b/docs/presets/developing.md new file mode 100644 index 0000000000..600d49f719 --- /dev/null +++ b/docs/presets/developing.md @@ -0,0 +1,194 @@ +# Developing presets + +A preset packages custom document templates, agent instructions, and scripts +in a directory with a `preset.yml` manifest. Prefer a template contribution +when only the output structure changes; override a command when the process +itself needs different instructions. For a one-off project change, a +project-local override may be simpler than a distributable preset. + +## Start from the scaffold + +Copy the repository's +[preset scaffold](https://github.com/github/spec-kit/tree/main/presets/scaffold) +to a directory you control: + +```bash +cp -r presets/scaffold my-preset +``` + +Edit its ID, name, version, description, required Spec Kit version, and +contributions. Remove unused examples, including example extension command +overrides, rather than shipping them accidentally. + +A typical package contains: + +```text +my-preset/ + preset.yml + README.md + LICENSE + CHANGELOG.md + .presetignore + templates/ + spec-addendum.md + commands/ + speckit.specify.md + scripts/ + my-helper.sh +``` + +Only include directories used by your preset. The manifest's +`provides.templates` list contains contributions of all three types, not +just document templates. The `file` field can point to a non-conventional +path; use `name` to identify the logical artifact being customized. + +## Declare contributions + +For example, append a traceability section to the effective specification +template: + +```yaml +schema_version: "1.0" + +preset: + id: "team-traceability" + name: "Team Traceability" + version: "1.0.0" + description: "Adds team traceability requirements to specifications" + author: "Example Team" + repository: "https://github.com/example/team-traceability" + license: "MIT" + +requires: + speckit_version: ">=0.9.0" + +provides: + templates: + - type: "template" + name: "spec-template" + file: "templates/spec-addendum.md" + description: "Traceability section" + strategy: "append" + +tags: + - "traceability" + - "governance" +``` + +Keep headings clear and placeholders explicit. If a command references a +template section, ensure the effective template actually contains it. +Declare only contributions you need so the preset composes with others. + +For `wrap`, the content file must contain `{CORE_TEMPLATE}` for templates +and commands, or `$CORE_SCRIPT` for scripts. These placeholders stand for the +resolved lower-priority content, not necessarily unmodified core content. +An append, prepend, or wrap contribution needs a lower `replace` base; +a new self-contained command normally uses `replace`. + +Declare extension dependencies in `preset.yml` when the preset relies on +extension capabilities. A namespace alone does not establish a dependency +or suppress registration. See the API reference for warning behavior and +optional/version-constrained dependencies. + +## Exclude development files with `.presetignore` + +Place a UTF-8 `.presetignore`, with or without a byte-order mark, beside +`preset.yml` in the source root: + +```gitignore +.git/ +.idea/ +tests/ +``` + +Filtering applies to copied local directories and extracted archives, +including replacements installed by `preset update`. Without this file, +all source files are copied as before. `.gitignore` is not used for +installation filtering, and there are no implicit development-file +exclusions. + +Patterns use Git-style matching and normalization, as with +`.extensionignore`: + +- Use one pattern per line; blank lines and `#` comments are ignored. +- `*` and `?` do not cross directory boundaries; `**` can cross them. +- A trailing `/` matches directories only. A leading `/`, or a `/` elsewhere + except at the end, anchors a pattern to the source root. Patterns without + such a slash match names at any depth. +- A later `!` pattern re-includes a match. Excluded directories are not + traversed, so a child cannot be re-included while its parent is excluded. +- Whitespace is trimmed and backslashes are normalized to `/`. Use UTF-8 + for non-ASCII names. + +To keep only `docs/api.md` inside `docs/`, exclude the contents rather than +the directory: + +```gitignore +docs/* +!docs/api.md +``` + +Using `docs/`, then `!docs/` and `!docs/api.md`, re-includes all files under +`docs/` unless another rule excludes them. + +Only the source root's `.presetignore` adds rules; nested ignore files are +not evaluated. If a root ignore file exists, files named `.presetignore` at +any depth are excluded even when negated. Without a root ignore file, +nested `.presetignore` files are copied unchanged. + +Manifest and declared asset files are not exempt. Keep `preset.yml` and all +required contribution files included; filtering them out can produce an +incomplete or unusable installation. + +The directory installer validates ignore rules before removing an existing +destination, including forced replacement through the Python manager API. +Invalid UTF-8 and malformed patterns raise a preset validation error. +The CLI's separate `update` command still removes first, then invokes add; +it does not preflight the replacement ignore file. + +## Test locally + +Use an initialized test project with the integration and command/skill mode +your preset supports. From that project: + +```bash +specify preset add --dev /path/to/my-preset --priority 5 +specify preset info team-traceability +specify preset list +specify preset resolve spec-template +specify artifact info template:spec-template --json +``` + +Confirm the contribution is present in generated artifacts, not just in the +installed directory. For command overrides, inspect the active +integration's delivered command or skill and invoke it with that agent. +Test relevant formats and modes rather than assuming every integration uses +the same file layout. + +Test overlapping presets at different priorities and equal priorities, +project-local overrides, removal/restoration, and missing dependencies or +composition bases. If you ship executable scripts, test their intended +behavior and failures; PowerShell scripts must target Windows PowerShell +5.1. Do not expect enable, disable, or priority changes alone to rewrite +already delivered command or skill files. + +After editing the development source, install a fresh copy. `--dev` does not +watch or link it: + +```bash +specify preset remove team-traceability +specify preset add --dev /path/to/my-preset --priority 5 +``` + +The `update --dev` alternative has deliberate remove-then-add semantics and +can leave the preset removed if the new source is invalid. Test archive +installation too before publishing, especially if packaging changes the +directory layout. + +## See also + +- [Preset overview](overview.md) +- [CLI reference](cli.md) +- [Manifest and composition API](api.md) +- [Catalogs](catalogs.md) +- [Publishing presets](publishing.md) diff --git a/docs/presets/overview.md b/docs/presets/overview.md new file mode 100644 index 0000000000..b1a1fb5e29 --- /dev/null +++ b/docs/presets/overview.md @@ -0,0 +1,142 @@ +# Presets + +Presets are stackable, priority-ordered customizations of Spec Kit templates, +commands, and scripts. Use them to enforce organizational standards, adapt a +Spec Kit process to your methodology, or change terminology without forking +core files. Extensions add capabilities; presets change how existing +capabilities work. + +> [!IMPORTANT] +> Vet a third-party preset's source before installing it. Community catalogs +> are discovery channels, not security endorsements. Maintainers check catalog +> entries for completeness and format; they do not review, audit, endorse, or +> support community preset code. + +## Quick start + +Run preset commands inside a project initialized with `specify init`: + +```bash +# Discover presets without installing them +specify preset search +specify preset info lean + +# Install a bundled preset +specify preset add lean + +# Inspect installed presets and template resolution +specify preset list +specify preset resolve spec-template + +# Remove it and restore the surviving layers +specify preset remove lean +``` + +For a preset you have authored or vetted, install a local copy with +`specify preset add --dev ./my-preset`, or a pinned release archive with +`specify preset add --from `. Local installs copy the source; +they are not live links to the development directory. A community search +result does not itself permit installation by ID. + +## How presets take effect + +Templates define what gets produced, such as a specification or plan. +Commands contain the instructions your coding agent follows to produce it. +Scripts provide executable behavior and require the same scrutiny as other +code you install. + +Each logical file name is resolved independently through these layers: + +| Precedence | Layer | +| --- | --- | +| Highest | Project-local overrides in `.specify/templates/overrides/` | +| Next | Enabled presets, ordered by priority, then preset ID | +| Next | Enabled extension contributions, ordered by priority, then extension ID | +| Lowest | Spec Kit core defaults | + +Lower priority numbers take precedence. Preset and extension priorities order +entries within their own layer; an extension cannot outrank the preset layer +by choosing a smaller number. + +Templates and scripts are resolved when needed. Commands are materialized as +command files or skills for the active integration during installation and +reconciliation; agents do not resolve the stack on each invocation. Switching +the default integration rescaffolds enabled presets for that integration. +The generic integration does not register preset command or skill overrides. + +With no preset installed, the remaining project overrides, extension +contributions, and core defaults continue to apply. + +## Stacking and composition + +Install multiple vetted presets with different priorities: + +```bash +specify preset add --dev ./team-base --priority 10 +specify preset add --dev ./compliance --priority 5 +specify preset set-priority compliance 3 +``` + +If both presets provide `spec-template` with the default `replace` strategy, +`compliance` wins entirely. Files provided only by `team-base` still use that +preset. Equal priorities are resolved alphabetically by preset ID. + +Presets can augment lower layers instead of replacing them: + +| Strategy | Effect | +| --- | --- | +| `replace` | Use this layer entirely; ignore lower layers | +| `prepend` | Put this layer before the lower-priority content | +| `append` | Put this layer after the lower-priority content | +| `wrap` | Insert lower-priority content at a placeholder in this layer | + +Templates and commands support all four strategies. Scripts support only +`replace` and `wrap`. Composition needs a lower `replace` base; a wrapper +must contain the appropriate placeholder. The API reference defines the +exact rules. + +## Constitution lifecycle + +Initialization seeds `.specify/memory/constitution.md` once from the resolved +`constitution-template`, preserving an existing constitution. Later +`/speckit.constitution` runs resolve the current composed template and use the +live constitution for project-specific values and amendments. + +By default, installing, removing, enabling, disabling, or reprioritizing +presets does not rewrite the live constitution. The bundled +`constitution-sync` preset opts into guarded install-time materialization and +command-time propagation. While it is enabled, stack changes may refresh an +unchanged generated constitution, but authored or hand-edited constitutions +are protected. Installing the preset can also seed a missing constitution. + +## FAQ + +### How do I see which file is being used? + +Use `specify preset resolve spec-template` for a template or +`specify preset resolve speckit.specify` for a command. Composed output can +have several contributing files rather than one final source path. +Use `specify artifact info --json` for the full artifact stack, +including hidden layers. + +### Is disabling the same as removing? + +No. Disabling excludes the preset from subsequent resolution but leaves +previously registered commands and skills in place. Use removal when you need +those delivered overrides cleaned up and the surviving layers restored. + +### Who supports a preset? + +Contact the preset's author through its repository. Community catalog +inclusion does not transfer maintenance or support responsibility to the +Spec Kit maintainers. + +## See also + +- [CLI reference](cli.md) +- [Developing presets](developing.md) +- [API reference](api.md) +- [Catalogs](catalogs.md) +- [Publishing presets](publishing.md) +- [Community presets](../community/presets.md) +- [Choosing customization building blocks](../guides/customization.md) diff --git a/docs/presets/publishing.md b/docs/presets/publishing.md new file mode 100644 index 0000000000..7d04b5d1ca --- /dev/null +++ b/docs/presets/publishing.md @@ -0,0 +1,183 @@ +# Publishing presets + +Publish a versioned preset archive, test it with Spec Kit, and submit a +Preset Submission issue to make it discoverable in the community catalog. +Use the same issue flow for new entries, version updates, and repairs. +Do not submit a hand-edited catalog pull request. + +Community listing is not code certification. Maintainers check catalog +entries for completeness and format; they do not review, audit, endorse, +or support community preset code. Users must vet third-party presets before +installing them. + +## Prepare the package + +Before submitting, have a publicly accessible repository containing a +working `preset.yml`, a preset usage README, and an open-source `LICENSE`. +Use a descriptive letter-leading lowercase-hyphenated ID and numeric +`X.Y.Z` version, such as `team-traceability` and `1.0.0`. Keep descriptions +concise (under 200 characters) and choose two to five useful lowercase tags. +A changelog is recommended. + +Start from the developing guide and check the API reference for manifest +fields and dependencies. Include all declared contribution files, and +ensure commands refer to sections the effective templates provide. Local +manifest validation is not a security review or a complete publishing +checklist. + +## Test local and release installation + +In an initialized test project: + +```bash +specify preset add --dev /path/to/team-traceability +specify preset info team-traceability +specify preset resolve spec-template +specify preset list +specify preset remove team-traceability +``` + +Test on at least one real project. For command contributions, inspect and +invoke the delivered command or skill with supported active integrations. +Check stacking, composition, and removal/restoration, not just whether +installation exits successfully. + +Create a tag and a GitHub release for the version. For example: + +```bash +git tag v1.0.0 +git push origin v1.0.0 +``` + +Pushing a tag is not by itself creating the GitHub release; create that +release through GitHub or your release tooling. Submission accepts pinned +ZIP URLs belonging to the submitted repository: + +```text +https://github.com///archive/refs/tags/v1.0.0.zip +https://github.com///releases/download/v1.0.0/.zip +``` + +Tags may use `vX.Y.Z`, `X.Y.Z`, or a scope with a matching version suffix, +such as `team-traceability-v1.0.0`. A floating `releases/latest/` URL is not +accepted. The GitHub release must exist for that tag. + +The CLI also supports `.tar.gz` and `.tgz`, but the community submission +contract currently requires a tag-pinned ZIP. For direct CLI installation, +`preset.yml` must be at the archive root or inside one top-level directory. +The submission verifier can locate preset-scoped manifests in monorepos; +that does not make arbitrary nested monorepo archives installable by the +CLI. Publish a preset-specific asset when necessary. + +Test the exact archive URL you will submit: + +```bash +specify preset add --from https://github.com/example/team-traceability/archive/refs/tags/v1.0.0.zip +specify preset resolve spec-template +specify preset remove team-traceability +``` + +## Usage README requirements + +The submission's Documentation URL must point to a readable GitHub-hosted +README explaining how to use this preset, not a pitch for a broader +framework or separate CLI. Accepted URL forms are GitHub `blob` or `raw` +URLs and `raw.githubusercontent.com` URLs. The path must end in +`README.md` (case-insensitive); query strings and fragments are ignored for +fetching. + +In a monorepo, prefer the preset-scoped README, such as +`presets/team-traceability/README.md`, instead of the repository overview. +Keep that README accessible before downloading the release, whether or +not it also ships inside the archive. + +Include what the preset provides, when to use it or not use it, supported +integrations and dependencies, and a valid install command. Prefer: + +```bash +specify preset add --from https://github.com/example/team-traceability/archive/refs/tags/v1.0.0.zip +``` + +The `--from` URL must exactly match the submitted Download URL. A valid +`specify preset add ` or `specify preset add --dev ` command is +also accepted by validation. ID installation still requires an +install-allowed catalog, so a direct pinned archive is clearest for +community users. + +A README with no valid install command fails validation. Stale release +URLs identifiable as belonging to this preset also fail, even if another +valid command is present. Unrelated presets' release examples in monorepos +are distinguished rather than automatically treated as stale. + +## Submit to the community catalog + +Open a +[Preset Submission issue](https://github.com/github/spec-kit/issues/new?template=preset_submission.yml). +Provide the ID, name, version, description, author, repository URL, pinned +Download URL, Documentation URL, license, required Spec Kit version, +required extension IDs, provided templates/commands/scripts, tags, and key +features. Complete the testing and submission checklists. + +Declare required extensions in `preset.yml` too. Catalog metadata alone +cannot convey dependencies for local and direct-archive installs. + +An optional submitted checksum can be supplied by appending a `### SHA-256` +heading to the issue with exactly 64 hexadecimal characters. There is no +dedicated checksum field in the form. If supplied, it must match the fetched +archive; a mismatch is a validation failure, not a value the automation +silently replaces. + +Do not edit `presets/catalog.community.json` or +`docs/community/presets.md` yourself as a substitute for submission. +Automation prepares those changes after validation. + +## What happens after submission + +1. The issue form applies the `triage-must-have` intake verdict. It does not + start catalog validation. +2. During triage, a maintainer separately applies `preset-submission` to + start the validation workflow. Contributors do not need to apply or + request that label. +3. Validation checks submission metadata, repository/license availability, + the linked README and install references, release pinning, archive + availability, optional submitted checksum, and required checklists. + The verifier parses the published manifest without executing archive + content, comparing its ID, version, Spec Kit requirement, and required + extensions to the issue. +4. On success, automation proposes a draft pull request updating the catalog + and community table. It records the actual archive digest, preserves + `created_at` on updates, sorts catalog IDs and display names appropriately, + and verifies the generated files before marking validation passed. +5. A maintainer reviews the generated catalog changes and merges them when + approved. The preset becomes discoverable; the community catalog remains + discovery-only. + +Confirmed submission defects are reported with `validation-failed`. +Permission, network, or tooling blockers are reported as blocked, not as +successful checks or necessarily as defects in the preset. The workflow +reports what could not run so a maintainer can investigate and rerun it. + +These are metadata and artifact-consistency checks, not a review of preset +instructions, template quality, or executable code safety. There is no +community code-approval or support guarantee. + +## Release updates + +Update the manifest version and changelog, publish a new immutable tagged +release, and retest its exact archive. Update README install references for +that release, then submit another Preset Submission issue with the new +version and URL. The same issue flow applies to repairing a broken entry. + +For private catalogs you operate yourself, maintain current and historical +release records according to the catalog reference. Do not assume the +community submission process publishes a release history or makes that +catalog install-allowed. + +## See also + +- [Preset overview](overview.md) +- [Developing presets](developing.md) +- [Manifest API](api.md) +- [Catalog entries and historical releases](catalogs.md) +- [CLI reference](cli.md) +- [Community presets](../community/presets.md) diff --git a/docs/reference/catalogs.md b/docs/reference/catalogs.md index 11106c68d9..4fedb31164 100644 --- a/docs/reference/catalogs.md +++ b/docs/reference/catalogs.md @@ -55,7 +55,7 @@ project: | --- | --- | --- | | Integrations | `specify integration catalog list` | [Integrations](../integrations/cli.md#catalog-management) | | Extensions | `specify extension catalog list` | [Extensions](../extensions/catalogs.md) | -| Presets | `specify preset catalog list` | [Presets](presets.md#catalog-management) | +| Presets | `specify preset catalog list` | [Preset catalogs](../presets/catalogs.md) | | Workflows | `specify workflow catalog list` | [Workflows](workflows.md#catalog-management) | | Workflow steps | `specify workflow step catalog list` | [Workflows](workflows.md#catalog-management) | | Bundles | `specify bundle catalog list` | [Bundles](bundles.md#manage-catalog-sources) | @@ -140,7 +140,7 @@ Use the component-specific publishing guidance when authoring catalog entries: | --- | --- | | Integrations | [Integration catalog contributions](../integrations/contributing.md) | | Extensions | [Extension Publishing Guide](../extensions/publishing.md) | -| Presets | [Preset Publishing Guide](https://github.com/github/spec-kit/blob/main/presets/PUBLISHING.md) | +| Presets | [Preset Publishing Guide](../presets/publishing.md) | | Workflows | [Workflow Publishing Guide](https://github.com/github/spec-kit/blob/main/workflows/PUBLISHING.md) | | Workflow steps | [Community workflow step types](../community/workflow-steps.md) | | Bundles | [Community bundles](../community/bundles.md) | diff --git a/docs/reference/overview.md b/docs/reference/overview.md index 3cf7324595..c8edf2cfbb 100644 --- a/docs/reference/overview.md +++ b/docs/reference/overview.md @@ -42,7 +42,9 @@ Extensions add new capabilities to Spec Kit — domain-specific commands, extern Presets customize how Spec Kit works — overriding command files, template files, and script files without changing any tooling. They let you enforce organizational standards, adapt the workflow to your methodology, or localize the entire experience. Multiple presets can be stacked with priority ordering to layer customizations. -[Presets reference →](presets.md) +[Presets guide →](../presets/overview.md) + +[Preset management reference →](../presets/cli.md) ## Artifacts diff --git a/docs/reference/presets.md b/docs/reference/presets.md deleted file mode 100644 index 9975578ce6..0000000000 --- a/docs/reference/presets.md +++ /dev/null @@ -1,430 +0,0 @@ -# Presets - -Presets customize how Spec Kit works — overriding templates, commands, and terminology without changing any tooling. They let you enforce organizational standards, adapt the workflow to your methodology, or localize the entire experience. Multiple presets can be stacked with priority ordering. - -## Search Available Presets - -```bash -specify preset search [query] -``` - -| Option | Description | -| ---------- | -------------------- | -| `--tag` | Filter by tag | -| `--author` | Filter by author | - -Searches all active catalogs for presets matching the query. Without a query, lists all available presets. - -## Install a Preset - -```bash -specify preset add [] -specify preset add --version -``` - -| Option | Description | -| --------------------- | -------------------------------------------------------------------- | -| `--dev ` | Install from a local directory (for development) | -| `--from ` | Install from a custom URL instead of the catalog | -| `--version ` | Select an exact release from the winning catalog (ID installs only) | -| `--priority ` | Resolution priority (default: 10; lower = higher precedence) | - -Installs a preset from the catalog, a URL, or a local directory. Preset commands -are automatically registered with supported active AI coding agent integrations. -The generic integration currently delivers extension invocations but does not -register preset command or skill overrides. -`--version` cannot be combined with `--from` or `--dev`. Direct URL installs -remain independent of catalog lookup. Without `--version`, installation still -selects the advertised current release (or the locally bundled preset). A -requested release absent from the winning catalog is an error; lower-priority -catalogs cannot supply it. Discovery-only catalogs cannot install any release. -Version-specific catalog installs verify the selected archive's `preset.yml` ID -and version before modifying installed presets. Historical releases require a -SHA-256 digest, which is also verified on download; a legacy current release -may omit the digest. - -> **Note:** All preset commands require a project already initialized with `specify init`. - -### Exclude development files with `.presetignore` - -Place a UTF-8 `.presetignore` (with or without a byte-order mark) beside -`preset.yml` in the preset source root to filter files copied into -`.specify/presets//`. For example: - -```gitignore -# Development-only directories -.git/ -.idea/ -tests/ -``` - -Filtering applies to local directory installs and extracted archives, including -reinstalls and replacements installed by `preset update`. Without -`.presetignore`, all source files are copied as before. **`.gitignore` is not -used for installation filtering**, and there are no implicit exclusions for -development files. - -Patterns follow the same Git-style matching and normalization as -`.extensionignore`: - -- Use one pattern per line; blank lines and `#` comments are ignored. -- `*` and `?` do not cross directory boundaries; `**` can match across directories. -- A trailing `/` matches directories only. A leading `/`, or a `/` within a - pattern other than its trailing slash, anchors the pattern to the source root. - Patterns without such a slash match names at any depth. -- A later `!` pattern re-includes a match. An excluded directory is not traversed, - so a child cannot be re-included while its parent remains excluded. -- Pattern whitespace is trimmed and backslashes are normalized to `/`, matching - the existing extension behavior. Use UTF-8 for non-ASCII names. - -To keep only `docs/api.md` within `docs/`, exclude the directory's contents -instead of the directory itself: - -```gitignore -docs/* -!docs/api.md -``` - -Using `docs/`, then `!docs/` and `!docs/api.md`, would re-include all files under -`docs/`, not just `api.md`, unless other patterns exclude them. - -Only the source root's `.presetignore` is read; nested ignore files do not add -rules. When a root `.presetignore` exists, files named `.presetignore` at any -depth are excluded, even if negated. Otherwise, nested `.presetignore` files -are copied unchanged. -Manifest and declared asset files are not exempt from filtering: keep -`preset.yml` and any templates, commands, or scripts the preset needs included. -Excluding them can leave an incomplete or unusable installation. - -For local directories and extracted archives, the source-directory installer -reads and validates `.presetignore` before removing an existing destination, -including during a forced reinstall. Invalid UTF-8 or malformed patterns raise -a preset validation error. The separate `preset update` command retains its -remove-then-add behavior described below; it does not preflight the replacement -ignore file before removal. - -## Update a Preset - -```bash -specify preset update [--from ] [--dev ] [--priority ] -``` - -Replaces an already-installed preset by running the normal `preset remove` -operation first and then the normal `preset add` operation. `--from`, `--dev`, -and `--priority` are forwarded to `preset add`; `--from` and `--dev` cannot be -combined. Without an explicit source, add resolves the preset through its usual -bundled and catalog lookup. - -Update is deliberately destructive. Arguments are checked before anything is -removed: `--from` and `--dev` cannot be combined, `--priority` must be 1 or -higher, and the preset must already be installed. Beyond those checks the -replacement source itself is not inspected in advance. If removal succeeds but -replacement installation fails, the previous preset has already been removed. -The command reports a copy-pastable `specify preset add` retry command, -including the replacement source and priority. On Windows, the reported command -is explicitly formatted for PowerShell. There is no source pre-flight, -version comparison, manifest diff, staging, rollback, automatic repair, or -recovery transaction. A missing or invalid replacement source can therefore -leave the preset removed. With -`--from` or `--dev`, the replacement manifest's `preset.id` is not checked -against the requested ID before removal; a source declaring a different ID may -therefore install a different preset after the requested one has been removed. - -A successful update follows normal remove and add behavior: it re-enables the -preset, recreates `installed_at`, removes local modifications tracked by the -preset, and treats an explicit `--from` or `--dev` as an intentional source -change. If constitution synchronization is enabled, both normal reconciliation -passes run. If add fails after removal, a generated constitution may remain -reconciled against the stack without the removed preset. The generated-file -guard still protects a hand-edited `.specify/memory/constitution.md`. No -update-specific constitution optimization is applied, so the normal remove and -add passes may rewrite the generated constitution even when the final resolved -content is unchanged. - -## Remove a Preset - -```bash -specify preset remove -``` - -Removes an installed preset and cleans up its registered commands. - -## List Installed Presets - -```bash -specify preset list -specify preset list --json -``` - -Lists installed presets with their versions, descriptions, template counts, and current status. - -`--json` writes a JSON array to stdout. Every item has the keys `id`, `name`, -`description`, `version`, `author`, `priority`, `enabled`, `source`, and -`provides`. `author` is `null` when absent; `source` is `{"kind":"local"}` -for local, legacy, or malformed provenance, or -`{"kind":"catalog","catalog":""}` for a valid catalog source. -Preset `provides` contains `commands`, `templates`, and `scripts` counts. On -success, `--json` writes exactly one array to stdout and exits 0. A runtime -failure after option parsing writes exactly one `{"error":"..."}` object to -stderr and exits 1. If parsing raises a usage error and the raw `--json` token -is present, it writes that JSON error object to stderr and preserves the usage -exit code (normally 2). Without `--json`, including for help, the existing -human-readable behavior is unchanged. - -Presets are printed in **resolution/precedence order**: the highest-precedence preset (lowest priority number) is listed first, and ties on priority are broken alphabetically by preset id. This matches the order used when composing commands and resolving templates, so the top entry is the one that wins for overlapping files. - -## Preset Info - -```bash -specify preset info -specify preset info --versions -specify preset info --json -``` - -Shows detailed information about an installed or available preset, including its templates, metadata, and tags. -`--versions` lists the advertised current version followed by historical -catalog versions, even for discovery-only entries; listing does not make -them installable. This view consults the catalog rather than the installed -preset. - -`--json` describes one installed preset, matched by ID, and writes a single -JSON object to stdout. The object has the same `id`, `name`, `description`, -`version`, `author`, `priority`, `enabled`, and `source` keys as the matching -`specify preset list --json` item. In place of the `provides` counts it has -`commands`, `templates`, and `scripts` arrays, one entry per manifest -contribution in declaration order. Each entry has `name`, `description` (`""` -when absent or empty), `source` (`{"layer": "preset", "presetId": ""}`, the -preset that provides it; the top-level `source` is where it was installed -from), `sourcePath` (the manifest -`file`, relative to the preset directory), and `strategy` (`replace`, -`prepend`, `append`, or `wrap`; `replace` when the manifest omits it). `--json` -cannot be combined with `--versions` (usage error, exit 2). A preset that is -not installed (including one that is only in a catalog), or a missing -project, writes one `{"error":"..."}` object to stderr and exits 1; usage errors -keep their exit code (normally 2), as with `list --json`. - -## Resolve a File - -```bash -specify preset resolve -``` - -Shows which file will be used for a given name by tracing the full resolution stack. Useful for debugging when multiple presets provide the same file. - -## Enable / Disable a Preset - -```bash -specify preset enable -specify preset disable -``` - -Disable a preset without removing it. Disabled presets are skipped during file resolution but their commands remain registered. Re-enable with `enable`. - -## Set Preset Priority - -```bash -specify preset set-priority -``` - -Changes the resolution priority of an installed preset. Lower numbers take precedence. When multiple presets provide the same file, the one with the lowest priority number wins. - -## Catalog Management - -Preset catalogs control where `search` and `add` look for presets. Catalogs are checked in priority order (lower number = higher precedence). - -> **A project's `.specify/preset-catalogs.yml` can point `add` and `search` at a catalog you didn't choose.** Before installing a preset in an unfamiliar project, run `specify preset catalog list` and inspect any catalog marked install-allowed — a project supplying that config, or marking a catalog install-allowed, is not evidence its presets were reviewed. Only mark a catalog `install_allowed` for one you authored or have vetted yourself; leave unfamiliar and community catalogs discovery-only. - -### List Catalogs - -```bash -specify preset catalog list -``` - -Shows all active catalogs with their priorities and install permissions. - -### Add a Catalog - -```bash -specify preset catalog add -``` - -| Option | Description | -| -------------------------------------------- | -------------------------------------------------- | -| `--name ` | Required. Unique name for the catalog | -| `--priority ` | Priority (default: 10; lower = higher precedence) | -| `--install-allowed / --no-install-allowed` | Whether presets can be installed from this catalog (default: discovery only). Only enable for a catalog you own and vet; never enable it for an unvetted public catalog. | -| `--description ` | Optional description | - -Adds a catalog to the project's `.specify/preset-catalogs.yml`. - -Re-adding the same named catalog with identical settings succeeds without changing the configuration; different settings are rejected. - -### Remove a Catalog - -```bash -specify preset catalog remove -``` - -Removes a catalog from the project configuration. - -### Catalog Resolution Order - -Catalogs are resolved in this order (first match wins): - -1. **Environment variable** — `SPECKIT_PRESET_CATALOG_URL` overrides all catalogs -2. **Project config** — `.specify/preset-catalogs.yml` -3. **User config** — `~/.specify/preset-catalogs.yml` -4. **Built-in defaults** — official catalog + community catalog - -### Versioned catalog entries - -Existing single-version entries remain valid: the top-level `version`, -`download_url`, optional `sha256`, and `requires` describe the advertised -current release. To retain older installable releases, add a `releases` -mapping keyed by version. Each historical record needs its own archive -`download_url` (HTTPS, or loopback HTTP for local development) and 64-digit -SHA-256 digest (optionally `sha256:`-prefixed, with surrounding whitespace); -other algorithm prefixes are rejected. Optional `requires` and `provides` -apply to that release instead of inheriting the current release's fields. -Other shared metadata, such as the name and description, is inherited. -Version keys must be distinct, including PEP 440-equivalent spellings, and -cannot repeat the current version. -Duplicate JSON keys are rejected before parsing can discard a release record. -Historical `requires.extensions` entries follow the preset manifest format: -extension IDs or mappings with an `id`, optional version constraint, and -optional boolean `required` flag. -For an ID lookup, catalogs are checked in priority order and stop at the -winning entry. Invalid or oversized payloads encountered before that entry -fail resolution rather than allowing a lower-priority entry to bypass its -installation policy. A malformed lower-priority source cannot block a valid -higher-priority match; searches across all sources still fail on malformed -catalogs. A non-object entry fails exact lookup for its own ID but is skipped -during all-catalog searches, which retain other valid entries. Unreachable -catalogs can still be skipped when another source is readable. -If every source fails, ID lookup (including `info --versions`) reports the -fetch error instead of claiming the preset has no catalog versions. Search -validates historical releases on each winning entry; invalid release history -from a shadowed source does not block its valid higher-priority replacement. - -```json -{ - "presets": { - "my-preset": { - "name": "My Preset", - "version": "2.0.0", - "download_url": "https://example.com/my-preset-2.0.0.zip", - "sha256": "<64 hex digits for the current archive>", - "releases": { - "1.5.0": { - "download_url": "https://example.com/my-preset-1.5.0.zip", - "sha256": "<64 hex digits for the older archive>", - "requires": {"speckit_version": ">=0.8.0"} - } - } - } - } -} -``` - -The bundled community catalog stays discovery-only and need not publish -release histories. Bundle pin resolution is a separate capability; adding -these preset records alone does not make bundle pins installable. - -Example `.specify/preset-catalogs.yml`: - -```yaml -catalogs: - - name: "my-org-presets" - url: "https://example.com/preset-catalog.json" - priority: 5 - install_allowed: true - description: "Our approved presets" -``` - -## File Resolution - -Presets can provide command files, template files (like `plan-template.md`), and script files. Each file name is evaluated independently against the priority stack, so different files can come from different layers. - -Templates and scripts are looked up from the stack when Spec Kit needs them. Commands use the same stack for replacement and composition, but are materialized into the active integration's directory only, instead of being re-resolved by agents or written to every detected agent directory (#2948). During preset install, Spec Kit registers command files for the preset being installed against the currently active integration; post-install and post-removal reconciliation then recomputes and writes the effective command content for affected command names based on the active stack. Install and rescaffold remain active-only, but removal may also update previously targeted inactive directories recorded by the removed preset to restore the surviving command or skill layer. A non-active installed integration does not otherwise receive these command files until it becomes the default — `specify integration use ` (or `switch `) rescaffolds enabled presets for the newly active integration. Agents do not re-resolve the stack each time they run a command. - -By default, files use a **replace** strategy: the first match in the priority stack wins and is used entirely. Templates and commands can also use composition strategies: **prepend** places preset content before lower-priority content, **append** places it after lower-priority content, and **wrap** replaces `{CORE_TEMPLATE}` with lower-priority content. Scripts support **replace** and **wrap**; script wrappers use `$CORE_SCRIPT` as the placeholder. - -The resolution stack, from highest to lowest precedence: - -1. **Project-local overrides** — `.specify/templates/overrides/` -2. **Installed presets** — sorted by priority (lower = checked first) -3. **Installed extensions** — sorted by priority -4. **Spec Kit core** — `.specify/templates/` - -### Resolution Stack - -```mermaid -flowchart TB - subgraph stack [" "] - direction TB - A["⬆ Highest precedence

1. Project-local overrides
.specify/templates/overrides/"] - B["2. Presets — by priority
.specify/presets/‹id›/"] - C["3. Extensions — by priority
.specify/extensions/‹id›/"] - D["4. Spec Kit core
.specify/templates/

⬇ Lowest precedence"] - end - - A --> B --> C --> D - - style A fill:#4a9,color:#fff - style B fill:#49a,color:#fff - style C fill:#a94,color:#fff - style D fill:#999,color:#fff -``` - -Within each layer, files are organized by type: - -| Type | Subdirectory | Override path | -| --------- | -------------- | ------------------------------------------ | -| Templates | `templates/` | `.specify/templates/overrides/` | -| Commands | `commands/` | `.specify/templates/overrides/` | -| Scripts | `scripts/` | `.specify/templates/overrides/scripts/` | - -### Resolution in Action - -```mermaid -flowchart TB - A["File requested:
plan-template.md"] --> B{"Project-local override?"} - B -- Found --> Z["✓ Use this file"] - B -- Not found --> C{"Preset: compliance
(priority 5)"} - C -- Found --> Z - C -- Not found --> D{"Preset: team-workflow
(priority 10)"} - D -- Found --> Z - D -- Not found --> E{"Extension files?"} - E -- Found --> Z - E -- Not found --> F["Spec Kit core"] - F --> Z -``` - -### Example - -```bash -specify preset add compliance --priority 5 -specify preset add team-workflow --priority 10 -``` - -For any file that both provide, `compliance` wins (priority 5 < 10). For files only one provides, that one is used. For files neither provides, the core default is used. - -## FAQ - -### Can I use multiple presets at the same time? - -Yes. Presets stack by priority — each file is resolved independently from the highest-priority source that provides it. Use `specify preset set-priority` to control the order. - -### How do I see which file is actually being used? - -Run `specify preset resolve ` to trace the resolution stack and see which file wins. - -### What's the difference between disabling and removing a preset? - -**Disabling** (`specify preset disable`) keeps the preset installed but excludes it from future template and script resolution. Previously registered commands remain available in your AI coding agent until preset removal, so use removal when you need command changes to stop taking effect. Disabling is useful for temporarily testing template/script behavior without a preset, or comparing template/script output with and without it. Re-enable anytime with `specify preset enable`. - -**Removing** (`specify preset remove`) fully uninstalls the preset — deletes its files, unregisters its commands from your AI coding agent, and removes it from the registry. - -### Who maintains presets? - -Most presets are independently created and maintained by their respective authors. The Spec Kit maintainers do not review, audit, endorse, or support preset code. Review a preset's source code before installing and use at your own discretion. For issues with a specific preset, contact its author or file an issue on the preset's repository. diff --git a/docs/toc.yml b/docs/toc.yml index 31085d637d..5ff12b1e9c 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -152,6 +152,23 @@ - name: Publishing href: extensions/publishing.md +# Presets +- name: Presets + href: presets/overview.md + items: + - name: Overview + href: presets/overview.md + - name: CLI Reference + href: presets/cli.md + - name: Developing + href: presets/developing.md + - name: API Reference + href: presets/api.md + - name: Catalogs + href: presets/catalogs.md + - name: Publishing + href: presets/publishing.md + # Reference - name: Reference items: @@ -165,8 +182,6 @@ href: integrations/cli.md - name: Catalogs href: reference/catalogs.md - - name: Presets - href: reference/presets.md - name: Artifacts href: reference/artifacts.md - name: Workflows diff --git a/presets/ARCHITECTURE.md b/presets/ARCHITECTURE.md deleted file mode 100644 index db540f7c72..0000000000 --- a/presets/ARCHITECTURE.md +++ /dev/null @@ -1,189 +0,0 @@ -# Preset System Architecture - -This document describes the internal architecture of the preset system — how template resolution, command registration, and catalog management work under the hood. - -For usage instructions, see [README.md](README.md). - -## Template Resolution - -When Spec Kit needs a template (e.g. `spec-template`), the `PresetResolver` walks a priority stack and returns the first match: - -```mermaid -flowchart TD - A["resolve_template('spec-template')"] --> B{Override exists?} - B -- Yes --> C[".specify/templates/overrides/spec-template.md"] - B -- No --> D{Preset provides it?} - D -- Yes --> E[".specify/presets/‹preset-id›/templates/spec-template.md"] - D -- No --> F{Extension provides it?} - F -- Yes --> G[".specify/extensions/‹ext-id›/templates/spec-template.md"] - F -- No --> H[".specify/templates/spec-template.md"] - - E -- "multiple presets?" --> I["lowest priority number wins"] - I --> E - - style C fill:#4caf50,color:#fff - style E fill:#2196f3,color:#fff - style G fill:#ff9800,color:#fff - style H fill:#9e9e9e,color:#fff -``` - -| Priority | Source | Path | Use case | -|----------|--------|------|----------| -| 1 (highest) | Override | `.specify/templates/overrides/` | One-off project-local tweaks | -| 2 | Preset | `.specify/presets//templates/` | Shareable, stackable customizations | -| 3 | Extension | `.specify/extensions//templates/` | Extension-provided templates | -| 4 (lowest) | Core | `.specify/templates/` | Shipped defaults | - -When multiple presets are installed, they're sorted by their `priority` field (lower number = higher precedence). This is set via `--priority` on `specify preset add`. - -The resolution is implemented three times to ensure consistency: - -- **Python**: `PresetResolver` in `src/specify_cli/presets.py` -- **Bash**: `resolve_template()` in `scripts/bash/common.sh` -- **PowerShell**: `Resolve-Template` in `scripts/powershell/common.ps1` - -### Composition Strategies - -Templates, commands, and scripts support a `strategy` field that controls how a preset's content is combined with lower-priority content instead of fully replacing it: - -| Strategy | Description | Templates | Commands | Scripts | -|----------|-------------|-----------|----------|---------| -| `replace` (default) | Fully replaces lower-priority content | ✓ | ✓ | ✓ | -| `prepend` | Places content before lower-priority content (separated by a blank line) | ✓ | ✓ | — | -| `append` | Places content after lower-priority content (separated by a blank line) | ✓ | ✓ | — | -| `wrap` | Content contains `{CORE_TEMPLATE}` (templates/commands) or `$CORE_SCRIPT` (scripts) placeholder replaced with lower-priority content | ✓ | ✓ | ✓ | - -Composition is recursive — multiple composing presets chain. The `PresetResolver.resolve_content()` method walks the full priority stack bottom-up and applies each layer's strategy. - -Content resolution functions for composition: - -- **Python**: `PresetResolver.resolve_content()` in `src/specify_cli/presets.py` (templates, commands, and scripts) -- **Bash**: `resolve_template_content()` in `scripts/bash/common.sh` (templates only; command/script composition is handled by the Python resolver) -- **PowerShell**: `Resolve-TemplateContent` in `scripts/powershell/common.ps1` (templates only; command/script composition is handled by the Python resolver) - -### Constitution lifecycle - -Initialization resolves `constitution-template` through the full stack and seeds -`.specify/memory/constitution.md` once. Existing files are preserved byte-for-byte. On subsequent -`/constitution` runs, the command resolves the current composed template at runtime and uses the live -constitution as the source of project-specific values and amendments. - -Preset installation, removal, enablement, disablement, and priority changes do not materialize -`constitution-template` by default. When the enabled preset registry contains `constitution-sync`, -those operations may reconcile the live file, but only if its provenance hash proves it is still -generated content. Missing files may be seeded when the preset is installed; authored or edited -constitutions are never overwritten. - -## Command Registration - -When a preset is installed with `type: "command"` entries, the `PresetManager` registers them into all detected agent directories using the shared `CommandRegistrar` from `src/specify_cli/agents.py`. - -```mermaid -flowchart TD - A["specify preset add my-preset"] --> B{Preset has type: command?} - B -- No --> Z["done (templates only)"] - B -- Yes --> C{Extension command?} - C -- "speckit.myext.cmd\n(3+ dot segments)" --> D{Extension installed?} - D -- No --> E["skip (extension not active)"] - D -- Yes --> F["register command"] - C -- "speckit.specify\n(core command)" --> F - F --> G["detect agent directories"] - G --> H[".claude/commands/"] - G --> I[".gemini/commands/"] - G --> J[".github/agents/"] - G --> K["... (17+ agents)"] - H --> L["write .md (Markdown format)"] - I --> M["write .toml (TOML format)"] - J --> N["write .agent.md + .prompt.md"] - - style E fill:#ff5722,color:#fff - style L fill:#4caf50,color:#fff - style M fill:#4caf50,color:#fff - style N fill:#4caf50,color:#fff -``` - -### Extension safety check - -Command names follow the pattern `speckit..`. When a command has 3+ dot segments, the system extracts the extension ID and checks if `.specify/extensions//` exists. If the extension isn't installed, the command is skipped — preventing orphan files referencing non-existent extensions. - -Core commands (e.g. `speckit.specify`, with only 2 segments) are always registered. - -### Agent format rendering - -The `CommandRegistrar` renders commands differently per agent: - -| Agent | Format | Extension | Arg placeholder | -|-------|--------|-----------|-----------------| -| Claude, Kilo Code, opencode, etc. | Markdown | `.md` | `$ARGUMENTS` | -| Copilot | Markdown | `.agent.md` + `.prompt.md` | `$ARGUMENTS` | -| Gemini, Qwen, Tabnine | TOML | `.toml` | `{{args}}` | - -### Cleanup on removal - -When `specify preset remove` is called, the registered commands are read from the registry metadata and the corresponding files are deleted from each agent directory, including Copilot companion `.prompt.md` files. - -## Catalog System - -```mermaid -flowchart TD - A["specify preset search"] --> B["PresetCatalog.get_active_catalogs()"] - B --> C{SPECKIT_PRESET_CATALOG_URL set?} - C -- Yes --> D["single custom catalog"] - C -- No --> E{.specify/preset-catalogs.yml exists?} - E -- Yes --> F["project-level catalog stack"] - E -- No --> G{"~/.specify/preset-catalogs.yml exists?"} - G -- Yes --> H["user-level catalog stack"] - G -- No --> I["built-in defaults"] - I --> J["default (install allowed)"] - I --> K["community (discovery only)"] - - style D fill:#ff9800,color:#fff - style F fill:#2196f3,color:#fff - style H fill:#2196f3,color:#fff - style J fill:#4caf50,color:#fff - style K fill:#9e9e9e,color:#fff -``` - -Catalogs are fetched with a 1-hour cache (per-URL, SHA256-hashed cache files). Each catalog entry has a `priority` (for merge ordering) and `install_allowed` flag. - -## Repository Layout - -```text -presets/ -├── ARCHITECTURE.md # This file -├── PUBLISHING.md # Guide for submitting presets to the catalog -├── README.md # User guide -├── catalog.json # Official preset catalog -├── catalog.community.json # Community preset catalog -├── scaffold/ # Scaffold for creating new presets -│ ├── preset.yml # Example manifest -│ ├── README.md # Guide for customizing the scaffold -│ ├── commands/ -│ │ ├── speckit.specify.md # Core command override example -│ │ └── speckit.myext.myextcmd.md # Extension command override example -│ └── templates/ -│ ├── spec-template.md # Core template override example -│ └── myext-template.md # Extension template override example -└── self-test/ # Self-test preset (overrides all core templates) - ├── preset.yml - ├── commands/ - │ └── speckit.specify.md - └── templates/ - ├── spec-template.md - ├── plan-template.md - ├── tasks-template.md - ├── checklist-template.md - └── constitution-template.md -``` - -## Module Structure - -```text -src/specify_cli/ -├── agents.py # CommandRegistrar — shared infrastructure for writing -│ # command files to agent directories -├── presets.py # PresetManifest, PresetRegistry, PresetManager, -│ # PresetCatalog, PresetCatalogEntry, PresetResolver -└── __init__.py # CLI commands: specify preset list/add/remove/search/ - # resolve/info, specify preset catalog list/add/remove -``` diff --git a/presets/PUBLISHING.md b/presets/PUBLISHING.md deleted file mode 100644 index 061e2eaf1a..0000000000 --- a/presets/PUBLISHING.md +++ /dev/null @@ -1,402 +0,0 @@ -# Preset Publishing Guide - -This guide explains how to publish your preset to the Spec Kit preset catalog, making it discoverable by `specify preset search`. - -## Table of Contents - -1. [Prerequisites](#prerequisites) -2. [Prepare Your Preset](#prepare-your-preset) -3. [Submit to Catalog](#submit-to-catalog) -4. [Verification Process](#verification-process) -5. [Release Workflow](#release-workflow) -6. [Best Practices](#best-practices) - ---- - -## Prerequisites - -Before publishing a preset, ensure you have: - -1. **Valid Preset**: A working preset with a valid `preset.yml` manifest -2. **Git Repository**: Preset hosted on GitHub (or other public git hosting) -3. **Documentation**: A preset-scoped README.md that explains how to use **this preset**, including a valid `specify preset add ...` install command (see [Usage README Requirements](#usage-readme-requirements)) -4. **License**: Open source license file (MIT, Apache 2.0, etc.) -5. **Versioning**: Semantic versioning (e.g., 1.0.0) -6. **Testing**: Preset tested on real projects with `specify preset add --dev` - ---- - -## Prepare Your Preset - -### 1. Preset Structure - -Ensure your preset follows the standard structure: - -```text -your-preset/ -├── preset.yml # Required: Preset manifest -├── README.md # Required: Documentation -├── LICENSE # Required: License file -├── CHANGELOG.md # Recommended: Version history -│ -├── templates/ # Template overrides -│ ├── spec-template.md -│ ├── plan-template.md -│ └── ... -│ -└── commands/ # Command overrides (optional) - └── speckit.specify.md -``` - -Start from the [scaffold](scaffold/) if you're creating a new preset. - -### 2. preset.yml Validation - -Verify your manifest is valid: - -```yaml -schema_version: "1.0" - -preset: - id: "your-preset" # Unique lowercase-hyphenated ID - name: "Your Preset Name" # Human-readable name - version: "1.0.0" # Semantic version - description: "Brief description (one sentence)" - author: "Your Name or Organization" - repository: "https://github.com/your-org/spec-kit-preset-your-preset" - license: "MIT" - -requires: - speckit_version: ">=0.1.0" # Required spec-kit version - extensions: # Optional: extensions this preset needs - - "companion-extension" - -provides: - templates: - - type: "template" - name: "spec-template" - file: "templates/spec-template.md" - description: "Custom spec template" - replaces: "spec-template" - -tags: # 2-5 relevant tags - - "category" - - "workflow" -``` - -**Validation Checklist**: - -- ✅ `id` is lowercase with hyphens only (no underscores, spaces, or special characters) -- ✅ `version` follows semantic versioning (X.Y.Z) -- ✅ `description` is concise (under 200 characters) -- ✅ `repository` URL is valid and public -- ✅ All template and command files exist in the preset directory -- ✅ Template names are lowercase with hyphens only -- ✅ Command names use dot notation (e.g. `speckit.specify`) -- ✅ Tags are lowercase and descriptive - -#### Declaring extension dependencies - -If your preset overrides commands that call into an extension, declare it in -`requires.extensions`. Without the extension the preset still installs and the -overrides fall through to the core workflow, so nothing errors — the feature -just silently does less than the user expects. Declaring the dependency makes -`specify preset add` say so, and spell out how to resolve it. - -Use a bare id, or a mapping when you need a version constraint or an optional -dependency: - -```yaml -requires: - speckit_version: ">=0.9.0" - extensions: - - "companion-extension" # required, any version - - id: "other-extension" - version: ">=1.2.0,<2" # optional PEP 440 specifier - required: false # optional, defaults to true -``` - -`version` accepts any PEP 440 specifier, not just a lower bound — upper bounds -(`<2`), exact pins (`==1.2.0`), and exclusions (`!=1.3.0`) all work. - -Notes: - -- The field is optional. A preset that declares nothing behaves exactly as before. -- A dependency that is missing, stale, disabled, or version-unsatisfied produces a **warning, not a failure** — the install still succeeds. -- A disabled extension counts as unmet, and so does one whose registry entry survives after its files were removed. Resolution skips both, so the preset is just as inert as if the extension were absent. -- The warning names an exact command for the missing, stale, and disabled cases. For a version mismatch it states the constraint to satisfy rather than naming a command, because `specify extension update` only moves forward to the catalog release and cannot satisfy an upper bound, a pin, or a downgrade. -- A recorded version that cannot be parsed is treated as uncomparable rather than as a mismatch, so an extension whose registry version reads `unknown` is not reported as failing a constraint it was never evaluated against. -- An extension present on disk but absent from the registry counts as satisfied. Resolution admits unregistered directories, so the preset works and warning about it would be a false alarm — though with no recorded version, a `version` constraint cannot be checked against it. -- `required: false` documents an enhancing-but-optional extension and is never warned about. -- Declare it in `preset.yml`, not only in your catalog entry. The catalog is not consulted for `--dev` and `--from ` installs, so the manifest is the only copy present on every install path. - -### 3. Test Locally - -```bash -# Install from local directory -specify preset add --dev /path/to/your-preset - -# Verify templates resolve from your preset -specify preset resolve spec-template - -# Verify preset info -specify preset info your-preset - -# List installed presets -specify preset list - -# Remove when done testing -specify preset remove your-preset -``` - -If your preset includes command overrides, verify they appear in the agent directories: - -```bash -# Check Claude commands (if using Claude) -ls .claude/commands/speckit.*.md - -# Check Copilot commands (if using Copilot) -ls .github/agents/speckit.*.agent.md - -# Check Gemini commands (if using Gemini) -ls .gemini/commands/speckit.*.toml -``` - -### 4. Create GitHub Release - -Create a GitHub release for your preset version: - -```bash -# Tag the release -git tag v1.0.0 -git push origin v1.0.0 -``` - -The release archive URL will be: - -```text -https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip -``` - -### 5. Test Installation from Archive - -```bash -specify preset add --from https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip -``` - -### Usage README Requirements - -The catalog `documentation` field must point at a README that explains how to use -**this preset** — not a product pitch for a broader framework or a separate CLI. - -The submission workflow **mechanically enforces** that the linked README is a GitHub-hosted -URL whose path ends with `README.md`, resolves to a readable file, and contains at least one -valid `specify preset add ...` command. The remaining items (preferring a preset-scoped README -in monorepos, covering the minimum structure) are expectations a human reviewer checks — -follow them so your submission isn't sent back for changes. - -- **Point `documentation` at the preset-scoped README.** In a monorepo where the preset - lives in a subdirectory (e.g. `presets//`), link the README inside that directory - (`presets//README.md`) rather than the repository-root README. The root README is - often a marketing/overview page; the catalog should surface preset usage instead. The key - requirement is that this README is reachable at the `documentation` URL so users can read - it *before* downloading the release artifact — it's fine for the same file to also ship - inside the release ZIP. -- **Include a valid Spec Kit CLI install command** *(enforced)*. The linked README must - contain at least one `specify preset add ...` invocation. Preferably use the - catalog-install form whose URL matches your Download URL: - - ```bash - # is the same URL you submit as the catalog Download URL — - # either the tag archive or a release asset, e.g.: - specify preset add --from https://github.com///archive/refs/tags/vX.Y.Z.zip - specify preset add --from https://github.com///releases/download/vX.Y.Z/-X.Y.Z.zip - ``` - - `specify preset add ` and `specify preset add --dev ` are also accepted, but the - `--from ` form is the clearest signal that the README documents this exact - preset release. -- **Cover the minimum structure** so a reader can decide whether the preset fits: - - What the preset does / what it provides - - The install command using Spec Kit CLI syntax (above) - - When to use it / when not to use it - -A submission whose linked README lacks a valid `specify preset add ...` command **fails -validation** (workflow check 2d) and will not be added until corrected. - ---- - -## Submit to Catalog - -### Understanding the Catalogs - -Spec Kit uses a dual-catalog system: - -- **`catalog.json`** — Official, verified presets (install allowed by default) -- **`catalog.community.json`** — Community-contributed presets (discovery only by default) - -All community presets should be submitted to `catalog.community.json`. - -### 1. Fork the spec-kit Repository - -```bash -git clone https://github.com/YOUR-USERNAME/spec-kit.git -cd spec-kit -``` - -### 2. Add Preset to Community Catalog - -Edit `presets/catalog.community.json` and add your preset. - -> **⚠️ Entries must be sorted alphabetically by preset ID.** Insert your preset in the correct position within the `"presets"` object. - -```json -{ - "schema_version": "1.0", - "updated_at": "2026-03-10T00:00:00Z", - "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json", - "presets": { - "your-preset": { - "name": "Your Preset Name", - "id": "your-preset", - "description": "Brief description of what your preset provides", - "author": "Your Name", - "version": "1.0.0", - "download_url": "https://github.com/your-org/spec-kit-preset-your-preset/archive/refs/tags/v1.0.0.zip", - "sha256": "OPTIONAL: SHA-256 hex digest of the archive above; verified before install", - "repository": "https://github.com/your-org/spec-kit-preset-your-preset", - "documentation": "https://github.com/your-org/spec-kit-preset-your-preset/blob/main/README.md", - "license": "MIT", - "requires": { - "speckit_version": ">=0.1.0" - }, - "provides": { - "templates": 3, - "commands": 1 - }, - "tags": [ - "category", - "workflow" - ], - "created_at": "2026-03-10T00:00:00Z", - "updated_at": "2026-03-10T00:00:00Z" - } - } -} -``` - -### 3. Update Community Presets Table - -Add your preset to the Community Presets table on the docs site at `docs/community/presets.md`: - -```markdown -| Your Preset Name | Brief description of what your preset does | N templates, M commands[, P scripts] | — | [repo-name](https://github.com/your-org/spec-kit-preset-your-preset) | -``` - -Insert your row in alphabetical order by preset **name** (the first column of the table). - -### 4. Submit Pull Request - -```bash -git checkout -b add-your-preset -git add presets/catalog.community.json docs/community/presets.md -git commit -m "Add your-preset to community catalog - -- Preset ID: your-preset -- Version: 1.0.0 -- Author: Your Name -- Description: Brief description -" -git push origin add-your-preset -``` - -**Pull Request Checklist**: - -```markdown -## Preset Submission - -**Preset Name**: Your Preset Name -**Preset ID**: your-preset -**Version**: 1.0.0 -**Repository**: https://github.com/your-org/spec-kit-preset-your-preset - -### Checklist -- [ ] Valid preset.yml manifest -- [ ] Usage README with a valid `specify preset add ...` command, linked from `documentation` (preset-scoped README recommended for monorepos) -- [ ] LICENSE file included -- [ ] GitHub release created -- [ ] Preset tested with `specify preset add --dev` -- [ ] Templates resolve correctly (`specify preset resolve`) -- [ ] Commands register to agent directories (if applicable) -- [ ] Commands match template sections (command + template are coherent) -- [ ] Added to presets/catalog.community.json -- [ ] Added row to docs/community/presets.md table -``` - ---- - -## Verification Process - -### What Happens After You Submit - -1. GitHub applies the `triage-must-have` verdict when the issue is opened through the Preset Submission form. This intake automation is specific to preset submissions and does not change the manual triage rubric for other issues. -2. A maintainer reviews the issue during issue triage and applies the separate `preset-submission` label, which starts the automated catalog validation. On this public repository, contributors cannot apply that label themselves, so there is nothing to label or re-request — the issue simply waits in triage. -3. The automated workflow validates the submission and, when validation passes, updates `presets/catalog.community.json` and `docs/community/presets.md` in a draft pull request -4. A maintainer reviews the generated pull request and merges it when approved -5. Your preset becomes discoverable via `specify preset search` - -### What Maintainers Check - -1. **Manifest validation** — valid `preset.yml`, all files exist -2. **Template quality** — templates are useful and well-structured -3. **Command coherence** — commands reference sections that exist in templates -4. **Security** — no malicious content, safe file operations -5. **Documentation** — the README linked from `documentation` explains how to use *this* preset and contains a valid `specify preset add ...` command - -> **Reviewer note:** the workflow can mechanically check *structure* (the linked README -> resolves and contains a valid `specify preset add ...` snippet; when that snippet uses the -> `--from ` form, its URL must match the submitted download URL exactly — other accepted -> forms like `specify preset add ` don't reference the download URL at all). Whether the -> README genuinely documents *this* preset is partly a content judgment, so a human reviewer -> should still confirm the linked doc isn't just a funnel to a separate product or CLI before -> approving. - -Once verified, `verified: true` is set and the preset appears in `specify preset search`. - ---- - -## Release Workflow - -When releasing a new version: - -1. Update `version` in `preset.yml` -2. Update CHANGELOG.md -3. Tag and push: `git tag v1.1.0 && git push origin v1.1.0` -4. Submit PR to update `version` and `download_url` in `presets/catalog.community.json` - ---- - -## Best Practices - -### Template Design - -- **Keep sections clear** — use headings and placeholder text the LLM can replace -- **Match commands to templates** — if your preset overrides a command, make sure it references the sections in your template -- **Document customization points** — use HTML comments to guide users on what to change - -### Naming - -- Preset IDs should be descriptive: `healthcare-compliance`, `enterprise-safe`, `startup-lean` -- Avoid generic names: `my-preset`, `custom`, `test` - -### Stacking - -- Design presets to work well when stacked with others -- Only override templates you need to change -- Document which templates and commands your preset modifies - -### Command Overrides - -- Only override commands when the workflow needs to change, not just the output format -- If you only need different template sections, a template override is sufficient -- Test command overrides with multiple agents (Claude, Gemini, Copilot) diff --git a/presets/README.md b/presets/README.md index 2559c3d0cb..416ddbb126 100644 --- a/presets/README.md +++ b/presets/README.md @@ -1,168 +1,29 @@ # 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: - -1. `.specify/templates/overrides/` — project-local one-off overrides -2. `.specify/presets//templates/` — installed presets (sorted by priority) -3. `.specify/extensions//templates/` — extension-provided templates -4. `.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//` during installation, Spec Kit walks the resolution stack on every template lookup rather than merging templates into a single location. - -`constitution-template` follows the same runtime model. Project initialization seeds -`.specify/memory/constitution.md` once so downstream commands always have a constitution to read. -After that, installing, removing, enabling, disabling, or reprioritizing presets does not rewrite the -live constitution. Each `/constitution` run resolves the current composed `constitution-template`, -then applies existing project values and amendments to that scaffold. - -Teams that intentionally want preset stack changes to refresh an unchanged generated constitution can -install the bundled `constitution-sync` preset. It restores guarded install-time materialization in -addition to its command-time propagation behavior; authored constitutions remain protected. - -For detailed resolution and command registration flows, see [ARCHITECTURE.md](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 - -```bash -# 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): - -```bash -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/.md`): - -```yaml -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. - -```bash -# 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/](scaffold/) for a scaffold you can copy to create your own preset. - -1. Copy `scaffold/` to a new directory -2. Edit `preset.yml` with your preset's metadata -3. Add or replace templates in `templates/` -4. Test locally with `specify preset add --dev .` -5. 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 - -```bash -# 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 doctor` for detecting composition conflicts. +This directory contains first-party preset assets, catalog data, and the +scaffold for creating presets. The canonical user and author documentation +is published in the [Presets guide](https://github.github.io/spec-kit/presets/overview.html). + +## Directory contents + +| Path | Purpose | +| --- | --- | +| `catalog.json` | First-party preset catalog | +| `catalog.community.json` | Community discovery catalog | +| `lean/` | Bundled lean process preset | +| `constitution-sync/` | Bundled, opt-in constitution synchronization preset | +| `scaffold/` | Example package to copy when authoring a preset | +| `self-test/` | Repository test fixture for preset contributions | + +Community presets are independently maintained. Catalog inclusion is not a +code review, security endorsement, or support commitment; users must vet +third-party presets before installation. + +## See also + +- [CLI reference](https://github.github.io/spec-kit/presets/cli.html) +- [Developing presets](https://github.github.io/spec-kit/presets/developing.html) +- [API reference](https://github.github.io/spec-kit/presets/api.html) +- [Catalogs](https://github.github.io/spec-kit/presets/catalogs.html) +- [Publishing presets](https://github.github.io/spec-kit/presets/publishing.html) +- [Community presets](https://github.github.io/spec-kit/community/presets.html) diff --git a/presets/scaffold/README.md b/presets/scaffold/README.md index b30a1ab6ac..234b1ab8d1 100644 --- a/presets/scaffold/README.md +++ b/presets/scaffold/README.md @@ -39,7 +39,7 @@ Required fields: ## Publishing -See the [Preset Publishing Guide](../PUBLISHING.md) for details on submitting to the catalog. +See the [Preset Publishing Guide](https://github.github.io/spec-kit/presets/publishing.html) for details on submitting to the catalog. ## License diff --git a/tests/test_catalog_trust_docs.py b/tests/test_catalog_trust_docs.py index 76003ea729..9a7f404acd 100644 --- a/tests/test_catalog_trust_docs.py +++ b/tests/test_catalog_trust_docs.py @@ -19,7 +19,7 @@ def test_workflow_publishing_does_not_claim_security_review(): def test_preset_catalog_docs_warn_about_vetting_install_allowed(): - text = (REPO_ROOT / "docs" / "reference" / "presets.md").read_text(encoding="utf-8") + text = (REPO_ROOT / "docs" / "presets" / "catalogs.md").read_text(encoding="utf-8") assert "install_allowed" in text assert "vet" in text.lower()