Claude Codeに任せたリリースで版番号を事故らせないChangesets運用術
Claude Codeでリリースを任せると速い。でも版番号は雑だと事故る。Changesetsで破壊的変更の誤公開を防ぐ運用を、失敗談つきで解説。
「このパッケージ、バージョン上げてリリースしといて」
Claude Codeにそうお願いした夜、僕はベッドで気づいて飛び起きました。あれ、破壊的変更が入ってたよな、と。慌てて確認したら、案の定patchで公開されていたんです。利用者のコードを壊す変更が、「ちょっとした修正」の顔をしてnpmに上がっていました。
戻すのは地獄でした。公開済みのバージョンはdeprecateしかできないし、すでにnpm installした人には届かない。あの冷や汗以来、僕はバージョン番号をAIに丸投げするのをやめました。
代わりに使い始めたのが Changesets です。今日はこれを、専門用語をできるだけ噛み砕きながら、僕の失敗込みで紹介します。
この記事の要点
- Claude Codeはリリースの「下書き」は得意だが、SemVer判断を単独で任せると事故る。
majorかpatchかの最終判断は人間が握る。 - Changesetsは
.changeset/*.mdという小さなメモから、版番号・CHANGELOG・リリースPR・npm公開を自動で組み立てるツール。「どのパッケージを、なぜ、どの種別で上げるか」をPRの時点で残せる。 - 一番危ないのは破壊的変更を
minor/patchで出すことと社内パッケージのnpm誤公開。この2つを構造で防ぐのがゴール。 - GitHub Actionsでは「リリースPRを作る」と「実際に公開する」を分ける。
mainにマージされた後にだけ公開ジョブが走る形にする。 - Claude Codeには「バージョン上げて」ではなく「changeset案をレビューとして出して」と頼む。判断理由を言わせると、誤った
minorを見つけやすい。
SemVerの約束を先に固定する
Changesetsの話に入る前に、土台のSemVer(セムバー)から。これは「意味のあるバージョン番号」の約束ごとです。1.4.2なら左からmajor.minor.patch。役割はこうです。
| 種別 | 何が変わったか | 利用者への影響 |
|---|---|---|
patch | 公開APIを壊さない修正 | そのまま上げてOK |
minor | 後方互換のある機能追加 | そのまま上げてOK |
major | 利用者のコード変更が必要になりうる変更 | 移行が要る、要注意 |
ここで多くの人がハマるのが、「公開API」は関数名だけじゃないという点です。Reactのprops、CSSのデザイントークン、CLIのフラグ、コマンドの終了コード(exit code)、デフォルトの挙動、exportしたTypeScriptの型——これ全部が「利用者が依存している契約」です。ボタンのsizepropを地味に削っただけでも、利用者の画面は崩れます。それは立派なmajorです。
僕はこの判断基準を、毎回Claude Codeに渡すようにしています。AIは賢いけれど、「あなたのライブラリで何が公開契約なのか」までは知らないからです。そこを教えてあげないと、平気で破壊的変更をpatchに放り込みます。冒頭の僕みたいに。
効く場面はだいたい決まっています。UIライブラリにpropsを足すとき。CLIのフラグを変えるとき。モノレポ(複数パッケージを1リポジトリで管理する構成)の内部依存を更新するとき。そして、社内専用パッケージをうっかり世界に公開しないようにするとき。どれも「あとから戻せない」種類の作業です。
Changesetsの初期設定
まずインストールして初期化します。
npm install -D @changesets/cli @changesets/changelog-github
npx changeset init
生成される.changeset/config.jsonは、次の形から始めると公開パッケージとモノレポの両方に対応しやすいです。
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": [
"@changesets/changelog-github",
{
"repo": "your-org/your-repo"
}
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
設定値の意味だけ、ここで押さえておきます。fixedは「常に同じ版番号にそろえたいパッケージ群」。linkedは「関連するパッケージを一緒に上げる」指定。updateInternalDependenciesは、モノレポ内で互いに依存しているパッケージの依存範囲をどう書き換えるか、です。
このあたりを曖昧にすると、公開した後で利用者の環境でinstallできない、という地味で厄介な落とし穴があります。僕は一度、内部依存の範囲指定をミスって「ローカルでは動くのに、利用者だけインストールに失敗する」状態を作りました。再現が難しくて、原因にたどり着くのに半日溶かしました。
最後にpackage.jsonのスクリプトも固定しておきます。これで「いつ何を叩くか」が決まります。
{
"scripts": {
"changeset": "changeset",
"changeset:status": "changeset status --since=origin/main",
"version": "changeset version",
"release": "changeset publish",
"build": "tsc -p tsconfig.json",
"test": "vitest run"
}
}
changesetファイルの書き方
公開パッケージに影響するPRでは、npx changesetを実行します。対話形式で「どのパッケージを、どの種別で上げるか」を聞かれ、.changeset/の下にメモが1枚できます。
npx changeset
できあがるメモは、こんなMarkdownです。
---
"@myapp/ui": minor
"@myapp/utils": patch
---
Add the `outline` variant to Button and keep the existing `solid` and `ghost` variants compatible.
Fix `formatCurrency` so it handles zero-decimal currencies without rounding errors.
この例では、@myapp/uiはButtonに新しいバリアントを足しただけなのでminor。@myapp/utilsは既存関数のバグ修正なのでpatchです。逆に、propsの削除、CLIフラグの改名、デフォルト挙動の変更があれば、それはmajor候補。「足した」はminor、「壊した・変えた」はmajor、とざっくり覚えておくと判断が速いです。
そしてここが今日の肝です。Claude Codeには「バージョンを上げて」とは頼みません。「changeset案を出して」というレビュー依頼にします。実行権を渡さず、提案だけさせるわけです。
このPRのdiffを読み、Changesets用のchangeset案を作ってください。
ルール:
- SemVerに従う。破壊的変更はmajor、後方互換の機能追加はminor、修正はpatch
- package.jsonのversionを直接編集しない
- npm publishを実行しない
- private: trueのpackageを公開計画に入れない
出力:
- 変更されたpackage
- packageごとの推奨bump
- 判断理由
- .changeset/*.mdの本文案
- 人間が確認すべき不確実な点
「判断理由」と「不確実な点」を必ず出させるのがコツです。理由を言葉にさせると、AI自身が「あれ、これprops消してるから本当はmajorかも」と気づくことが増えます。沈黙してminorにされるのが一番怖い。
モノレポと社内パッケージの扱い
モノレポでは、世界に公開するパッケージと、デプロイ専用で公開しないアプリが同じリポジトリに同居します。ここの線引きを間違えると、社内コードがnpmに流出します。やることは決まっています。
- 公開しないパッケージは
package.jsonに"private": trueを付ける - 社内レジストリに出すものは
publishConfig.registryでURLを明示する - 公開npm用のトークンと社内レジストリ用のトークンを分ける
- Changesets側でも、リリース対象から外したいものを
ignoreに入れる
設定ファイルだと、こんな形になります。fixedでコアとCLIを同じ版にそろえ、ignoreでアプリとドキュメントサイトを公開対象から外しています。
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": [
"@changesets/changelog-github",
{
"repo": "your-org/your-repo"
}
],
"commit": false,
"fixed": [
["@myapp/core", "@myapp/cli"]
],
"linked": [
["@myapp/ui", "@myapp/theme"]
],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["@myapp/app", "@myapp/docs"]
}
private: trueとignoreは二重の安全網です。片方だけだと、設定の書き換えひとつで穴が空きます。モノレポの育て方そのものに不安があるなら、先にClaude Codeでのモノレポ管理を読んでおくと、この設定の意味がもっとスッと入ると思います。
GitHub Actionsでリリースを2段に分ける
ここが事故防止の本丸です。標準のchangesets/actionを使うと、未処理のchangesetがあるときは「version PR(版上げPR)」を自動で作り、そのPRがマージされた後にだけnpm公開が走ります。つまり「版を決める」と「公開する」が物理的に分かれる。
name: Release
on:
push:
branches:
- main
concurrency: release-${{ github.ref }}
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm test
- run: npm run build
- name: Create release PR or publish to npm
uses: changesets/action@v1
with:
version: npm run version
publish: npm run release
title: "chore: version packages"
commit: "chore: version packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
ポイントは、プルリクエストから直接publishできる設計にしないこと。フォークからのPRやうっかりのpushで公開が走らないよう、トリガーはmainへのpushに限定しています。concurrencyで同時実行も1本に絞っているので、二重公開も防げます。
加えて、PR側のCIではnpx changeset status --since=origin/mainを走らせて、changeset漏れを落とします。「機能を足したのにメモを書き忘れた」PRが、ここで赤くなって止まる。ドキュメントだけのPRはchangeset不要なこともありますが、そのスキップ条件はチームルールとして文書に明記してください。Claude Codeに「例外を広げていい」と思わせないのが大事です。緩い例外を一度許すと、AIはそれを根拠にどんどん抜け道を作ります。このCIまわりの土台はClaude CodeでのCI/CDセットアップとGitHub Actionsの高度化に詳しく書いたので、合わせてどうぞ。
CHANGELOGの品質と、ありがちな失敗
リリースノートの良し悪しは、利用者の体験を直撃します。ダメな例はUpdate Button.の一行。これを見ても、利用者は「で、何が変わったの? 私のコード壊れる?」しか分かりません。
良いリリースノートは、追加されたAPI、既存利用者への影響、必要なら移行手順までを書きます。variant="outline"を足したなら、既存のsolidやghostは互換のままなのか、テーマ側で新しいCSSトークンを足すべきなのか、まで触れる。読んだ人が次の行動を決められるかどうか、が分かれ目です。
僕がこれまで踏んだ地雷を、正直に5つ並べます。
package.jsonのversionを手で直接いじって、Changesetsの計算とズレた- 破壊的変更を
minorで出して、利用者から「動かない」と連絡が来た(冒頭のやつ) privateを付け忘れて、社内パッケージを公開対象に入れかけた- 内部依存のbumpを忘れて、利用者環境だけインストール失敗した
- CHANGELOGが「改善しました」だけで、何の役にも立たなかった
特に5番は地味に効きます。実装者向けに書いたメモ(「リファクタしてテスト追加」みたいなやつ)をそのままchangesetに突っ込むと、公開CHANGELOGとして読みにくくなる。これは僕の検証でも何度もやりました。書く相手が違うんですよね。コミットメッセージは未来の自分宛て、CHANGELOGは利用者宛てです。
公開前のレビューは、プロンプトを固定しておくとブレません。
このchangesetを公開CHANGELOGとしてレビューしてください。
観点:
- 利用者が影響範囲を理解できるか
- major/minor/patchの判断と本文が一致するか
- migrationが必要なら手順があるか
- 「改善」「更新」だけの曖昧な表現がないか
- package名、関数名、props名が実在するか
疑わしい点は質問として列挙してください。黙って修正しないでください。
最後の「黙って修正しないで」は本気です。AIに勝手に直されると、何が問題だったのか僕が学べない。質問で返してもらうと、判断の基準が自分の中に貯まっていきます。
公開ボタンを押す前の最終チェック
リリース直前には、僕はこの順番で手元確認をします。コマンドにやらせられることは、全部コマンドに任せる。人間の目視に頼ると、忙しい日に必ず抜けます。
npm run changeset:status
npm test
npm run build
npm run version -- --snapshot canary
npm pack --dry-run
--snapshot canaryは、本番に出さずに「版番号の計算結果」と「CHANGELOGの出来上がり」を確認するためのお試し公開です。npm pack --dry-runは、実際にtarball(公開される圧縮物)に何が詰まるかを一覧で見せてくれます。
この--dry-runが地味に命綱です。ここで.env、巨大なテスト用フィクスチャ、社内ドキュメント、逆に欠けているビルド成果物が見つかります。Claude Codeが完璧なリリースノートを書いていても、公開物の中身がおかしければ事故です。リリースノートと公開ファイル、両方を見ないといけない。
Claude Codeに任せる範囲と、人間が握る範囲
最後に線引きの話を。Changesets運用で本当に大事なのは、ツールの使い方より、AIに任せる作業と人間が決める作業を分けることです。ここが今日一番伝えたいところかもしれません。
Claude Codeに向いているのは、補助の仕事です。diffから変更候補を拾う。package名が実在するか確認する。CHANGELOGの文章を読みやすく整える。CI設定の漏れを探す。このへんはAIが速いし、正確です。
一方で、人間が握るべき判断もはっきりしています。
- これは
majorかminorか(=利用者のコードを壊すか) - 公開APIとして何を約束するか
- この社内パッケージを外部公開していいか
実務でうまくいったコツがひとつ。PR本文に「このリリースで利用者がやる必要のある作業」を1行で書かせるんです。これが書けない変更はpatchの可能性が高い。逆に移行手順が要る変更はmajorを疑う。そしてClaude Codeには、その1行の説明とchangeset本文が矛盾していないかを見張らせる。説明は「破壊的変更なし」なのにpropsを消していたら、そこで止まります。
npmトークンを扱うワークフローは、とりわけ慎重に。さっきも書いたとおり、PRから直接publishできる設計は避け、mainマージ後にだけリリースジョブを走らせる。private package、サンプルアプリ、ドキュメントサイトはignoreに入れて、npm pack --dry-runで公開物を確かめる。この手順を一個でも省くと、AIが正しいノートを書いていても、設定ミスで公開事故が起きます。
ちなみに、AIにルールを安定して守らせる土台として、CLAUDE.mdのベストプラクティスにリリース方針を書いておくのは効きます。毎回プロンプトで唱えなくても、プロジェクトの憲法として効いてくれます。
よくある質問
Q. Changesetsはモノレポじゃない単独パッケージでも使えますか?
使えます。単独パッケージならfixedやlinkedは空のままでOKで、npx changeset→npm run version→npm run releaseの流れだけ回せば十分機能します。むしろ「版番号を手で書かない習慣」を身につける入口として、単独リポジトリで始めるのはおすすめです。
Q. ドキュメント修正だけのPRにもchangesetは必要?
基本は不要です。ただし「不要」の条件はチームで明文化してください。曖昧にすると、Claude Codeが「これも例外」と勝手に判断を広げます。CIでchangeset statusを走らせ、本当に公開物に影響しないPRだけスキップを許す、という線引きが安全です。
Q. Claude Codeにバージョンの種別判断まで任せたら、なぜ事故るの?
AIは「あなたのライブラリで何が公開契約か」を知らないからです。関数名の変更は分かっても、CSSトークンやexit codeが利用者の依存対象だと気づけないことがある。だから種別の最終判断は人間が握り、AIには「判断理由を言わせる」のが安全です。理由を言語化させると、誤ったminorが露見します。
Q. すでに間違った版番号でnpmに公開してしまったら?
公開済みバージョンの上書きはできません。npm deprecateで「使わないで」と警告を出し、正しい版番号で出し直すのが基本対応です。だからこそ、公開をmainマージ後に限定し、npm pack --dry-runで事前確認する構造が効きます。事後対応は痛いので、事前で止めるのが一番です。
Q. fixedとlinkedの違いがよく分かりません。
fixedは「常に完全に同じ版番号にそろえる」。コアとCLIをセットでバージョン管理したいときに使います。linkedは「一方が上がったら他方も連動して上がる」が、版番号自体は別々でいい。UIとテーマのように、関連はするけど独立して進むものに向いています。
実際に試した結果
冒頭の「破壊的変更をpatchで公開」事件から、僕のリリースは目に見えて静かになりました。
決め手は、賢さじゃなくて構造でした。Claude Codeに種別判断を丸投げするのをやめて、「changeset案+判断理由」を出させ、公開はmainマージ後だけに固定し、npm pack --dry-runを儀式にした。それだけで、深夜に飛び起きることがなくなりました。
Claude Codeはdiffからリリースノートを起草するのは本当に速い。でもSemVer判断を単独で任せると、やっぱり不安定です。一番効いたプロンプトは「なぜこれは破壊的変更ではないのか説明して」。理由を言わせると、誤ったminorやpatchがぽろぽろ見つかります。AIを疑うのではなく、AIに説明させる。これが今の僕の結論です。
リリースフローを自分のチームに本気で根づかせたいなら、設定の壁打ちから一緒にやれます。困ったらClaude Code研修・導入相談か、関連する教材一覧をのぞいてみてください。
公式情報はSemVer、Changesets、npmのパッケージ公開ガイド、GitHub Actionsを基準にしています。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeのチーム利用でコストが読めない時に作る予算ログ
チーム導入前に、誰が何に使い、どの成果が出たかを見える化する予算ログの作り方。
コミット前の3分チェック: Claude Codeが触った範囲を確認してから確定する
Claude Codeが勝手に広げた変更を、コミット前に3分で見抜く確認手順。差分の範囲、検証ログ、ステージするファイルの絞り込みを順番に解説します。
Claude Codeをチーム導入する前に作る「リスク台帳」の中身
Claude Codeを個人実験で終わらせずチーム導入するための、権限・CI・公開の事故を防ぐリスク台帳の作り方を実例とコードで解説します。