speckit-companion: Command for Claude Code

.claude/commands/publish-speckit-ext.md

publish-speckit-ext is a command for Claude Code from alfredoperez/speckit-companion. It costs 20 tokens per session (2,258 once invoked), scanned C, original, MIT.

A release command for the SpecKit extension, which adds SpecKit Companion commands and scripts. It packages the extension and publishes it as a GitHub release for installation without a local repository.

In plain words
What is it for?
Use it when releasing a new SpecKit extension version, including creating the required versioned tag and ZIP archive.
Why use it?
It applies the packaging and naming rules needed for the installer to find the right release and all available commands. This avoids publishing the SpecKit extension as the separate VS Code extension.

Command for Claude Code

Written for Claude Code: allowed-tools in frontmatter.

This is alfredoperez/speckit-companion's own configuration. It tells Claude Code how to work on speckit-companion itself, so it is not a mod to install elsewhere. Copy it as a starting point and replace the rules that are about this project. Everything speckit-companion configures →

Needs its repository: it runs a file that does not travel with it, so clone the repository first. The line is python3 scripts/package-manifest.py --copy-to /tmp/cb/companion-$V/scripts.

Reuse

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.

Copy the file
curl -O https://raw.githubusercontent.com/alfredoperez/speckit-companion/main/.claude/commands/publish-speckit-ext.md
Clone the repo
git clone --depth 1 https://github.com/alfredoperez/speckit-companion

Made for: Claude Code.

Wrote 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.

agentmods badge for publish-speckit-ext

README.md
[![agentmods](https://agentmods.dev/badge/commands/alfredoperez/speckit-companion/publish-speckit-ext/github.svg)](https://agentmods.dev/commands/alfredoperez/speckit-companion/publish-speckit-ext)
Your own site
<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.

agentmods 80×15 button for publish-speckit-ext

Your own site · 80×15
<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>
Per session 20 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 2,258 The whole file, excluding the scripts and references it only reads on demand.
Security scan C 1 finding. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

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.

ModelPer sessionOnce 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

Measured 12d ago against content hash 2f37e7a356b3, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-11, from the pricing page.

Security

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
.claude/commands/publish-speckit-ext.md · 79 lines

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)

  1. Tag namespace — use a prefixed tag speckit-ext-v<X.Y.Z>. A bare v* tag triggers release.yml and would publish the WRONG thing to the VS Code Marketplace.
  2. Archive must be a .zip (the installer rejects .tar.gz with BadZipFile), with a single top-level dir companion-<X.Y.Z>/ containing extension.yml at its root (mirrors the GitHub source-archive layout the CLI expects).
  3. Every command must be registered in extension.yml provides.commands — a command markdown that exists but isn't listed is silently skipped by the installer (this bit us once).
  4. 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

  1. Bump speckit-extension/extension.yml extension.version (semver). Confirm the target version with the user.
  2. Update speckit-extension/CHANGELOG.md — add a dated section for the new version; keep prior versions. End-user-friendly bullets.
  3. Readiness checklist (the catalog guide's gates):
    • id lowercase-hyphen; description < 100 chars; homepage present; license field and a LICENSE file in speckit-extension/; tags 2–5.
    • Every provides.commands[].file exists AND every command markdown under speckit-extension/commands/ is listed in provides.commands.
    • README is current (it's the catalog listing page).
  4. Commit + push to main (chore(speckit-ext): release v<X.Y.Z>).
  5. Build the archiveallow-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-only nodes/+presets/ sources — the catalog renders README/CHANGELOG from GitHub blob URLs, not the zip. (Don't "restore" a tar --exclude deny-list here: an allow-list is what keeps future doc/source additions out of the package.)
    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 )
    
    Never hand-type the script list here. scripts/package-manifest.py is the single source of truth; --copy-to fills 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.
  6. 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
    
  7. Refresh the stable companion-latest asset — this is what the README/install docs point users at, so the install/update URL never changes between releases. Force-replace the stable-named companion.zip on a reusable companion-latest prerelease 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
    
    • --prerelease is mandatory. It keeps companion-latest out of the repo's /releases/latest (which resolves across BOTH products — a v* VS Code release would otherwise hijack it). The stable URL …/releases/download/companion-latest/companion.zip resolves by tag, so it's immune to the v*/speckit-ext-v* interleaving. The trailing gh release edit … --prerelease re-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-latest tag is non-v*, so it does not trigger release.yml (the VS Code Marketplace publish).
  8. 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 throw FileNotFoundError. 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 Source prompt; a pre-existing install aborts with already installed … retry with --force (remove first or use --force); a stale ✗ companion (v0.1.0) ⚠️ Corrupted extension must 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.
  9. Confirm neither the prefixed tag nor companion-latest triggered release.yml: gh run list --workflow=release.yml --limit 2 (no new run — both tags are non-v*).
  10. 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 rolling companion-latest URL. Do NOT open a PR against extensions/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 with gh. It needs two human-authored inputs — Key Features and Example Usage — and one attestation confirmation.

Read the full file on GitHub · 79 lines

Changes

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.

  1. 12d ago First seen · 79 lines · 20 tokens per session scan C 2f37e7a356b3

Subscribe to this mod's changes

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.