agentsclimarketplace

Releasing

Skill kc0506/ntucool/.claude/skills/releasing

Cut a new ntucool release — bump versions across the workspace + plugin manifest, push, tag, let cargo-dist build prebuilt binaries on GitHub. Use whenever the user says "ship", "release", "publish", "tag a version", "cut a release", or asks "should we release v0.0.X?". Covers the dual-channel ship (binary via cargo-dist tag, plugin via plugin.json version) and the version-file matrix that's easy to miss.From its SKILL.md

Install
npx -y skills add kc0506/ntucool --skill releasing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.7 KB, as published. Nobody here has run it

Releasing ntucool

ntucool ships two artifacts on every release that have independent version sources in the repo:

ArtifactVersion sourceDistribution channelTrigger
cool binary[workspace.package] version in root Cargo.toml (+ 3 internal path-dep pins)GitHub Release via cargo-distgit push <tag> matching v*
Claude Code pluginversion in plugins/ntucool/.claude-plugin/plugin.jsonClaude Code's plugin update reads marketplace.json from origin/main and diffs plugin.json versionsgit push origin main

Both must bump for a release to flow end-to-end. Skipping the plugin bump is a silent failure — Claude Code's plugin update won't notice anything changed (it keys on plugin.json version, not git tags).

Pre-flight (run before bumping)

cargo test --workspace --quiet
cargo check -p ntucool --quiet

Quick MCP smoke (kept in scripts/):

cargo build --release -p ntucool --quiet
(printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}\n{"jsonrpc":"2.0","method":"notifications/initialized"}\n{"jsonrpc":"2.0","id":2,"method":"tools/list"}\n'; sleep 0.5) \
  | timeout 5 ./target/release/cool mcp 2>/dev/null \
  | grep -o '"name":"[^"]*"' | wc -l   # expect ≥ 24

Tag the current expected tool count somewhere and treat a deviation as a regression — past releases settled at 24 - 25.

The bump matrix (5 lines, in 4 files)

Same OLD → NEW substitution everywhere:

Cargo.toml:                         [workspace.package] version
cool-cli/Cargo.toml (2 lines):      path-dep pins to cool-api, cool-tools
cool-tools/Cargo.toml:              path-dep pin to cool-api
cool-tui/Cargo.toml:                path-dep pin to cool-api
plugins/ntucool/.claude-plugin/plugin.json:  version

One-liner that bumps all five at once (verify the match list first):

OLD=0.0.2 NEW=0.0.3
sed -i "s/version = \"$OLD\"/version = \"$NEW\"/g" \
  Cargo.toml cool-cli/Cargo.toml cool-tools/Cargo.toml cool-tui/Cargo.toml
sed -i "s/\"version\": \"$OLD\"/\"version\": \"$NEW\"/" plugins/ntucool/.claude-plugin/plugin.json
cargo check -p ntucool --quiet  # touches Cargo.lock
git diff --stat

Confirm the diff hits exactly those 4 files + Cargo.lock. Anything else means the sed picked up a co-incidental "0.0.X" somewhere.

Decision: which version number?

The project follows 0.0.x "everything is alpha" semantics. Breaking changes (renaming an MCP tool, changing the .mcp.json command users copy, removing a CLI subcommand) are fine inside 0.0.x — no minor bump needed.

If the contract feels stable enough to advertise, bump to 0.1.0. Until then, default to 0.0.<next>.

Ship sequence

# 1. Commit the bump
git add Cargo.toml Cargo.lock cool-*/Cargo.toml plugins/ntucool/.claude-plugin/plugin.json
git commit -m "chore(release): bump workspace + plugin to v0.0.X

What changed since v0.0.<prev>:
- <bullet 1>
- <bullet 2>
..."

# 2. Push main FIRST — this is what plugin-update reads from
git push origin main

# 3. Tag and push the tag — this triggers cargo-dist
git tag v0.0.X
git push origin v0.0.X

gh run watch the resulting Release workflow. Expected jobs:

plan → build-local-artifacts (3 targets) → build-global-artifacts → host → announce

15 - 20 min wall clock. On success, gh release view v0.0.X --json assets should list:

ntucool-installer.sh / .ps1
ntucool-x86_64-{pc-windows-msvc.zip, unknown-linux-{gnu,musl}.tar.xz}
each artifact's .sha256
dist-manifest.json + source.tar.gz

Known caveats — surface these in the release notes

  • macOS prebuilt is disabled. dist-workspace.toml has it commented out (GitHub free-tier macOS runner queue stalled v0.0.1 for 12h+). macOS users currently can't cargo install ntucool either — the crate has never been pushed to crates.io. State this honestly in the release announcement.
  • cool update available since v0.0.3. The embedded axoupdater reads an install-receipt that cargo-dist's shell/powershell installer drops at $XDG_CONFIG_HOME/ntucool/ntucool-receipt.json. Users on v0.0.2 or older need one last manual curl ...installer.sh | sh to reach a binary that has the subcommand; from then on cool update self-sustains. cargo install users never have a receipt — error message in commands/update.rs tells them to cargo install ntucool --force.
  • Plugin / binary version skew is possible. A user can have plugin v0.0.3 with binary v0.0.1 (or reversed). setup.md doesn't (yet) check version drift.

Pitfalls (post-mortems of past mistakes)

  • install-updater = true is NOT what makes the receipt get written. v0.0.3 set this flag thinking it was needed for cool update to find a receipt. Wrong — cargo-dist 0.9+ writes the receipt regardless. The flag actually ships a standalone ntucool-update binary alongside cool, undoing the single-binary principle. v0.0.4 reverted to false. Keep it false unless you specifically want a separate updater binary on PATH. Verify by checking gh release view v0.0.X --json assets — there should be NO ntucool-x86_64-*-update entries.
  • Don't push the tag before pushing main. If origin/main has commits you don't have locally (e.g. the user pushed a README edit while you were preparing the bump), pushing the tag first succeeds but pushing the branch fails with non-fast-forward. Recovery sequence: gh run cancel <id> for any triggered CI, git push origin :v0.0.X to delete the orphan tag, git pull --rebase (or git fetch && git rebase origin/main), git tag v0.0.X at the rebased HEAD, then git push origin HEAD:main v0.0.X together.
  • Main worktree may have uncommitted WIP that blocks a local fast-forward. If git -C <main-worktree> merge --ff-only reports "Your local changes would be overwritten", do NOT stash the user's WIP without asking. Push the worktree branch directly to origin/main with git push origin HEAD:main from the release worktree — this updates origin without touching the main worktree's working tree.

What this skill does NOT cover

  • cargo publish to crates.io — never done, namespace deferred indefinitely
  • macOS-target restoration in cargo-dist
  • Generating release notes from git log automatically (do it by hand for now)

Keep looking

Skills are one crate of 628,971. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.