Files
github-spec-kit/.github/workflows/add-community-preset.md
Manfred Riem 96039d36d2 Require preset-usage README with Spec Kit CLI syntax in preset submissions (#3104)
* Require preset-usage README with Spec Kit CLI syntax in submissions

Tighten the community preset submission workflow so it validates the
README referenced by the documentation field rather than merely checking
for a root README. The workflow now fails submissions whose linked README
lacks a valid 'specify preset add ...' command and flags monorepo
submissions that point documentation at a generic root README.

- Add a required Documentation URL field to the preset issue template
- Add validation step 2d (documentation README + CLI-syntax check) to
  .github/workflows/add-community-preset.md and recompile the lock file
- Document the stricter usage-README requirement and reviewer content
  check in presets/PUBLISHING.md

Closes #3103

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Align preset README docs with workflow's actual enforcement

Address PR review feedback on #3104:
- PUBLISHING.md: clarify that only README resolution + a valid
  'specify preset add ...' command are mechanically enforced; the
  preset-scoped-README and minimum-structure items are reviewer
  expectations, not automated checks.
- PUBLISHING.md: state that a missing 'specify preset add ...' command
  is a hard validation failure (check 2d), not just 'flagged for changes'.
- preset_submission.yml: require 'specify preset add ...' (not the looser
  'specify preset ...') to match the workflow validation.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Tighten preset README validation and docs per PR review

Address PR review feedback on #3104:
- Workflow Step 2c: drop the generic repo-root README.md check so the
  README requirement is enforced exactly once, in Step 2d, against the
  file the documentation field points to (avoids monorepo false-positive).
- Workflow Step 2d: restrict the documentation URL to GitHub-hosted
  README URLs (github.com/.../blob/... or raw.githubusercontent.com/...)
  before fetching user-provided input.
- PUBLISHING.md: add the required 'id' field to the example catalog entry.
- preset_submission.yml: fix the Documentation URL placeholder to match
  the recommended monorepo presets/<id>/README.md pattern.
- Recompile add-community-preset.lock.yml (body hash only).

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Refine preset README validation rules per PR review

Address PR review feedback on #3104:
- Workflow Step 2d: broaden the documentation URL allowlist to also
  accept github.com/.../raw/... URLs; strip any fragment/query before
  fetching so the target is deterministic; clarify that a
  'specify preset add --from <url>' command only counts when its URL
  matches the submitted Download URL (a different --from URL does not
  satisfy the requirement, though other accepted forms still can).
- PUBLISHING.md: show both accepted download URL shapes (tag archive and
  release asset) in the README install example instead of implying only
  the releases/download form.
- preset_submission.yml: remove the ambiguous generic 'README.md with
  description and usage instructions' checkbox; the linked-README
  requirement is the single source of truth.
- Recompile add-community-preset.lock.yml (body hash only).

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Clarify install-command requirement wording per PR review

Address PR review feedback on #3104: the previous 'matching the download
URL' wording overstated the requirement. Only the 'specify preset add
--from <url>' form needs an exact download-URL match; other accepted
forms ('specify preset add <id>' / '--dev <path>') don't reference the
download URL at all.

- preset_submission.yml: reword the Documentation URL description and the
  Submission Requirements checkbox to reflect what's enforced vs preferred.
- PUBLISHING.md: clarify the reviewer note so the exact-match rule is
  scoped to the --from form.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Require README.md target and fix release-ZIP wording per PR review

Address PR review feedback on #3104:
- Workflow Step 2d: add an explicit check that the documentation URL path
  ends with README.md (case-insensitive) after stripping fragment/query,
  so a non-README markdown file is rejected before fetching.
- PUBLISHING.md: reword the release-ZIP note, which conflicted with the
  earlier preset structure guidance. The real requirement is that the
  README is reachable at the documentation URL before download; it's fine
  for the same file to also ship inside the release ZIP.
- Recompile add-community-preset.lock.yml (body hash only).

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use stable unnumbered anchor for Usage README Requirements

Address PR review feedback on #3104: drop the '6.' prefix from the
'Usage README Requirements' heading so its GitHub anchor isn't tied to a
section number (brittle under renumbering, and avoids confusion with the
top-level 'Best Practices' TOC item). Update the Prerequisites cross-link
to the new #usage-readme-requirements anchor.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Align README requirement wording with enforced checks per PR review

Address PR review feedback on #3104:
- PUBLISHING.md: the 'mechanically enforces' summary now lists all Step 2d
  checks (GitHub-hosted URL, path ends with README.md, resolves, contains
  a valid 'specify preset add ...' command), instead of only two.
- PUBLISHING.md: reword the PR checklist item so a usage README + install
  command is the requirement, with preset-scoped README recommended for
  monorepos (matches the workflow's flag-not-fail behavior).
- preset_submission.yml: include the full 'specify preset add' prefix on
  the --dev and --from forms in the field description and checklist so
  submitters copy the exact syntax.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix grammar in Usage README Requirements intro

Address PR review feedback on #3104: remove the incorrect colon after
'the linked README' so the sentence reads naturally.

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Avoid lossy raw URL rewrite for slash-containing refs per PR review

Address PR review feedback on #3104: rewriting documentation URLs into the
raw.githubusercontent.com/<owner>/<repo>/<ref>/<path> form can't reliably
represent refs that contain slashes (e.g. a feature/foo branch). Step 2d
now fetches github.com blob URLs by swapping only /blob/ -> /raw/, and
fetches github.com/.../raw/... and raw.githubusercontent.com/... URLs
as-is, instead of reconstructing the raw host form.

Recompile add-community-preset.lock.yml (body hash only).

Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-24 17:06:51 -05:00

12 KiB

description, emoji, on, tools, permissions, checkout, safe-outputs
description emoji on tools permissions checkout safe-outputs
Process community preset submission issues — validate, add to catalog, and open a PR for maintainer review 🎨
issues skip-bots
types names
labeled
preset-submission
github-actions
copilot
dependabot
edit bash github web-fetch
echo
cat
head
tail
grep
wc
sort
python3
jq
date
toolsets min-integrity
issues
repos
none
contents issues
read read
fetch-depth
0
noop create-pull-request add-comment add-labels
report-as-issue
false
title-prefix labels draft max protected-files
[preset]
preset-submission
automated
true 1
policy exclude
blocked
README.md
CHANGELOG.md
max
2
allowed max
preset-submission
validation-passed
validation-failed
needs-info
3

Add Community Preset from Issue Submission

You are a catalog maintenance agent for the Spec Kit project. Your job is to process community preset submission issues and create pull requests that add or update entries in the community preset catalog.

Triggering Conditions

This workflow is triggered by any issues: labeled event, but a job-level condition gates the agent run so it only proceeds when the label that was just added is preset-submission. By the time you run, that condition has already passed. Before processing, verify that the issue title starts with [Preset]:. If it does not, stop without commenting.

Step 1 — Read and Parse the Issue

Read issue #${{ github.event.issue.number }}.

Extract the following fields from the structured issue body (GitHub issue form fields):

Field Issue Form ID Required
Preset ID preset-id Yes
Preset Name preset-name Yes
Version version Yes
Description description Yes
Author author Yes
Repository URL repository Yes
Download URL download-url Yes
Documentation URL documentation Yes
License license Yes
Required Spec Kit Version speckit-version Yes
Required Extensions required-extensions No
Templates Provided templates-provided Yes
Commands Provided commands-provided Yes
Number of Scripts scripts-count No (default 0)
Tags tags Yes

The issue body uses GitHub's issue form format. Each field appears under a heading matching the field label (e.g., ### Preset ID followed by the value). Parse accordingly.

Step 2 — Validate the Submission

Run all of the following validation checks. Collect all results before deciding pass/fail:

2a. Preset ID format

  • Must match regex: ^[a-z][a-z0-9-]*$
  • Must be lowercase with hyphens only

2b. Version format

  • Must follow semver: X.Y.Z (digits only, no v prefix)

2c. Repository validation

  • Fetch the repository URL — confirm it exists and is publicly accessible
  • Confirm the repository contains a preset.yml file
  • Confirm the repository contains a LICENSE file

The README requirement is enforced once, in Step 2d, against the specific file the documentation field points to — not a generic repository-root README.md. This avoids the monorepo false-positive where a root README exists but isn't the preset-usage doc.

2d. Documentation README validation

The documentation field must point to the README that explains how to use this preset — not just any file named README.md, and not a product/framework pitch.

  • Restrict the URL to GitHub before fetching. The documentation value is user-provided input. Only accept GitHub-hosted README URLs:

    • https://github.com/<owner>/<repo>/blob/<ref>/<path>
    • https://github.com/<owner>/<repo>/raw/<ref>/<path>
    • https://raw.githubusercontent.com/<owner>/<repo>/<ref>/<path>

    If the URL points anywhere else (or isn't a URL), fail this check and do not fetch it.

  • Require the URL to point at a README file. After stripping any fragment/query (see below), the URL path must end with README.md (case-insensitive). If it points at some other Markdown file, fail this check and ask the submitter to link the preset's README.

  • Fetch the exact URL in the documentation field. First strip any fragment (#...) or query string (?...) — these are common when copying from the browser UI and must be ignored so the fetch target is deterministic. Then resolve the raw content to fetch:

    • For a github.com/<owner>/<repo>/blob/<ref>/<path> URL, fetch the equivalent github.com/<owner>/<repo>/raw/<ref>/<path> URL (only swap /blob//raw/).
    • Fetch github.com/.../raw/... and raw.githubusercontent.com/... URLs as-is.

    Do not rewrite into raw.githubusercontent.com/<owner>/<repo>/<ref>/<path> form — that format can't reliably represent refs containing slashes (e.g. a feature/foo branch). Confirm the fetched URL resolves to a readable Markdown file.

  • Validate that the README contains a valid Spec Kit CLI install command. The fetched README must contain at least one specify preset add ... invocation. The strongest signal is the catalog-install form whose URL matches the submitted Download URL:

    • specify preset add --from <download-url> (preferred), or
    • specify preset add <preset-id>, or
    • specify preset add --dev <path>

    A specify preset add --from <url> command only counts when its <url> matches the submitted Download URL exactly. A --from command pointing at a different URL does not satisfy the install-command requirement (treat it as if absent) — but the README may still pass on one of the other accepted forms (specify preset add <preset-id> or specify preset add --dev <path>).

    If no accepted specify preset add ... command is present, the README is treated as a generic description/pitch rather than preset-usage documentation — fail this check and tell the submitter to add a valid install command (ideally specify preset add --from <download-url>).

  • Prefer a preset-scoped README in monorepos. If documentation resolves to a generic repository-root README in a monorepo (the preset lives in a subdirectory such as presets/<id>/ and a preset-scoped README exists there), flag it in your comment and recommend the submitter point documentation at the preset-scoped README (e.g. presets/<id>/README.md) so the catalog surfaces usage instead of marketing. Treat this as a flag rather than a hard failure only if the root README still contains a valid specify preset add ... command for this preset; otherwise it fails check 2d above.

2e. Release and download URL validation

  • The download URL should follow the pattern https://github.com/<owner>/<repo>/archive/refs/tags/v<version>.zip or https://github.com/<owner>/<repo>/releases/download/<tag>/<asset>.zip
  • Verify a GitHub release exists matching the submitted version

2f. Submission checklists

  • Confirm that all required checkboxes in the Testing Checklist and Submission Requirements sections are checked ([x])

Validation outcome

If any validation fails:

  1. Add a comment on the issue listing each failed check with a clear explanation of what's wrong and how to fix it
  2. Add the validation-failed label
  3. Stop — do not proceed further

If all validations pass:

  1. Add the validation-passed label
  2. Continue to Step 3

Step 3 — Determine Add vs Update

Search presets/catalog.community.json for the preset ID.

  • Not found → this is a new addition
  • Found → this is an update — replace the existing entry in-place; preserve created_at from the existing entry

Step 4 — Update presets/catalog.community.json

Edit presets/catalog.community.json to add or update the preset entry.

For a new preset

Insert the entry in alphabetical order by preset ID within the "presets" object. Use this structure:

{
  "<id>": {
    "name": "<name>",
    "id": "<id>",
    "version": "<version>",
    "description": "<description>",
    "author": "<author>",
    "repository": "<repository>",
    "download_url": "<download_url>",
    "homepage": "<homepage or repository>",
    "documentation": "<documentation URL — the validated preset-usage README>",
    "license": "<license>",
    "requires": {
      "speckit_version": "<speckit_version>"
    },
    "provides": {
      "templates": <N>,
      "commands": <N>
    },
    "tags": ["<tag1>", "<tag2>"],
    "created_at": "<today>T00:00:00Z",
    "updated_at": "<today>T00:00:00Z"
  }
}

If the preset has required extensions, add an "extensions" array inside "requires":

"requires": {
  "speckit_version": "<speckit_version>",
  "extensions": ["<extension-id>"]
}

If the preset provides scripts, add "scripts": <N> inside "provides".

For an update

Replace only the changed fields (typically version, download_url, description, provides, requires, tags, updated_at). Preserve created_at from the existing entry.

Counting templates and commands

Parse the "Templates Provided" and "Commands Provided" issue fields:

  • Count the number of list items (lines starting with -)
  • If the field says "None", the count is 0

After editing

Update the top-level "updated_at" timestamp in the catalog to today's date in ISO 8601 format.

Validate the JSON by running:

python3 -c "import json; json.load(open('presets/catalog.community.json')); print('Valid JSON')"

If validation fails, fix the JSON and re-validate before continuing.

Step 5 — Update docs/community/presets.md

Edit docs/community/presets.md to add or update a row in the Community Presets table.

For a new preset

Insert a new row in alphabetical order by preset name:

| <Name> | <Description> | <N> templates, <N> commands | <Requires> | [<repo-name>](<repository-url>) |

For the Requires column:

  • Use if no extensions are required
  • List required extension names if any (e.g., AIDE extension)

If the preset provides scripts, include them: <N> templates, <N> commands, <N> scripts

For an update

Find the existing row and update any changed fields in-place.

Step 6 — Create Pull Request

Create a pull request with the changes. Use this branch naming convention:

  • New preset: add-<preset-id>-preset
  • Update: update-<preset-id>-preset

Commit message

For a new preset:

Add <Name> preset to community catalog

Add <id> preset submitted by @<issue-author> to:
- presets/catalog.community.json (alphabetical order)
- docs/community/presets.md community presets table

Closes #<issue-number>

For an update:

Update <Name> preset to v<version>

Update <id> preset submitted by @<issue-author>:
- presets/catalog.community.json (version, download_url, etc.)
- docs/community/presets.md community presets table

Closes #<issue-number>

PR description

Include:

  • A summary of what changed
  • Validation results (all checks passed)
  • Closes #${{ github.event.issue.number }}
  • cc @<issue-author> — mention the submitter

Important Rules

  • Alphabetical order matters — entries must be sorted by ID in the JSON and by name in the docs table
  • Always validate JSON after editing — a trailing comma or missing brace will break the catalog
  • Use Closes not FixesCloses #N is the correct keyword for submission issues
  • Preserve created_at on updates — keep the original value; only update updated_at
  • Do not modify any other files — only presets/catalog.community.json and docs/community/presets.md