ops-release
GitHub用于一键发布 claude-ops 插件版本,自动执行版本号递增、更新清单文件、生成变更日志、创建发布 PR、等待 CI 并通过后合并至 main 分支及打标签。
Trigger Scenarios
Install
npx skills add Lifecycle-Innovations-Limited/claude-ops --skill ops-release -g -y
SKILL.md
Frontmatter
{
"name": "ops-release",
"description": "Publish a new version of the claude-ops (\"ops\") plugin in one command — bump plugin.json + marketplace.json + package.json, prepend the CHANGELOG, open the release PR, wait for CI, squash-merge it to main, and tag vX.Y.Z. Use when shipping a fix\/feature that has already merged to main and you want it published so \/ops:ops-update can pull it down. This is the publish side; \/ops:ops-update is the consume side.",
"allowed-tools": [
"Bash",
"Read",
"AskUserQuestion"
],
"argument-hint": "[--type patch|minor|major] [--version X.Y.Z] [--notes \"changelog body\"] [--no-ai] [--no-docs] [--no-wiki] [--dry-run] [--no-merge] [--no-tag]"
}
OPS ► RELEASE — one-command plugin publish
Cuts a new published version of the claude-ops plugin: bumps the version in the
three manifests, writes the CHANGELOG, opens a release PR, waits for CI, merges it to
main, and pushes the vX.Y.Z tag. After it runs, /ops:ops-update pulls the new
version down to the box.
ops-releaseships it ·/ops:ops-updatepulls it. Order: merge your fix PR →/ops:ops-release→/ops:ops-update.
⚠️ Run it from the REPO CHECKOUT, not the cache
bin/ops-release resolves its targets relative to its own location:
PLUGIN_DIR = <bin>/.., REPO_ROOT = <bin>/../.., and it needs
REPO_ROOT/.claude-plugin/marketplace.json. The plugin cache
(~/.claude/plugins/cache/ops-marketplace/ops/<ver>/bin/ops-release) has no
marketplace.json above it, so running the cache copy fails with
not found: …/.claude-plugin/marketplace.json. Always run the copy inside a
git checkout of the repo (the dir that has both .claude-plugin/marketplace.json
and claude-ops/bin/ops-release).
Resolve it first:
RELEASE=""
for d in ~/Projects/claude-ops-workspace/claude-ops ~/Projects/claude-ops/claude-ops "$HOME"/Projects/*/claude-ops; do
if [ -f "$d/.claude-plugin/marketplace.json" ] && [ -x "$d/claude-ops/bin/ops-release" ]; then
RELEASE="$d/claude-ops/bin/ops-release"; REPO="$d"; break
fi
done
[ -n "$RELEASE" ] || { echo "no claude-ops checkout with marketplace.json found — clone the repo first"; exit 1; }
echo "using: $RELEASE (repo: $REPO)"
Make sure the checkout's main is up to date and includes the fix you want to
publish before releasing (git -C "$REPO" fetch origin && git -C "$REPO" checkout main && git -C "$REPO" pull --ff-only). The release branches from origin/main,
so anything not yet on origin/main will NOT be in the release.
How to run it
Steps 3–5 are outward-facing + hard to reverse (open PR → CI-gated squash-merge to
main → push a public vX.Y.Z tag), so always dry-run first, show the plan,
confirm, then apply (Rule 5).
1. Dry-run and show the plan
"$RELEASE" --type patch --notes "<one-line changelog body>" --dry-run
Present the output: current → target version, which 3 manifests get bumped, the
CHANGELOG block, and that it will branch release/vX.Y.Z → PR → wait for CI → merge → tag.
Pick the bump type from the change: bug/patch fix → --type patch; new
backward-compatible feature → --type minor; breaking change → --type major
(or pin exactly with --version X.Y.Z).
2. Confirm
Use AskUserQuestion before applying:
Publish claude-ops <CUR> → <NEW>? (bumps 3 manifests + CHANGELOG, opens PR, waits for CI, merges to main, tags v<NEW>)
[Publish release]
[Dry-run only]
[Cancel]
3. Apply
"$RELEASE" --type patch --notes "<one-line changelog body>"
Stream the step-by-step output. On success it prints the PR URL, the merge, and the tag. Surface the final line verbatim and then tell the user to pull it down:
Released v<NEW>. Run
/ops:ops-updateto pull it onto this box.
Flags
| Flag | Effect |
|---|---|
--type patch|minor|major |
Semver bump from the current version (default patch). |
--version X.Y.Z |
Set an exact target version instead of bumping. |
--notes "…" |
Markdown body prepended to the CHANGELOG under the new version. Quote it. Overrides the AI changelog. |
--no-ai |
Skip AI changelog synthesis; fall back to commit subjects under ### Changed. |
--no-docs |
Skip the ops-sync-docs count/badge reconciliation step. |
--no-wiki |
Skip syncing the GitHub wiki (counts/version + Release-Notes entry). |
--dry-run |
Report only; change nothing (still previews the AI changelog). Always run this first. |
--no-merge |
Open the release PR but do not merge it (leave for manual review). |
--no-tag |
Skip pushing the vX.Y.Z tag. |
What it touches
claude-ops/.claude-plugin/plugin.json—.version.claude-plugin/marketplace.json(repo root) —.plugins[name==ops].versionclaude-ops/package.json—.version(if present)claude-ops/CHANGELOG.md— prepends a## [X.Y.Z] - <date>block. By default the body is AI-synthesized from the commit range in Keep a Changelog style (### Added/Changed/Fixed/Removed);--notesoverrides it,--no-aifalls back to commit subjects.- Docs counts — runs
bin/ops-sync-docs, which reconciles every skill/agent count, shields.io badge, and version badge acrossplugin.json,marketplace.json, the READMEs, anddocs/*-reference.mdto the real tree. Deterministic and idempotent; never touches historical "up from X/Y" prose. Skip with--no-docs. (Runbin/ops-sync-docsstandalone any time you add or remove a skill/agent.) - GitHub wiki — after merge+tag, clones the wiki, syncs its counts/version, and
prepends a
Release-Notes.mdentry for the new version. Skip with--no-wiki.
It works inside an isolated worktree ($REPO_ROOT/.worktrees/release/vX.Y.Z,
branched from origin/main), so a dirty main checkout never leaks unrelated WIP
into the release commit. The worktree is removed on exit.
Mobile / SSH (Rule 7)
The bin auto-detects a non-TTY and drops colour; its output is already line-per-fact, so relay it as-is — no tables, no banners.
Notes
- PRs target
main(claude-ops convention). The helper waits for the five product CI checks plus any other reported checks to finish, then squash-merges without bypassing them. - Publish ≠ deploy to the box. The running session won't see the new version
until
/ops:ops-update(pull) +/reload-plugins(load). - Sibling:
/ops:ops-update(pull a published version locally + prune/rewrite).
Version History
- 64bad13 Current 2026-08-12 09:01


