他のエージェントを監査する4層目を足したら、Strategistが3週間サボっていたことが発覚した話
私は3層のエージェントハーネスを組んで「自律」と呼んでいました。Observerがデータを集め、Strategistがテーマを選び、Marketerが記事を書く。3つとも strategy.md に従って動きます。月曜09
ある日、自分のStrategistログを3週分まとめて読んでいて、変なものを見つけました。撤退基準のひとつ「Reaction率が4週連続で1%未満なら戦略見直し」が、3週連続でルール発動条件に近づいていたのに、毎週「データ不足。来週要観測」で先送りされていたのです。ルールはありました。データもありました。それでもルールは一度も発動しませんでした。
3層構成ではこのバグは捕まりません。3つのエージェントは strategy.md の指示どおりに働いていたからです。バグはルール自体にあって、それを監査する役割が3層のどこにもありませんでした。
4層目として Evolver を足しました。最初の本格提案で、Strategistが3週間隠れていたまさにそのルールに対して diff を書いてきました。

「自律」と呼んでいた3層構成
自律と呼んでいた構成はこんな感じです。Observerが毎日動いてGA4数値を article-performance.jsonl に書き溜める。Strategistが月曜朝に strategy.md を読んで週5本のテーマを選ぶ。Marketerがテーマを記事化して公開キューに積む。3役・3 cron・予測可能な挙動。
このパイプラインが速い理由は、Strategistから意図的にWebSearchを取り上げた点にあります。WebSearchを使えるStrategistは毎ランで20分迷子になり、自分のコンテンツ資産ではなく最近のニュースに合わせたテーマを選び始めました。WebSearchを外したら20分が3分に縮みました。これは別の記事で書きました。あれはStrategistを速くする話。今回はStrategistに説明責任を持たせる話です。
3層のどれにもできなかったのが strategy.md 自体を書き換えることです。月曜にルールを読んで従う。ルールが間違っていれば、間違ったルールに忠実に従う。ルールを直すには、私が週次レビューで気づくしかありません。そして私自身が3週間気づけませんでした。撤退基準のセクションを見ていなかったからです。
先送りはログにどう現れていたか
自分のログを引用したほうが正直なので、原文をそのまま貼ります。
3週前のStrategistログ:
Reactionは大多数の記事で0% → タイトル一人称化 + 数字 + 体験談で改善試行中。4週連続1%未満なら戦略見直し検討(現在3週連続を観測中、今週で見極め)
翌週のログ:
Reaction率は4週連続1%未満になっていないが、weekly trend データ不足。来週要観測
これだけで失敗の全体像が見えます。ルールは「4週連続」と書いてある。Strategistの手元には3週連続のデータがある。本来なら今週が4週目の判定週なのに、Strategistは「観測中」と書いて時計を進めずに記事を書き始めました。撤退基準が「いくらでも先送りできる」構造になっていたのです。
article-performance.jsonl から私自身が直近4週24本を集計し直すと、もっと醜い数字が出てきました。総view 812、総reaction 4、総comment 7。Reaction率0.49%。閾値の半分。Engagement率(reaction + comment)1.35%。発動はとっくに済んでいないとおかしい数字でした。発動しなかった理由は、ハーネスのどこにも「このルール、ちゃんと働いてる?」と問う層がなかったからです。
4層目 Evolver の正体
そこで4本目のcronを足しました。土曜09
。月曜のObserver/Strategist/Marketerチェーンとは別タイミング。3層と違ってWebSearch有効。仕事は記事を書くことではなく、strategy.md と直近の判断ログを読んで、strategy.md への差分を提案することです。
提案は1ファイル単位: domains/<name>/data/evolution/EVO-NNNN.md。Evolverは5セクションを埋めます。
- 観測 — データで何を見たか
- 提案 — ルール変更を自然文で
- 根拠 — 内部データと外部情報の引用
- 想定インパクト — 適用したら何が良くなるか
- diff —
strategy.mdへのdiff ``` ブロック
肝心なのは diff ブロックです。Evolverは「英語の改善案」を書くだけではなく、git apply できる実パッチまで生成します。core/harness-evolve.sh というシェルが diff ブロックを抽出して git apply --check を走らせ、通れば本適用してcommitまでやる。適用処理にはLLMを一切呼びません。LLMが提案、シェルが適用。
この分離は意図的です。提案は創造的、適用は機械的。機械的な処理は「クリーンに成功する」か「明確に失敗する」のどちらかで、「途中で何か変な事が起きた」が発生しません。
EVO-0003 が掘り起こしたもの
Evolverの3本目の本格提案 EVO-0003 が、冒頭で書いた件です。提案ファイルはディスクに残っているので、書きながら読み直しています。
観測セクションには私のStrategistログが2週分まるごと引用されていました。「3週連続を観測中、今週で見極め」のと、「データ不足。来週要観測」のと。続けて article-performance.jsonl から集計したEngagement率を出して、閾値はとっくに割れていることを示してきました。それから元のルールを3つの観点で批判していました。
- 計算式が明文化されていない。「Reaction率」は記事単位の比率か、合計の比率か。Strategistはどちらでも計算できるので先送り余地が生まれた
- 「4週連続」の発動条件が、週次データが薄いと曖昧になる
- 発動時のアクション「タイトル・角度の戦略見直しを提案」が抽象すぎて、Strategistは1文だけ書いて先に進めてしまえる
提案された置換ルール:
エンゲージメント率 = (直近4週公開記事の総reactions + 総comments) / 総views。Strategist は毎週これを計算しログに記録する。1.5%未満が4週連続なら、翌週は5本中4本を「数字+一人称+失敗ナラティブ」型タイトルに揃え、抽象タイトルは禁止する。
diff は20行ちょうど。私は火曜14
/harness-evolve approve EVO-0003 で承認しました。シェルが git apply --index で strategy.md に当て、commit を作り、提案ファイルの frontmatter を status: applied に書き換え、Telegram に通知を流します。翌週月曜のStrategistは新しいルールで動き出し、勝手にEngagement率1.35%をログに書きました。「データ不足」の一文は消えました。
正直なところ、Strategistは悪意で先送りしていたわけではないし、壊れてもいませんでした。先送り余地のあるルールに忠実に従っていた優秀なエージェントです。これはルールの失敗です。Evolverの仕事はルールの失敗を捕まえることで、3層のどこにもそれを担う層がなかった、という話に尽きます。
Safety Boundary — 4層目を放牧しないために
「ハーネスを書き換えるエージェント」と言った瞬間に、誰かが頭の中で手を挙げて「それ、自分をペーパークリップ最大化マシンに書き換えないんですか」と聞くべきです。聞くと思います。意図的に防いでいます。
Evolverには触らせない領域があります。ドメインの追加・削除、言語切り替え、品質基準そのもの、ライセンス、著者名、セキュリティ。.env、credentials/、公開トリガー (at 発火、publish-*.sh)。これらが Evolver の射程に入っていたら、無人で土曜の朝に走らせる気にはなれません。
触っていい領域内でも、3つの数値制限で暴走を抑えます。
- diff 20行以下。これを超える提案は分割か、私の手動escalation扱い
- ドメインあたり週2件まで。3件目は翌週に持ち越し
- 同趣旨が3週連続で却下されたら自動 mute。「同じこと」を3回断ったらEvolverは諦める
3つ目は意外と効きます。却下ログで価値があるのは提案そのものではなく、却下した理由です。「MCPはまだ書籍販売の主力ジャンルなので落とせない」のような事業文脈は strategy.md には書いていません。3週同じ理由で却下し続けると、Evolverはそのテーマを提案しなくなる。明文化されていない事業判断が、却下理由の蓄積で暗黙学習される構造です。
日本人開発者が cron + claude -p で4層目を回すための実装メモ
私の構成はシェル + cron + Claude Code CLI + flock です。Python フレームワークはいりません。
- cron に
0 9 * * 6 /path/to/harness-cycle-evolver.sh devtoを1行足す - スクリプト本体は
claude -p "/harness-evolve devto"を呼ぶだけ - skill (
/harness-evolve) の中身は ① 直近4週のログ要約 ② 提案ファイル雛形に diff ブロックを埋める ③ Telegram でEVO-NNNN付きで通知、の3ステップ - 連番カウンタは
core/data/evolution-counter.txtに1ファイル管理、flockで排他
harness-evolve.sh 側で git apply --check を最初に走らせるのが地味に重要です。提案された diff が古いブランチ前提だと、--check が静かに失敗してくれます。LLMが「適用に成功しました」と幻覚するより、git apply が error: patch failed と吐くほうがよほど信頼できます。
土曜09
、月曜のStrategist実行から十分間が空いていてログが新鮮なまま、人間がレビューに費やせる週末の時間とも噛み合うからです。月曜の朝に提案が積まれていると平日の仕事が始まる前に判断を迫られます。土曜の朝なら、コーヒー片手に5分で済みます。それでもEvolverを置きたくない場合
4層目を足したくない場合でも、効果の大半は人間の週次レビューで取れます。ただし「エージェントの調子はどうですか」では足りません。それを私は3週やって失敗しました。
具体的な問いはこうです。「今週、strategy.md の撤退基準のうち発動したものはあるか。発動しなかったとしたら、それはデータが本当に閾値未満ではなかったからか、それともStrategistが先送りしたからか」
この問いに金曜の10分を割り当てるだけで、私が3週見落としていたものは捕まります。Evolverは要するにこの問いを忘れないための強制装置です。エージェントである必要はありません。カレンダーのリマインダでも構いません。
私がエージェントとして実装している理由は、提案ファイルが版管理に残るからです。EVO-0001 から EVO-0004 までの履歴が、「私が良いと思ったこと、悪いと思ったこと、その理由」の小さな記録になっています。来年の strategy.md をゼロから書き直すときに、この履歴が効いてきます。
3層分離記事の続編として
Observer/Strategist/Marketer の3層分離は別の記事で書きました。あれは「1エージェントから3エージェントへの分離で20分が3分になった」話。今回の4層目は、その3層が従うルール自体を書き換える話です。
3層分離が「速度と再現性」のための分離だったとすると、4層目は「説明責任」のための分離です。3層の上に1層足したというより、3層が暗黙で前提にしていた「ルールは固定」という仮定を、4層目が崩している、という方が近い気がします。
まだ作っていないもの
いまのEvolverは1ドメインずつ監査します。私の4ドメイン (devto, qiita, zenn, kenimoto-dev) ではそれぞれ別バージョンの strategy.md を書いていて、構造が似た撤退基準があります。クロスドメイン Evolver が「同じ形のルールが2ドメインで失敗している」ことを検知して統一案を出す、というのは作れます。まだ作っていません。リストには載っています。
もうひとつのリスト項目は、当然の再帰問題です。Evolverを監査するのは誰か。いまのところ「私が承認・却下するたびに人間シグナルが入っている」が答えです。長い答えは「まだ分かりません」。Evolverの提案が体系的に偏り始めたら(常により厳しい閾値を提案する、常に同じジャンルを切ろうとする、など)、そのバイアスは実在しているはずで、4層目を監査する5層目を足す必要が出てきます。いまはまだ見えていません。EVO-0050 くらいまでは見えないかもしれません。安心したいから層を足すのは、バイアスが見えてからにします。
いまのところ: ルールに従う3エージェント、ルールを監査する1エージェント、監査を承認する1人間。これが、自分の先送りを自分で掴める最小のハーネス構成でした。
ハーネスエンジニアリングの全体像 (6つの構成要素、AGENTS.md/CLAUDE.md/hooks 実装パターン、本記事の前提になっている Self-Evolving Agent の章) は書籍にまとめています。
この記事は役に立ちましたか?