Submit a community-catalog update
SkillFiles & storageFile the spec-kit community-catalog update for the `companion` extension as an Extension Submission ISSUE on github/spec-kit (never a PR — direct catalog PRs are rejected). Renders the issue body from the LIVE upstream issue-form template so our headings can't drift from theirs. Minor and major releases only. Use when the user says "/submit-catalog-update", "update the catalog", "file the catalog issue", "the catalog is stale", or right after /publish-speckit-ext cuts a minor or major spec-kit-extension release.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Submit a community-catalog update skill
What this skill tells your AI
The instructions your AI receives, as published by alfredoperez/speckit-companion in .claude/skills/submit-catalog-update/SKILL.md and read by ahel’s review.
The catalog entry for companion is version-pinned, so a release only reaches catalog users once the entry is bumped. This files that bump.
Deliberately no Edit/Write: this skill writes to a third-party repository and must not be able to mutate ours.
Hard-won rules (do not skip)
- Never open a PR against
extensions/catalog.community.json. github/spec-kit#3937 was closed unmerged — "Updates to extensions must use the extension submission issue template." The publishing guide is explicit: "Do not open a pull request directly to editextensions/catalog.community.json." Both first listings and version updates go through the [Extension Submission] issue. If you find yourself typinggh pr createagainstgithub/spec-kit, you are in the wrong workflow. - Never hardcode the
###headings. GitHub serializes an issue form as### <label>/ blank / value, and maintainers' validation parses that.render_submission.pyfetches the live.github/ISSUE_TEMPLATE/extension_submission.ymland renders from its labels — including the(optional)suffixes. If it cannot fetch the template it aborts; it never falls back to a remembered shape, because that fallback is the failure this skill exists to prevent. - The download URL is the version-pinned asset —
…/releases/download/speckit-ext-v$V/companion-$V.zip. Nevercompanion-latest/companion.zip: the catalog requires the declared version to equal the downloaded bits. This issue body is the only place a pinned URL belongs, and it is generated into a scratch dir, never committed. - Minor and major only. A patch does not touch the catalog; patch users ride
companion-latest. Compare against the catalog's current pin, not against.0— going 0.11.0 → 0.20.2 is a minor bump and correctly pins at the newest patch of the new line. - Never rebuild the catalog JSON. The script deep-copies the live entry and applies deltas, because that entry carries
verified,downloads,stars, andcreated_atwhich exist nowhere inextension.yml. Rebuilding drops them and reads as a destructive edit. - Do not pass
--label. We hold onlypullon github/spec-kit;gh issue create --labelerrors for a user without triage rights and nothing gets filed. Maintainers applyextension-submissionat triage — that is the documented flow. --body-file, never--body. The body carries em dashes, backticks,$, and fenced blocks.
Steps
-
Resolve the version.
V=extension.versionfromspeckit-extension/extension.yml. Everything keys off it; the script aborts if it disagrees with what you pass. -
Confirm the shape of the run. Working tree clean and on
main;speckit-ext-v$Vexists as a release; the pinned asset returns 200 and unzips to a singlecompanion-$V/whose manifest reports$V:git status --porcelain && git branch --show-current gh release view speckit-ext-v$V --json tagName curl -sIL -o /dev/null -w '%{http_code}\n' \ https://github.com/alfredoperez/speckit-companion/releases/download/speckit-ext-v$V/companion-$V.zip -
Read the cadence verdict. Fetch the live entry's
version. If$Vis only a patch ahead of it, stop and say patch fixes ridecompanion-latest. If the entry already carries$V, stop — nothing to submit. If there is nocompanionentry at all, this is a first listing, not an update: say so and confirm before continuing. -
Check for a duplicate before doing any work. Two passes, because titles get reworded but field values do not:
gh issue list --repo github/spec-kit --state all --limit 100 \ --search 'in:title "[Extension]" "Companion" author:@me' --json number,title,state,url,bodyThen parse the value under the live template's
Versionheading out of each hit. Any issue — open or closed — already carrying$Vmeans it is filed; stop. An open issue for an older version is still in triage, so comment on it rather than opening a second. -
Review the drift diff. Run the renderer and read
report.json'scatalog_nowagainstproposed. Get explicit approval for anything that is not a version bump —description,tags, andcategoryare editorial changes and must never ride along silently. -
Draft the two human fields.
Key Featuresis seeded from every## [x.y.z]section ofspeckit-extension/CHANGELOG.mdstrictly between the catalog's pin and$V— everything the catalog has never seen. Five to eight bullets,**Bold lead** — what it means for a user. Every bullet must trace to a changelog line or a shipped command; invent nothing.Example Usageis raw content with no inner fence (the template already wraps it in```markdown, and the accepted #2926 submission has no nested fence).Testing Detailsstates what was actually run —uname -sr,specify --version, and the real scenarios. -
Attestation gate — ask once. The script mechanically proves the manifest, README, LICENSE, release, command files, and id convention. It cannot prove: all commands execute without errors · documentation is complete and accurate · no security vulnerabilities identified · tested on at least one real project. List those four, plus a confirmation that Testing Details describes what actually happened, and require an explicit yes. Anything else aborts. Never tick an attestation the user did not give.
-
Render.
python3 .claude/skills/submit-catalog-update/render_submission.py \ --version $V --root . --category process --description "<catalog copy>" \ --features-file $S/features.md --example-file $S/example.md \ --testing-details-file $S/testing.md --context-file $S/context.md \ --attest yes --auto-checks-passed yes \ --out-body $S/body.md --out-title $S/title.txt --out-report $S/report.json--category/--descriptiondefault to the live values; pass them only for a deliberate change. Exit 3 means the template grew a required field the script cannot fill — read the message, add a filler, re-run. Never work around a gate. -
Show the full body and title verbatim. No summarizing. Confirm by eye: headings carry the
(optional)suffixes; the catalog fence isjsonand preservesverified/downloads/stars/created_at; the download URL is pinned; every required checkbox is[x]. Cheap cross-check — the heading set should be identical to the accepted submission:diff <(gh issue view 2926 --repo github/spec-kit --json body --jq .body | grep '^### ' | sort) \ <(grep '^### ' $S/body.md | sort) -
Re-check for duplicates, then file:
gh issue create --repo github/spec-kit \ --title "$(cat $S/title.txt)" --body-file $S/body.md -
Verify what landed. Diff the stored body against what you sent, normalizing trailing newlines — GitHub appends one, which is not mangling:
diff <(sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' $S/body.md) \ <(gh issue view <n> --repo github/spec-kit --json body --jq .body | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}')Any real difference means the create path mangled something.
-
Report the issue URL, the version transition, the template SHA rendered against, and any drift the report listed. Say plainly that maintainers apply
extension-submissionat triage, which starts automated validation — no label request, no follow-up PR — and that existing users are unaffected meanwhile because they update throughcompanion-latest.
Signals
- GitHub stars
- 90
- Forks
- 22
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
submit-catalog-update- Source
- github.com/alfredoperez/speckit-companion