Borrowing it
Nothing to install: this file belongs to alfredoperez/speckit-companion. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.
curl -O https://raw.githubusercontent.com/alfredoperez/speckit-companion/main/.claude/commands/publish-speckit-ext.mdgit clone --depth 1 https://github.com/alfredoperez/speckit-companionWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/commands/alfredoperez/speckit-companion/publish-speckit-ext)<a href="https://agentmods.dev/commands/alfredoperez/speckit-companion/publish-speckit-ext"><img src="https://agentmods.dev/badge/commands/alfredoperez/speckit-companion/publish-speckit-ext/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/commands/alfredoperez/speckit-companion/publish-speckit-ext"><img src="https://agentmods.dev/badge/commands/alfredoperez/speckit-companion/publish-speckit-ext.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00020 | $0.02258 |
| Opus 5 | $0.00010 | $0.01129 |
| Sonnet 5 | $0.00004 | $0.00452 |
| Haiku 4.5 | $0.00002 | $0.00226 |
Grade C, and why
publish-speckit-ext scanned grade C with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 12d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Recursive force deletehighDestructive command
rm -rf with a variable or a broad path is one typo away from removing the wrong tree.
rm -rf /tmp/cb && mkdir -p /tmp/cb/companion-$V/scripts How it starts
The opening of the file, as written. The whole thing — 79 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Context
- spec-kit ext version: !
grep -A4 '^extension:' speckit-extension/extension.yml | grep 'version:' | tr -d ' "' | sed 's/version://' - Latest spec-kit-ext tags: !
git tag --list 'speckit-ext-v*' --sort=-version:refname | head -3 - Git status: !
git status --porcelain | head
Your task
Release the spec-kit extension (speckit-extension/, id: companion) so people can install it without a local clone. This is separate from /publish (that's the VS Code extension → Marketplace). Full reference: speckit-extension/docs/publishing.md.
⚠️ Hard-won rules (do not skip)
- Tag namespace — use a prefixed tag
speckit-ext-v<X.Y.Z>. A barev*tag triggersrelease.ymland would publish the WRONG thing to the VS Code Marketplace. - Archive must be a
.zip(the installer rejects.tar.gzwithBadZipFile), with a single top-level dircompanion-<X.Y.Z>/containingextension.ymlat its root (mirrors the GitHub source-archive layout the CLI expects). - Every command must be registered in
extension.ymlprovides.commands— a command markdown that exists but isn't listed is silently skipped by the installer (this bit us once). - Install command needs the name arg:
specify extension add companion --from <https-url>(not just--from). The URL must be HTTPS. A raw-URL install shows a one-time "untrusted source" prompt (expected until the catalog lists it).
Steps
- Bump
speckit-extension/extension.ymlextension.version(semver). Confirm the target version with the user. - Update
speckit-extension/CHANGELOG.md— add a dated section for the new version; keep prior versions. End-user-friendly bullets. - Readiness checklist (the catalog guide's gates):
idlowercase-hyphen;description< 100 chars;homepagepresent;licensefield and aLICENSEfile inspeckit-extension/;tags2–5.- Every
provides.commands[].fileexists AND every command markdown underspeckit-extension/commands/is listed inprovides.commands. - README is current (it's the catalog listing page).
- Commit + push to
main(chore(speckit-ext): release v<X.Y.Z>). - Build the archive — allow-list, runtime files only. Copy just what the installed extension runs (manifest, dispatched commands, the workflow, the runtime scripts, license). Do NOT ship docs, CHANGELOG, ROADMAP, README,
examples/, or the build-onlynodes/+presets/sources — the catalog renders README/CHANGELOG from GitHub blob URLs, not the zip. (Don't "restore" atar --excludedeny-list here: an allow-list is what keeps future doc/source additions out of the package.)
Never hand-type the script list here.V=<X.Y.Z> rm -rf /tmp/cb && mkdir -p /tmp/cb/companion-$V/scripts cd speckit-extension cp extension.yml LICENSE /tmp/cb/companion-$V/ cp -R commands workflows /tmp/cb/companion-$V/ python3 scripts/package-manifest.py --copy-to /tmp/cb/companion-$V/scripts cd - >/dev/null ( cd /tmp/cb && zip -rq companion-$V.zip companion-$V )scripts/package-manifest.pyis the single source of truth;--copy-tofills the archive from it and refuses to copy from a failing list. Hand-enumerating the scripts here is what shipped an archive missing five of them (#432). If a command starts calling a new script, CI fails until the manifest carries it — there is nothing to update in this file. - Cut the release (prefixed tag, attach the version-named zip for archival):
gh release create speckit-ext-v$V /tmp/cb/companion-$V.zip \ --title "SpecKit Companion spec-kit extension v$V" \ --notes-file <[X.Y.Z] section of speckit-extension/CHANGELOG.md> --target main - Refresh the stable
companion-latestasset — this is what the README/install docs point users at, so the install/update URL never changes between releases. Force-replace the stable-namedcompanion.zipon a reusablecompanion-latestprerelease with the same build:cp /tmp/cb/companion-$V.zip /tmp/cb/companion.zip if gh release view companion-latest >/dev/null 2>&1; then gh release upload companion-latest /tmp/cb/companion.zip --clobber else gh release create companion-latest /tmp/cb/companion.zip \ --title "SpecKit Companion (latest)" \ --notes 'Rolling stable download for the spec-kit extension. Always serves the newest `companion` build. Install/update: `specify extension add companion --from https://github.com/alfredoperez/speckit-companion/releases/download/companion-latest/companion.zip --force`' \ --prerelease --target main fi gh release edit companion-latest --prerelease # idempotent — re-asserts prerelease every run so a mis-marked prior release can't become /releases/latest--prereleaseis mandatory. It keepscompanion-latestout of the repo's/releases/latest(which resolves across BOTH products — av*VS Code release would otherwise hijack it). The stable URL…/releases/download/companion-latest/companion.zipresolves by tag, so it's immune to thev*/speckit-ext-v*interleaving. The trailinggh release edit … --prereleasere-asserts the flag on every run (the create path sets it, but an existing release that lost the flag would otherwise stay a normal release). Never document…/releases/latest/download/…for this repo.- The
companion-latesttag is non-v*, so it does not triggerrelease.yml(the VS Code Marketplace publish).
- Verify the deployed install (simulate a user) in a scratch dir — install from the stable URL, the same one users run:
mkdir -p /tmp/sk-verify/.specify/extensions && cd /tmp/sk-verify yes | specify extension add companion --from https://github.com/alfredoperez/speckit-companion/releases/download/companion-latest/companion.zip --force specify extension list # → SpecKit Companion (vX.Y.Z), all commands listed- If a prior local install left inconsistent emission dirs (
.{claude,cursor,agents}/skills/speckit-companion-*,.{gemini,qwen}/commands/speckit.companion.*, etc.), the install can throwFileNotFoundError. Nuke all companion emission artifacts first, then retry. - Expected non-error output (don't flag these as failures): a raw-URL install shows a one-time
⚠ Untrusted Sourceprompt; a pre-existing install aborts withalready installed … retry with --force(remove first or use--force); a stale✗ companion (v0.1.0) ⚠️ Corrupted extensionmust be removed before installing; and a clean install ends with an informational⚠ Configuration may be required / Check: .specify/extensions/companion/— no manual config is actually needed.
- If a prior local install left inconsistent emission dirs (
- Confirm neither the prefixed tag nor
companion-latesttriggeredrelease.yml:gh run list --workflow=release.yml --limit 2(no new run — both tags are non-v*). - Refresh the community-catalog entry — MINOR or MAJOR releases only; skip for patches. A patch (
x.y.Z) does not touch the catalog: catalog users stay on the current minor and patch fixes ride the rollingcompanion-latestURL. Do NOT open a PR againstextensions/catalog.community.json— direct catalog PRs are rejected (github/spec-kit#3937 was closed with "Updates to extensions must use the extension submission issue template"). Both first listings and version updates go through the [Extension Submission] issue. Run/submit-catalog-update: it renders the issue body from the live upstream issue-form template so our headings cannot drift from theirs, gates on the pinned asset returning 200 and on the minor/major cadence, refuses to file a duplicate, and creates the issue withgh. It needs two human-authored inputs — Key Features and Example Usage — and one attestation confirmation.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 12d ago First seen · 79 lines · 20 tokens per session scan C 2f37e7a356b3
publish-speckit-ext is a command published in the GitHub repository alfredoperez/speckit-companion (90 stars, last pushed today), licensed MIT. It adds 20 tokens to every session and 2,258 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it C with 1 finding (recursive force delete). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other commands, from other repositories
fest-commit
Commit changes with festival traceability metadata.
sddp-implement
Command description: Implement the current feature tasks. Argument hint: [optional: phase or task to start from] Command category: feature-delivery Prerequisites: spec, plan, tasks, checklists:complete-if-present.
wrap
The session-scoped landing step after ship: flips board rows, merges the operator's own green PRs one at a time, checks deploys, tidies branches and worktrees, writes the activity line, calls /kit:retro when a shipped PR merged, and prints the skim-first report. Use when the operator says to wrap up or close out the…
pr-ready
Run the project's pre-commit review loop to determine whether the current branch is ready to push — lint, tests, parallel pr-review-toolkit agents plus an over-engineering audit, fix-and-re-run until convergence.
ship
Ship: review gate, tests, version bump, changelog, conventional commit, docs update, PR. Complete pipeline from done to merged.
commit
Based on the above changes, create a single git commit for the staged changes.