テストが通るまで「もう一回やって」「やっぱりここ直して」を、私は手で何度も打ち込んでいました。1 回の出力では終わらないタスクに付きっきりで、再実行のトリガーを毎回自分で引いています。出力を見て、直すべき箇所を指摘して、また実行して、また見て。気づけば「Claude に任せたはずの作業」を、私が監督として張りついて回していました。
シリーズ #14 毎朝同じチェックを Claude に投げ直す生活 で扱ったのは「定刻に投げ直す」時間軸の自動化でした。本記事はその縦の繰り返し、つまり 「完了するまで止まらない」ループ です。鍵になるのが Ralph Wiggum(ラルフ・ウィッグム)という手法と、Anthropic の公式プラグイン ralph-wiggum です。
TL;DR
- Ralph Wiggum は「同じプロンプトを、完了するまで AI に投げ続ける」手法です。ジェフリー・ハントレーの「Ralph はただの Bash ループだ」が原典で、転んでも立ち上がるシンプソンズのキャラクターから名前を取っています
- Anthropic の公式プラグイン ralph-wiggum があります。
/ralph-loop "タスクの説明" --completion-promise "DONE" --max-iterations 20の 1 行で始まります - 仕組みは Stop hook(Claude がターンを終えて終了しようとした瞬間に発火する hook。詳細は #11 Hooks 入門)です。終了を差し止めて、同じプロンプトをそのまま投げ返し、
<promise>DONE</promise>が出るまで回します - 「完了まで働かせる」公式の手段は 3 つあります。時計が止め時を決める
/loop(#14)、モデルが条件成立を判定する/goal、自分のスクリプトが判定する Stop hook(= Ralph)です - 罠は 4 つ。完了条件が曖昧だと止まらない/
--max-iterationsを付け忘れる/嘘の合言葉で抜けさせる/既存の大規模コードには向かない - 今週やる 1 つ: テストが通るまで自走させる小さな新規タスクで、
--max-iterations 10を付けて 1 回試す
「もう一回」を手で何度も打ち込んでいませんか
白状します。テスト駆動開発(TDD、先にテストを書いてから実装を進める方法)で小さな API を書かせるとき、私の手元はこう動いていました。
- 「テストを先に書いて、それから実装して」と投げる
- テストが 3 件落ちる。「この 3 件を直して」と打つ
- 2 件は通った。1 件はまだ落ちている。「残りを直して」と打つ
- 通った。「ついでに型注釈も付けて」と打つ
1 発で完璧を求めず、失敗を見てから直す進め方そのものは正しいはずです。問題は、その「失敗を見て、もう一度投げる」のトリガーを毎回私が手で引いていることでした。Claude は失敗を直す能力を持っているのに、直すきっかけを与える係として私が張りついています。
似た構造に心当たりはないでしょうか。リファクタリングで「まだ重複が残ってる、もう一回」を 5 回打つ。ドキュメントの整形で「ここの表記が揺れてる、直して」を繰り返す。どれも、AI の能力ではなく、人間の手数で回しているループです。
前回の #14 で扱ったのは「定刻になったら投げ直す」でした。今回ほしいのは「終わっていなければ投げ直す」です。
問題は「何回やり直すか」ではなく「いつ止めるか」を誰が決めるか
繰り返し実行の話には、軸が 2 つあります。「いつ再実行するか」と「いつ止めるか」 です。
シリーズ #14 の /loop が答えていたのは前者でした。5 分おき、あるいは Claude が動的に選んだ間隔で、時計が再実行のタイミングを決めます。止め時は人間がセッションを閉じるか、7 日の失効を待つか、でした。
完了するまで自走させたいなら、答えるべきは後者です。「いつ止めるか」を機械に委ねる。そして、その止め時を判定する者には 3 通りの選択肢があります。
- 時計に決めさせる(
/loop、#14 で扱った) - モデルに条件成立を判定させる(
/goal) - 自分で書いたスクリプトに判定させる(Stop hook)
このうち 3 番目、「自分のスクリプトが、決めた合言葉が出るまでループを止めない」 を最小の仕掛けで実現するのが Ralph Wiggum です。
Ralph Wiggum とは「ただの Bash ループ」
Ralph Wiggum という名前は、シンプソンズに登場する少年ラルフ・ウィッグムから来ています。何度つまずいても気にせず立ち上がる、その粘り強さが手法の精神を表しています。
提唱者のジェフリー・ハントレーは、この手法を一言で「Ralph はただの Bash ループだ」と説明しています(ghuntley.com/ralph、非公式の原典)。実体は、次の 1 行がすべてです。
while :; do cat PROMPT.md | claude-code ; done
同じプロンプトファイルを、AI エージェントに延々と食わせ続けるだけのループです。たとえば shanraisshan/ralph-wiggum-self-evolving-loopの ralph.sh は、回数を区切った for ループの中で claude -p(プロンプトを 1 回だけ渡して結果を返す非対話モード)を呼び、出力に <promise>COMPLETE</promise> が現れたら抜ける、という構造でした。
for ((i=1; i<=$1; i++)); do result=$(claude -p "$(cat "$PROJECT_ROOT/prompt.md")" --output-format text 2>&1) || true echo "$result" if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then echo "見つかった、$i 回目で完了" exit 0 fi done
ハントレーはこの手法を「不確実な世界で、決定論的にダメ(deterministically bad)」と表現しています。1 回ごとの出力は荒いですし、外すこともあります。でもその失敗は予測可能なデータで、プロンプトをギターの弦のように少しずつ調律していけば、いずれ収束する、という考え方です。失敗をエラーとして恐れるのではなく、次の改善のための材料として扱います。
実際の成果として、公式プラグインの説明には次の例が並んでいます。
- Y Combinator のハッカソンで、一晩に 6 つのリポジトリを生成した
- ある 5 万ドルの案件を、API 利用料 297 ドルで仕上げた
- 3 か月かけて独自のプログラミング言語(cursed)を作っている
そして、この素朴なループを Anthropic が公式プラグインとして仕立て直しました。
公式 ralph-wiggum プラグインの正体は Stop hook
ralph-wiggum は、Anthropic の公式リポジトリ anthropics/claude-code に含まれるプラグインです。外部の Bash ループと決定的に違うのは、今開いているセッションの中だけで回る ことです。while true を別ターミナルで走らせる必要はありません。その仕掛けが Stop hook です。
まず入れ方です。公式マーケットプレイスを追加して、プラグインをインストールします。
/plugin marketplace add anthropics/claude-code /plugin install ralph-wiggum@claude-code-plugins
使うときは 1 行です。タスクの説明、完了の合言葉、反復回数の上限を渡します。
/ralph-loop "ToDo の REST API を作る。要件: CRUD 4 操作・入力バリデーション・テスト。すべて満たしたら <promise>COMPLETE</promise> と出力する。" --completion-promise "COMPLETE" --max-iterations 50
これを 1 回叩くと、あとは Claude が自分で回します。API を実装し、テストを走らせ、落ちたら直し、要件を満たすまで反復し、満たしたら合言葉を出して止まります。
中で何が起きているかを順に追います。
/ralph-loopが状態ファイル.claude/ralph-loop.local.mdを作ります。中身は YAML frontmatter(ファイル先頭の---で囲んだメタ情報欄)に反復回数・上限・完了の合言葉を持ち、その下に渡したプロンプト本文が入ります- Claude がタスクに取り組み、ターンを終えて終了しようとします
- その瞬間に Stop hook(
hooks/stop-hook.sh)が発火します。状態ファイルがあれば、終了を差し止めます - 直前の出力に
<promise>...</promise>があり、中身が完了の合言葉と完全一致すれば、状態ファイルを消してループを終えます。一致しなければ、同じプロンプトをそのまま投げ返します - 反復回数を 1 つ増やし、上限に達していれば停止します
差し止めと投げ返しの実体は、Stop hook が返す JSON です。公式の stop-hook.sh は、完了でも上限到達でもないとき、こう出力します。
jq -n \ --arg prompt "$PROMPT_TEXT" \ --arg msg "$SYSTEM_MSG" \ '{ "decision": "block", "reason": $prompt, "systemMessage": $msg }'decision: block で終了をブロックし、reason に最初のプロンプトをそのまま入れて返します。これが「同じプロンプトを完了まで投げ続ける」の正体です。hook が exit code と stdout で decision を返す仕組み自体は #11 Hooks 入門 で扱った通りで、Ralph はその Stop イベントを完了条件ループに使っているだけです。
図にすると 1 枚に収まります。
flowchart TD Start(["/ralph-loop でタスクを渡す"]) --> State["状態ファイル<br/>.claude/ralph-loop.local.md<br/>(反復回数・上限・完了の合言葉)"] State --> Work["Claude がタスクに取り組む<br/>ファイルを編集・テストを実行"] Work --> Exit["ターンを終えて<br/>終了しようとする"] Exit --> Hook{"Stop hook が判定"} Hook -- "完了の合言葉が出た" --> Done(["ループ終了<br/>状態ファイルを削除"]) Hook -- "上限回数に到達" --> Stop2(["強制終了<br/>状態ファイルを削除"]) Hook -- "どちらでもない" --> Feed["同じプロンプトを<br/>そのまま投げ返す<br/>(decision: block)"] Feed --> Workこの自己参照ループの肝は、プロンプトが毎回まったく同じ ことです。変わるのは Claude が触ったファイルと git の履歴だけ。Claude は次の反復で、自分が前回書いたコードやテスト結果をファイルから読み直し、そこを起点に改善します。指示を変えていないのに前進するのは、過去の自分の仕事が成果物として残っているからです。
生 Ralph と公式プラグインの違い
「生の Ralph」(外部の Bash ループ)と公式プラグイン(セッション内の Stop hook)は、同じ思想ですが文脈の扱いが違います。
| 生 Ralph(外部ループ) | 公式プラグイン(Stop hook) | |
|---|---|---|
| 回し方 | 別ターミナルで while / for ループ | 今のセッション内で /ralph-loop 1 行 |
| 1 回ごとの実行 | claude -p をまっさらな状態で起動 | 同じセッションでターンを継続 |
| 会話の文脈 | 毎回リセット。記憶はファイルと git だけ | セッションに蓄積する |
| 前回作業の引き継ぎ | ファイル・git 履歴を読み直す | ファイル・git 履歴 + 会話文脈 |
| 止め方 | ループ条件 or プロセス停止 | /cancel-ralph(状態ファイルを消す) |
どちらも「作業がファイルに残る」ことが前提です。違いは会話文脈を持ち越すかどうか。生 Ralph は毎回まっさらなので、文脈の汚れが溜まらず長く回せます。一方、公式プラグインは会話文脈を引き継ぐので、直前のやり取りを覚えたまま反復できますが、回し続けると文脈が膨らみます。
止めたいときは /cancel-ralph を実行します。状態ファイル .claude/ralph-loop.local.md を削除するだけのコマンドで、ファイルが消えれば次の Stop hook は素通りし、ループが終わります。
「完了まで働かせる」公式 3 手段の使い分け
ここまで Ralph(Stop hook)を見てきましたが、「完了まで Claude を働かせる」公式の手段はほかにも 2 つあります。/goal の公式ドキュメントには、この 3 つを並べた比較が載っています。日本語に整理するとこうなります。
止め時を判定する者で言い換えると、モデル(/goal)・時計(/loop)・自分のスクリプト(Stop hook) の 3 択です。/goal と Stop hook はどちらもターンが終わるたびに発火しますが、/goal はセッション限定の手軽な近道(条件を打つとそのセッションだけ有効)で、Stop hook は設定ファイルに住み続ける常設の仕掛け、という違いがあります。
使い分けの目安はこうなります。
- 完了条件を自然な日本語で書けて、その判定をモデルに任せたい →
/goal - CI やデプロイのような外部の状態を、一定間隔で見張りたい →
/loop(#14) - 「この合言葉が出たら完了」を厳密に決めて、テストが緑になるまで自走させたい → Ralph(Stop hook)
/goal は #14 でも「条件を満たすまで会話を続けたい場合」として 1 行だけ触れました。Ralph との距離が近い手段なので、別途あらためて扱います。本記事は「合言葉で止める Ralph」に絞ります。
良いプロンプトの書き方 4 原則
Ralph の成否は、モデルの賢さより プロンプトの書き方 で決まります。公式プラグインの説明にある 4 つの原則を、実例とともに見ます。
- 完了条件を明確にする
「ToDo API を作って、いい感じにして」では、いつ終わりか機械に判定できません。チェックリストと合言葉で締めます。
ToDo の REST API を作る。 完了条件: - CRUD 4 エンドポイントが動作する - 入力バリデーションが入っている - テストが通る(カバレッジ 80% 超) - README に API ドキュメントがある - 出力: <promise>COMPLETE</promise>
- ゴールを段階に割る
「完全な EC サイトを作って」のような巨大な一塊は、ループが収束しません。フェーズに分けます。
フェーズ 1: ユーザー認証(JWT、テスト) フェーズ 2: 商品カタログ(一覧・検索、テスト) フェーズ 3: カート(追加・削除、テスト) すべてのフェーズが終わったら <promise>COMPLETE</promise> と出力する。
なお JWT(ログイン後にサーバが発行する署名付きトークン)のような略語は、プロンプト内でも初出時に補っておくと、反復のたびに解釈がぶれません。
- 自己修正を仕込む
「機能 X のコードを書いて」だけだと、書いて終わりになります。直す手順まで指示します。
機能 X を TDD で実装する: 1. 失敗するテストを書く 2. 機能を実装する 3. テストを走らせる 4. 落ちたらデバッグして直す 5. 必要ならリファクタする 6. すべて緑になるまで繰り返す 7. 出力: <promise>COMPLETE</promise>
- 脱出口を用意する
不可能なタスクで無限に回り続けないよう、--max-iterations を必ず付けます。公式も第一の安全装置として必須だと書いています。
# 推奨: 必ず妥当な反復上限を設定する /ralph-loop "機能 X を実装する" --max-iterations 20
プロンプト側にも、詰まったときの振る舞いを書いておくと安全です。たとえば「15 回反復しても完了しないなら、何が進行を妨げているか・何を試したか・別案を文書化して止まる」のように指示します。
罠 4 つ
罠 1: 完了条件が曖昧で、いつまでも止まらない
--completion-promise は 完全一致 で判定されます。stop-hook.sh の中身を見ると、ワイルドカード照合(* などで曖昧に一致させる glob 方式)ではなく文字列リテラルの比較(=)で、<promise> タグの中身が合言葉と一字一句同じかを見ています。だからこそ合言葉は短く一意な文字列(DONE や ALL GREEN など)にします。逆に「いい感じになったら終わり」のような曖昧な完了条件をプロンプト本文に書いても、機械は判定できず、合言葉が出ないまま回り続けます。
罠 2: --max-iterations を付け忘れて止まらなくなる
合言葉も上限も設定しないと、Ralph は文字どおり無限に走ります。setup-ralph-loop.sh も起動時に「このループは手動では止められません。--max-iterations か --completion-promise を設定しない限り無限に走ります」と警告を出します。最初は必ず小さめの上限(--max-iterations 10 など)から始めて、挙動を見てから伸ばします。
罠 3: 嘘の合言葉でループを抜けさせてしまう
長く回ると、Claude が「もう十分だろう」と判断して、条件を満たしていないのに合言葉を出してしまう誘惑があります。公式はこれを明確に禁じています。/ralph-loop のコマンド定義にも「完了の合言葉は、その記述が完全かつ疑いなく真であるときにのみ出力してよい。詰まったと思っても、抜けるために嘘をついてはならない」と書かれています。状態ファイルを更新するたびに hook が出す画面メッセージにも、同じ警告(嘘で抜けるな)が添えられます。プロンプトを書く側も、合言葉を出す条件を検証可能な形(テストが緑・全要件を満たす)にしておくことが、この誘惑を断つ近道です。
罠 4: 既存の大規模コードベースに使う
Ralph が輝くのは、更地から作る新規プロジェクト(greenfield、既存コードのない状態から作るもの)で、テストや lint のような自動検証が効く場面です。ハントレー自身が「既存のコードベースで Ralph を使うことは絶対にしない」と言い切っています。完成度はおよそ 9 割を狙う前提で、最後の仕上げと設計判断は人間が担う、という温度感です。本番障害の調査のような、人間の判断が要る作業には向きません。
今週やる 1 つ
今週、私が最初に試すなら、小さな新規タスクで自走を 1 回体験します。単機能の CLI でも、エンドポイントが 2 つだけの小さな API でも構いません。テストが緑になるまで自走させるプロンプトを書いて、上限を低めに設定します。
/ralph-loop "Python で気温の単位変換 CLI を作る。摂氏・華氏・ケルビンを相互変換する。要件: 引数で変換元と変換先と数値を受け取る・不正入力はエラーメッセージを出す・pytest のテストを書き、全て通す。完了条件をすべて満たしたら <promise>ALL GREEN</promise> と出力する。" --completion-promise "ALL GREEN" --max-iterations 10
走らせている間、別ターミナルで今が何反復目かを覗けます。
grep '^iteration:' .claude/ralph-loop.local.md
10 回以内に ALL GREEN が出れば、テストが緑になるまで Claude が一人で直し切ったということです。出なければ、どこで詰まっているかが反復のログに残ります。そこを見て、完了条件かプロンプトの指示を調律してから、もう一度回します。失敗はエラーではなく、次の調律のためのデータです。
まとめ
1 回で終わらないタスクは、「完了まで止まらないループ」に乗せれば、付きっきりの再投入から抜けられます。要は、止め時の判定を誰に委ねるかです。時計に委ねるなら /loop(#14)、モデルに委ねるなら /goal、自分のスクリプトに委ねるなら Stop hook、つまり Ralph Wiggum です。
Ralph は Anthropic の公式プラグインになっていて、Stop hook が同じプロンプトを完了まで投げ直します。仕掛けは素朴な Bash ループと同じ思想で、過去の自分の仕事がファイルと git に残るから、指示を変えなくても前へ進みます。
シリーズ #13 Agent Teams は「同じ瞬間に複数の Claude を並べる」横軸、#14 Scheduled Tasks と Routines は「同じ Claude を別の時刻に起こす」縦軸でした。本記事はその先の「完了条件まで深掘りする」第 3 の軸です。新規プロジェクト・自動検証・反復上限。この 3 点さえ守れば、Claude は「呼ぶたびに監督が要る道具」から「合言葉が出るまで一人で粘るエージェント」に近づきます。
パイソンエンジニア部
