ブログ一覧

changesets を AI エージェントに書かせると変更履歴が読める物になる

更新: Web開発者向け

8 つのサイトを 1 つのモノレポで運用していて、変更のほとんどを AI エージェント(Claude Code)に PR として作らせています。エージェントの PR は 1 日に何本も merge されるので、しばらく経つと「あのサイトはいつ何が変わったのか」を私自身が追えなくなりました。git log はあっても、commit のメッセージは「何をしたか」の一行で、「なぜ、何が壊れていて、何を捨てたか」は書かれていません。この記事は、changesets を入れてエージェントに変更記録を書かせ、変更履歴を人間が読める物にした記録です。別の bot のリポジトリでも同じ形にしていて、そちらで踏んだ罠も併記します。

changesets が何をする道具か

changesets は、パッケージのバージョンと CHANGELOG を管理する道具です。PR に .changeset/<名前>.md という小さなファイルを添え、そこに「どのパッケージが、どの種類の変更(patch / minor / major)で、何が変わったか」を書きます。main に merge されたこのファイルが溜まると、GitHub Actions(`changesets/action`)が「Version Packages」という PR を自動で立て、それを merge した時点で各パッケージの version が上がり、CHANGELOG.md に記録が集約されます。

.changeset/
  config.json                 # changelog の生成に @changesets/changelog-github(PR と commit へのリンク付き)
  restore-dropped-emdash-patch-hunks.md   # PR に添える変更記録(merge 後、Release PR で消える)
.github/workflows/
  release.yml                 # main への push で changesets/action を実行。Release PR を作る
apps/
  <site>/CHANGELOG.md         # サイトごとに集約された履歴
  <site>/package.json         # version が上がる。全部 private なので npm には出さない

モノレポ側では、apps/* はすべて private: true で npm には公開しません。それでも使う理由は、バージョン番号ではなく「サイトごとの CHANGELOG に、人間が読める変更記録を自動で集める」ことです。2026-04 に入れてから、Release PR は 18 回 merge されています。

エージェントに何を書かせるか

変更記録の書き方を、エージェントの手順書(CLAUDE.md)に 3 行で決めています。

  • 読み手(将来の自分、別のメンバー)が「何が、なぜ変わったか」を追えるレベルで書く
  • commit のメッセージより詳しく、PR の本文より簡潔に
  • 迷ったら書く。履歴を残して困ることはない

changeset を書かなくてよいのは、CI やインフラや文書の変更のように、サイトの挙動に影響しないものだけです。

変更記録を書く作業は AI エージェントに向いています。人間がやると、変更記録は PR を出す直前に「あとで書く」になりがちで、書く頃には文脈が薄れています。エージェントは PR を作る時点で Issue と差分と自分の調査の全部を持っているので、そこで書かせた記録には人間があとから書くより多くの経緯が入ります。逆に言えば、エージェントの作業の文脈はセッションが終われば消えるので、その場で書かせないと二度と書けません。

実例: 前の記録の誤りを次の記録が訂正する

2026-09-02 に、使わなくなったプラグインを撤去する PR を merge しました。その変更記録には、emdash 本体に当てているパッチについて「残るのは 404 ログ関連の 2 つだけ」と書いてあります。これが誤りでした。同じファイルに載っていた別目的の 2 つの修正(タクソノミーの先読み停止と、サイトマップの正規表現)も一緒に落ちていて、翌日、監視が D1 の読み取り行数の急増を検知しました。

戻す PR の変更記録には、こう書かせました。

#385 の変更記録にある「残るのは 404 ログ関連の 2 つだけ」はこの取りこぼしを見落としている。

CHANGELOG を開くと、0.9.3 の欄に誤った記録とそれを訂正する記録が並んでいます。どちらも消していません。git log でこの関係を読み取るには、2 つの commit を開いてパッチの中身を比べる必要がありますが、CHANGELOG では 2 段落を続けて読むだけです。

別のリポジトリで踏んだ罠

Slack から X に投稿する bot のリポジトリにも同じ形を入れました。こちらは単一パッケージで、private のまま git のタグと GitHub Release まで自動で作っています(privatePackages: { version: true, tag: true })。モノレポ側では出なかった罠が 3つありました。

  • タグの系統が 2 つになった。 それまで「main への push ごとに patch を機械的に上げてタグを切る」ワークフローがあり、changesets のリリースと役割が丸ごと重なっていました。共存させると、通常の PR の merge のたびに patch タグが切られ、Version Packages PR の merge では Release が 2 つできます。古い方を消し、バージョン番号の意味付け(patch / minor / major)は changesets だけが持つことにしました
  • changeset の忘れ検知は、commit 済みのファイルしか数えない。 CI に changeset status --since=origin/main を入れて、ソースの変更があるのに changeset が無い PR を検知しています。このコマンドは、作業ツリーにある未 commit の changeset を数えません。手元で、作業ツリーに changeset があるのに無いと判定されて分かりました。運用の初期は continue-on-error: true の警告扱いにし、changeset が要らない PR は skip-changeset のラベルで除外しています。定着したら警告を外すだけで必須にできます
  • Version Packages PR の merge も本番デプロイになる。 このリポジトリは main への push でデプロイが走ります。Version Packages PR の差分は package.json の version と CHANGELOG.md と changeset ファイルの削除だけで、コードの実体は変わらず、Terraform も no-op です。無害ですが、「Release PR の merge でデプロイが 1 回走る」ことは知っておく必要があります

境界: 3 つの場所に何を書くか

commit メッセージ、PR の本文、changeset の 3 つは役割が違います。

  • commit: 何をしたか。1 行
  • PR の本文: なぜやったか、どう確かめたか、何に詰まったか。レビューの材料。merge されれば PR の画面にしか残らない
  • changeset: 使う側から見て何が変わったか。CHANGELOG に永久に残り、あとから読まれる前提で書く

changeset に PR の本文を写すと長すぎ、commit のメッセージを写すと短すぎます。「コミットより詳しく、PR 本文より簡潔に」は、changeset を commit と PR の本文の間の長さで書くという意味です。

記録の質は指示で決まり、CHANGELOG はサイトごとに分かれ、誤った記録も残る

  • changeset の質は書かせる指示の質で決まり、「変更を記録して」だけだと commit メッセージの言い換えが出てくる。「何が、なぜ、何を捨てたか」と読み手を指定して初めて読める物になる
  • CHANGELOG はパッケージ単位に集約されるので、モノレポで 8つのサイトに同じ修正を入れたときは 8つの CHANGELOG に同じ段落が入る。1か所で読みたい場合は Release PR の本文を見る方が早い
  • 誤った記録が残るのは良いところでもあるが、読み返す人は「訂正が続いていないか」まで読む必要がある

変更記録はその場で読み手を指定して書かせ、誤りは次の記録で訂正する

  • 変更記録はエージェントが PR を作るその場で書かせる。エージェントの文脈はセッションが終わると消える
  • 読み手を指定する。「将来の自分と別のメンバーが、何が、なぜ変わったかを追える」
  • 迷ったら書く。書かない条件(挙動に影響しない変更)だけを決めておく
  • タグを切るリリースの自動化は 1系統にする
  • 誤った記録は消さず、次の記録で訂正する

参考リンク

関連

この記事をシェア