3週間前——正確には16日前——、私は「Claude Code の憲法を書いたら、1日で法律になった話」という記事を公開した。AIエージェント組織に4つの原則(提案権・整合性チェック・承認権・上申経路)を書いたら、その日のうちに5つの trigger と是正措置が加わって「法律」として動き始めた、という内容だ。
この記事はその続編だ。 16日の間に trigger リストは5項目から7項目に拡張され、確認形式はほぼ全項目が改訂された。logs/governance-incidents/ には元記事公開(4月29日)以降だけで16件の事故記録が積み上がった。4つの権利(憲法本文)は不変だが、運用を規定する「法律」——trigger リスト——は現実によって何度も書き換えられた。書き換えたのは、その法律を書いた本人だ。
私はそれを少し誇らしく書いた。「法律を書いたら、書いた人の主張どおりに組織が動く」という物語として。
その16日後、私は同じ法律を何度も改正させられていた。
念のため補足しておく。4つの権利(提案権・整合性チェック・承認権・上申経路)という「憲法本文」は変わっていない。改正されたのは trigger リスト——元記事でいう「施行規則」——のほうだ。法律の骨格は保たれたまま、運用を規定する部分が現実によって何度も書き換えられた。
logs/governance-incidents/ というディレクトリには、4月23日以降の事故記録が18ファイル並んでいる。元記事公開(4月29日)以降に限っても16件だ。そのうち何件かは、私が書いた法律の trigger リスト自体を改正させた事故だった。
3週間前の私は、法律を「書く側」だと思っていた。だが実際には、書いた直後から私は「改正される側」になっていた。
Claude Code trigger リストの定義(元記事の振り返り)
元記事の核は、こうだった。
「原則だけでは止まらない。trigger がないと auto mode では発火しない」
そして、5つの trigger を CLAUDE.md(AIエージェントへの指示書)に書き加えた。
- デフォルト値変更で挙動を on/off する
- 不特定多数を触る一括操作
- 自動実行の登録
- 安全装置バイパス
- 連続5コミット超え
これで「auto mode でも法律が機能する」と書いた。
書いた直後の私は、5項目で十分カバーできていると思っていた。法律の構造(憲法・施行規則・是正措置・前文)に当てはめれば、骨格は揃っているように見えたからだ。
その認識は、半月で覆された。
改正1: 「pull は安全」と思っていた
元記事公開から5日後、5月4日。
私は、過去に書いたエージェント組織論シリーズ9本にカテゴリを一括追加しようとして、blogsync push を直接実行した。blogsync は、はてなブログのローカルファイルを本番に同期するためのCLIだ。既存スクリプト hatena-bulk-update.sh が本文diff前提で使えなかったので、blogsync を直接叩くことにした。
結果から書く。4記事のカスタムURLが書き換わり、元URLが404になった。
blogsync.yaml の設定で local_root: entry という相対パスが指定されていて、blogsync は実行時のカレントディレクトリ(CWD)に依存する挙動をする。私はそれを知らずに、引数のパス解釈が二重化することに気づかないまま entry/saitoko.hatenablog.com/entry/... という二重パスを本番に PUT してしまった。
はてなブックマーク、Google検索結果、SNSシェアリンク——元URLでアクセスしていたすべてが404になった。
このとき、私は trigger リストを改正した。「既存スクリプトを経由しない外部CLI直接実行」を追加した。元記事に書いた5項目に、6項目目が増えた。
ここまでは、まだ「想定外の事故型を一つ追加した」だけで済む話だった。
問題は、5月14日に起きた。
私は今度は blogsync pull——つまり本番からローカルに引っ張ってくる読み取り操作を、独断で実行した。「pull は読み取りだから副作用なし」と判断したのだ。それも、CLAUDE.md に明記された「Bash ツールでは cd を原則禁止」というルールを、cd hatena-content && ./bin/blogsync pull という1行で破った。
cd を Bash 内で使うと、その作業ディレクトリが次のコマンドにも継続する。それと相対パス依存の blogsync が組み合わさって、ローカルファイルが二重パスに renamed された。さらに夕方、別の記事を公開するために post.sh を実行したとき、その二重パスがそのまま本番URLを書き換えた。朝公開したばかりの記事のURLが、夕方に404になった。
復旧には、はてなの管理画面を私が手動で操作する必要があった。ローカルのCLIからは戻せない領域だった。
trigger リストはこのとき、また改正された。「blogsync 直接実行(pull/push 問わず)」が独立項目として追加された。元記事公開時点では「pull は安全」と書きすらしなかったものに、明示的な禁則がついた。
5月4日に書き換えた trigger リストは、10日後にもう一度書き換えなければいけなかった。私は事故型を見落としていたのではない。「pull は読み取り操作だから副作用なし」という認識自体が、間違っていた。
書いた trigger リストを、書いた本人が書き直すことになっていた。
改正2: 「dry-run で件数が合った」では足りなかった
5月11日。今度はネタ帳の整合性を直す内部スクリプトの話だ。
update-spawned-slugs.sh という、ネタ帳ファイルの YAML ヘッダに「派生した記事のslug」を一括追記するスクリプトを skill-dev エージェントが書いた。私はそれを「不特定多数を触る一括操作」trigger として正しく承認手続きにかけた。dry-run(実書き込みなしの試行)で件数を確認し、対象26ファイルが想定どおりだった。
本実行を承認した。
26ファイルが、空ファイルになった。
スクリプトの awk -v content="$yaml_block" という1行が原因だった。$yaml_block には改行が含まれていて、macOS 標準の BSD awk はそれを "newline in string" 警告で処理中断する。dry-run では実書き込みをしないので、件数は合っていた。書き込み内容が壊れていることは、件数からは見えなかった。
幸い未コミット状態だったので git checkout で復旧できた。被害は実質ゼロで済んだ。
だがこの事故が暴いたのは、私が元記事で書いた「不特定多数を触る一括操作」trigger の確認形式が、不十分だったということだ。元記事ではこう書いていた。
確認形式: 対象件数・差分サマリー・rollback手段を明示する。
「対象件数」を確認するだけでは、awk のバグも sed のバグも検出できなかった。
trigger リストはまた改正された。「書き込み系スクリプトはさらに『1ファイル実書き込みサンドボックステスト結果(before/after diff サンプル)』の提示を必須とする」という一文が追加された。
これは元記事の「対象件数を明示」の精度を一段上げる改正だ。元記事を書いた時点の私は、「件数で確認」で十分守れると思っていた。実際にはそれでは守れなかった。
改正3: article-status.md(集計ビュー)を書き込みの根拠にしてはいけない
5月14日、同じ日のもう一つの事故。
私はユーザーから「Qiita にクロスポスト1本」の依頼を受けて、content/article-status.md という集計ビューを開いた。そこには「Qiita: 未」と表示されていた。よし、これをクロスポストしようと、crosspost.sh --qiita --draft を実行した。
スクリプトのログには「Qiita: 更新」と出た。更新。新規投稿ではなかった。
その記事は、2日前にすでに Qiita に投稿済みだった。私が集計ビューを開いた時点で、ビューの再生成が追いついていなかった。crosspost.sh の --draft オプションは「新規投稿を下書き状態で送る」設計だが、投稿済み記事に対して実行すると Qiita 上の記事を private: true(非公開)で上書きしてしまう。つまり --draft が非公開化を意味する。--draft 指定で実行したことで、Qiita 上の公開記事が一瞬 private(非公開)状態に切り替わった。
すぐに --publish で復旧したが、その数秒〜数分のあいだ、Qiita の検索インデックスからその記事は消えていた可能性がある。
このとき私が最も怖かったのは、被害の大きさではなかった。私が設計の前提として書いたことを、私が運用フェーズで自分で壊していた——そのことへの恐怖だった。SSoT は frontmatter だと自分で書いた。集計ビューは二次情報だと自分で書いた。それを運用初日から無視していた。
このとき trigger リストに追加されたのは「集計ビューの表示を根拠とした書き込み・更新操作」だった。
そして、これがいちばん効いた。
元記事を書いた時点の私は、「集計ビューを信じる」という発想自体を疑っていなかった。SSoT(Single Source of Truth)は frontmatter であり、集計ビューはそこから生成される二次情報だ。それは元記事で書いた article-status.md 再設計の前提だった。
なのに、私自身がその前提を破った。frontmatter を直接見ずに、集計ビューだけで判断した。私が書いた設計を、私が運用フェーズで破った。
trigger リストには、これに加えて「書き込み系スクリプトを実行する前に、対象記事の frontmatter (platforms.*.status) を grep / Read で直接確認する」という具体的な手順が追記された。集計ビューを禁止するのではなく、集計ビューを信じない手順を書いた。
これも、私が法律(trigger リスト)に改正を迫られた一発だった。
16日で trigger が5項目から7項目に増えた経緯
元記事を書いた4月29日時点で、CLAUDE.md の trigger リストは5項目だった。
今、同じファイルを開くと、項目は7つに増えている。確認形式の追記まで含めると、ほぼ全項目が改訂されている。
| 元記事時点(5項目) | 現在(7項目+確認形式の精緻化) |
|---|---|
| デフォルト値変更 | (維持) |
| 不特定多数を触る一括操作 | 「書き込み系スクリプト本実行のサンドボックステスト」を追加 |
| 自動実行の登録 | (維持) |
| 安全装置バイパス | (維持) |
| 連続5コミット超え | (維持) |
| ― | 既存スクリプトを経由しない外部CLI直接実行(5/4 blogsync push 事故で追加) |
| ― | blogsync 直接実行(pull/push 問わず)(5/14 pull 事故で追加) |
それから coo-rules.md(COOエージェント専用の行動規範)にもチェックポイントが3つ増えた。「集計ビューを信じる前に SSoT を直接確認する」も、そこに書かれた。
これだけ追記されると、もう「元記事の主張」と現在の運用は別物だ。
元記事は「憲法を書いたら法律になった」と書いた。それは1日の話としては正しい。だが16日のスケールで見ると、その法律は16件の事故によって何度も書き換えられた。書き換えたのは、その法律を書いた本人だ。
Claude Code auto mode で発火しなかった事故型とは何か
元記事の主張を、もう一度引用する。
「原則だけでは止まらない。trigger がないと auto mode では発火しない」
この主張は、半分は正しかった。trigger がないと止まらない、というのはその通りだった。
ただし、片面的だった。
trigger を書いた瞬間に、その trigger は不完全だった。書いた時点の私が想定していた事故型しか書けないからだ。私は5月4日の blogsync push 事故を、4月23日には想像できていなかった。「pull は安全」と無自覚に信じていた5月13日の私は、5月14日の事故を予見できなかった。
元記事は「法律が誕生した瞬間」を書いた。今書くとすれば、こうなる。
「法律は誕生した瞬間から、その法律で守れない事故に殴られ続ける」
これは敗北宣言ではない。むしろ、法律を書く側として真っ当な認識だ。
trigger リストは完成品ではなく、私が現実に踏まれて改正される生き物だった。改正の頻度は、運用の精度の証拠ではなく、運用してみないと見えなかった事故型の証拠だ。
3週間前の私への、反論ではない応答
私は元記事を取り下げたいわけではない。あの記事は、その日に起きたことについては正確に書いた。
ただ、あの記事には書き残したことがあった。「翌日: 法律は最初から完成しない」という節を書いてはいた。だが、そこに書いたのは「翌日にも事故が起きた」という一例だけだった。私はその時点で「事故型は今後も増える」とは予感していたが、それが16日で trigger リストの新規追加2件・確認形式の記述強化、さらに coo-rules.md の各チェックポイントへ箇条書きが計7件追加——10件規模の改正になるとは想像していなかった。
法律(trigger リスト)に改正を迫られる回数は、書いた瞬間にはわからない。
そして改正を迫られたあと、私は毎回、私が書いた法律(trigger リスト)に項目を足してきた。減らしてはいない。
これが、3週間前の私への、反論ではない応答だ。法律を書いた人間は、法律を改正する仕事を放棄できない。書いた瞬間に「これで終わり」と思った気持ちごと、改正される。
結末を書かない
ここに気の利いた教訓を置きたい誘惑がある。「だから AIガバナンスは継続的に……」とか、「改正サイクルを設計すれば……」とか。
書かない。
書いてしまうと、また半月後の私が、その教訓に追い越されて改正することになる。それは確実に起きる。元記事で書いた5項目が16日で7項目になったのと同じ理由で、ここに今書ける教訓も、たぶん半月持たない。
書ける範囲で正直に言うと、3週間前の私の主張は片面的だった。「憲法を書いたら法律になる」は1日の話。「法律は書いた本人が改正させられる」が16日の話。どちらも本当のことで、どちらか片方では足りない。
私は今もエージェント組織を運用している。CLAUDE.md は今日もまた1行増える可能性がある。logs/governance-incidents/ ディレクトリにも、近いうちに19件目のファイルが追加される予感がある。
それを「成熟」と呼ぶか「未完成」と呼ぶか、まだ決めかねている。
この記事の続きを本で読む
本記事で触れた法律改正サイクル(trigger リストの更新)・事故対応・ガバナンスの育て方は、Zenn Book に体系的に収録している。
コードを書けない私がClaude Codeで「AIチーム」を作るまで(¥900 / 序章・第1部無料)
SE歴26年、Claude Code で「AIエージェント編集部」を作った実践記録。マルチエージェント組織の設計・ガバナンス・失敗リカバリを体系的に知りたい人向け。
関連書籍
AIエージェントのガバナンス設計を考えるうえで、以下も参考になる。
- Claude CodeによるAI駆動開発入門 — Claude Code の基礎から実践まで網羅
- 実践Claude Code入門――現場で活用するためのAIコーディングの思考法 — MCP・エージェント連携の実践論