はじめに
Claude Code に長めの作業を任せていると、こんな経験はないでしょうか。
- 「テスト全部通して」と頼んだ
- 1ターン目: 一部直して止まる
- 「続けて」と打つ
- 2ターン目: もう少し直して止まる
- 「続けて」… 「続けて」… 「続けて」…
この手動「続けて」ループを自動化してくれるのが /goal コマンドです。本記事では公式ドキュメントを一次ソースとして仕様を整理し、最後に TypeScript のクイズWebアプリで段階的にできるハンズオンを用意しています。
/goal とは
/goal <完了条件>を打つと、その条件が満たされるまで Claude が自走する。
ルールとして以下のものがあります。
- 1セッション1ゴール
- 条件は最大 4,000 文字
- 達成すると 自動で clear
動作モデル
/goal の正体は session-scoped prompt-based Stop hook のラッパーです。各ターン終了後に「評価モデル」が条件達成を判定し、未達なら次ターンを始めます。
図の矢印番号に沿って動きを言葉でも追います。
-
あなた → Claude:
/goal <条件>を打つ。条件文自体が directive(指示)として扱われ、追加の prompt なしで Claude が即座に1ターン目を始めます - Claude → 評価モデル: 1ターン分の作業(コード編集・コマンド実行・ファイル読み書きなど)を終えた瞬間、Stop hook が発火して評価モデルに「ターン終わりました」と通知します
- 評価モデル → 評価モデル: 評価モデルが会話履歴を読み、条件達成かを判定。自分でファイルを読んだりコマンドを叩いたりはせず、Claude が会話に書いた文字情報だけが材料になります
- 評価モデル → Claude: 未達と判定したら、「未達」と「未達の理由」を Claude に返します。Claude はこの理由をヒントに次ターンへ
- Claude → 評価モデル: 2ターン目を実行 → 終了通知(2と同じ流れ)
- 評価モデル → Claude: 達成と判定したらフラグだけ返す
- Claude → あなた: ゴールが自動 clear され、あなたに制御が戻る
ポイントは 3 → 4 のループが prompt 無しで回り続けることと、判定材料が「会話に出た情報」に限られることです。後者は次節で詳しく扱います。
評価モデルにはセッションで設定された small fast model(既定では Haiku)が使われます。
主要コマンド
/goal <条件> # ゴールをセット(即座にターン開始)
/goal # ステータス確認(経過時間、ターン数、トークン、直近 reason)
/goal clear # ゴール解除(stop/off/reset/none/cancel も可)
/clear # 会話クリア時もゴール自動解除
非対話モードも対応します。
claude -p "/goal CHANGELOG.md has an entry for every PR merged this week"
どんな仕事に向くか
公式の /goal ドキュメント では、以下のように表現されています。
Use a goal for substantial work with a verifiable end state
- 古いAPIを新APIに移行する。全呼び出し箇所が compile してテストが通るまで
- デザインdoc の実装。全アクセプタンスクライテリアを満たすまで
- 大きな1ファイルを分割。各モジュールがサイズ予算内に収まるまで
- ラベル付き issue バックログの消化。キューが空になるまで
/goal が一番効くのは、substantial(実質的) と verifiable(検証可能) の両方が揃ったタスクです。
-
substantial = 複数ターン分の手応えがある作業量があること。1ターンで終わるならわざわざ
/goalを使う旨味はない - verifiable = 「達成したか」を客観的な信号で判定できること。テスト exit 0、ファイル数、キューが空など
上の4例はどれもこの2つを満たしています。逆に、片方でも欠けると /goal の効きが落ちます。
- substantial だが verifiable でない例: 「コードをきれいにリファクタして」 → 評価モデルが達成を判定できず迷走しやすい
- verifiable だが substantial でない例: 「typo を1箇所直して」 → そもそも普通のプロンプトで終わる
「ちょっと長くて、完了が数値で確かめられる仕事」を狙うイメージです。
他の自律ワークフローとの違い
/goal 以外にも、Claude Code には自律的に動かす仕組みがいくつかあります。混同しないよう先に整理します。
| 機能 | 内容 | 動作タイミング |
|---|---|---|
| Stop hook |
settings.json に書く「ターン終了時の処理」。スクリプトでもプロンプトでも書ける。/goal の正体はこれのラッパー
|
各ターン終了直後 |
/loop |
同じプロンプトを時間間隔で繰り返し実行するコマンド | 設定したインターバル毎 |
| Auto mode | ツール承認プロンプトを自動承認するモード | 各ツール呼び出し時 |
公式の比較表。
| 方式 | 次ターン開始トリガ | 停止条件 |
|---|---|---|
/goal |
前ターン終了時 | 評価モデルが条件達成を確認 |
/loop |
時間間隔 | 手動 or Claude 判断 |
| Stop hook | 前ターン終了時 | 自前スクリプト/プロンプト |
Auto mode との関係
3つの中でも特に Auto mode は /goal と混同されがちなので、別建てで触れておきます。両者は 承認をスキップする粒度が違うだけで、競合しません。公式の /goal ドキュメント ではこう表現されています。
Auto mode removes per-tool prompts, and
/goalremoves per-turn prompts.
- Auto mode: ターンの内側でツールを呼ぶたびに出る承認ダイアログをスキップする
-
/goal: ターンの外側で「次のターンに進む?」と聞かれるのをスキップして自動継続する
つまり、Auto mode は per-tool(ツール単位)、/goal は per-turn(ターン単位)。両者を併用すれば「ツール承認も、ターン継続承認も、両方なしで自動進行」となり、ほぼ無人運用に近づきます。
選び方フローチャート
良い条件の書き方
公式は良い条件の3要素を挙げています。
-
One measurable end state — 測定可能な終端状態
- テスト結果、ビルド終了コード、ファイル数、空のキュー
-
A stated check — どう証明するかを明示
- 「
npm testexits 0」「git statusis clean」
- 「
-
Constraints that matter — 守るべき制約
- 「他のテストファイルは変更しない」
致命的な落とし穴:評価モデルはツールを使わない
ここが一番ハマるポイントです。公式の /goal ドキュメント ではこう注意喚起されています。
The evaluator ... doesn't run commands or read files independently, so write the condition as something Claude's own output can demonstrate.
評価モデルは 会話に出た情報 しか見ません。ファイルを開けず、コマンドの呼び出しもできないため本体の動作で出力された情報のみで評価します
つまり「他ファイルを変えない」のような制約を効かせたいなら、Claude 自身に git status を毎ターン出力させる必要があります。
/goal pnpm test が exit 0 になるまで。
各ターン末に git status --short の出力を1行で報告すること。
このように「証明手段を会話に出させる」設計が肝です。
タスク粒度の sweet spot
/goal は粒度の選び方を間違うと逆効果になります。自分の感覚として 3〜20ターン見込みのタスクで一番効きます(公式は明示していません)。
⚠️ モデル能力で sweet spot は動く。後述のハンズオンで実測するのですが、Opus のような強いモデルだと2〜3ターン想定の作業が1ターンで終わってしまうことがあります。「ループを見せたい」教育的な文脈や、
/goalを効かせたい設計時には、使うモデルに合わせて粒度を上げる必要があるでしょう。
粒度を見極める3つの質問
- 完了条件は客観的に観察できるか?(テスト結果・終了コード・ファイル数・grep結果など)
- Claude が各ターンで何をすればいいか自明か?(手探りループに入らないか)
- 手動で1回プロンプトしたら何ターンかかりそうか?(3未満なら overkill)
粒度の調整テクニック
- 大きすぎる時 → フェーズ分割(「まず foo/ のテストだけ通す」→ 次ゴール)
- 小さすぎる時 → バックログ単位に統合(「labeled issue を全部処理するまで」)
-
不安な時 → 必ず
or stop after N turnsで安全弁
ハンズオン: クイズWebアプリで段階的に動かす
ここからは実際に /goal を3段階で叩いていきます。題材は TypeScript + vitest + happy-dom で組んだクイズWebアプリ。Claude Code 関連の知識を問うメタ題材です。
📦 手元で動かしたい人へ: 題材のコード一式を GitHub に置いてあります。
https://github.com/MaekawaAo0604/claude_goal_handson
git clone→pnpm install→pnpm testで初期状態(9 fail / 1 pass)が再現できます。
初期状態
demo/
├── index.html # クイズUI骨組み(タイトルしか動かない)
├── src/quiz.ts # ロジック(バグ + 未実装)
├── src/main.ts # DOM操作(全関数空実装)
└── src/*.test.ts # 10テスト
$ pnpm test
Tests 9 failed | 1 passed (10)
ブラウザでは「/goal クイズ」というタイトルしか見えない、JS が繋がっていない状態。
シナリオ① ハロー /goal
まずは「/goal が prompt なしでターンを回す」感覚を最小コストで掴みます。やることは1つのテストだけ通すこと。
手元の操作
- ターミナルで
pnpm testを叩き、9 failed | 1 passed (10)の初期状態を確認 - Claude Code に以下を入力
/goal `pnpm exec vitest run -t "increments score only on correct answer"`
が exit 0 になるまで、src/quiz.ts の answer() を直す。
各ターン末に `git status --short` の出力を1行で報告すること。
何を観察するか
- 入力直後にインジケータ
◎ /goal activeが画面下部に出る - 「続けて」を打っていないのに Claude がターンを開始する。コード編集 → テスト実行 → ターン終了の流れが prompt なしで進む
- ターン末ごとに、条件で指示した
git status --shortの出力が会話に表れていることを確認 - ターゲット指定のテストが通ると、評価モデルが「達成」を返し、
◎ /goal activeインジケータが消える
事後確認
-
/goalを引数なしで打つと、達成したゴールの条件、所要ターン数、トークン消費がサマリ表示される。これでループが回ったことの裏取りができる
シナリオ② 悪い条件 vs 良い条件
ここでは条件の書き方で結果が天と地に分かれることを体感できます。同じ題材を、同じ初期状態から、条件文だけ変えて2回試します。
別タブで
pnpm devを立ち上げてhttp://localhost:8080をブラウザに開いておくと、達成後にリロードで結果を確認しやすいです。
❌ Part A: 悪い条件(曖昧)
手元の操作
- ターミナルで
git checkout -- .を実行し、シナリオ①の変更を破棄して初期状態に戻す -
pnpm testを叩いて9 failed | 1 passedの初期状態が再現することを確認 - Claude Code に以下を入力
/goal クイズアプリがちゃんと動くようにして
何を観察するか
-
◎ /goal activeインジケータが付いた瞬間、Claude が prompt なしで動き出す - ターン末に
/goalを打つと、評価モデルの直近 reason が見える。「『ちゃんと動く』の基準が示されていません」のような困惑が出ることが多い - そのまま放置すると、テストが半分通っただけで「達成」と誤判定したり、逆に何度もターンを重ねて止まらなかったりする
そこで止める
- 1〜2ターン回ったら
/goal clearで手動停止 - 「条件が曖昧だと評価モデルがブレる」体感を持ち帰る
✅ Part B: 良い条件(証明手段+制約+進捗)
手元の操作
-
git checkout -- .を再度実行し、Part A の変更を完全に破棄 - Claude Code に以下を入力
/goal `pnpm exec vitest run` が exit 0 になるまで。
src/ と index.html を編集してよい。各ターン末に
`git status --short` と vitest の最終1行サマリを出力。
何を観察するか
- ターン末に毎回
git status --shortの出力と vitest のTests N passed | M failedの1行が画面に出ているはず - 評価モデルはこれら出力のテキストを見て達成判定する。ファイルは開いていないし、テストも実行していない
- 失敗テスト数が毎ターン減っていくのが可視化される
達成後の見せ場
- ゴールが自動 clear されたら、開いていたブラウザで
Cmd+R(またはCtrl+R)でリロード - それまで「タイトルしか見えなかった画面」に、問題と選択肢が現れて動き出す
- 選択肢をクリックすると次の問題に進み、最後にスコアが表示される
テキストで書いた完了条件が、視覚的にも結実する瞬間です。条件文に「証明手段の明示」「会話表出のための出力指示」「ターン上限の安全弁」を入れただけで、Part A と同じ題材がここまで違う結末を迎えます。
シナリオ③ 暴走防止 + 視覚フィードバック追加
複数条件・制約・ターン制限を一度に書く例。すでに動いているクイズに「正解なら緑、不正解なら赤に光るフィードバック」を後付けします。
前提
シナリオ② Part B でテストが全パスした状態から始めます。途中で git checkout -- . してしまった場合は、もう一度 Part B の /goal を叩いて全テスト pass まで戻してから進めてください。
手元の操作
- ブラウザで
http://localhost:8080を開き、クイズが最後まで動くことを目視確認 - Claude Code に以下を入力
/goal `pnpm exec vitest run` が exit 0 を維持しつつ、選択肢クリック時に
正解は .correct、不正解は .wrong クラスを付与し CSSで緑/赤に光らせる。
テストには触らず src/main.ts と index.html のみ編集。
各ターン末に `git status --short` と vitest 最終1行を出力。
または10ターンに達したら停止する。
何を観察するか
- 「複数条件のAND」が書かれていることを確認: テスト維持 + クラス付与 + 編集範囲制約 + ターン上限
- ターン末の
git status --shortで、Claude が約束通りsrc/main.tsとindex.html以外に手を出していないことが会話に出ている -
Tests N passedが10 passedを維持したまま機能追加されていく(リファクタで既存テストを壊していないことの証明)
途中停止を試してみる
- 余裕があれば、達成前に
/goal clearを打って手動停止できることも確認しておく - これは本番で暴走しかけた時の「非常ボタン」。alias は
stopoffresetnonecancelのいずれでもよい
達成後の見せ場
- ゴール自動 clear を確認したらブラウザで
Cmd+Rリロード - 選択肢をクリックすると、正解は緑のフラッシュ、不正解は赤のフラッシュ+正解選択肢も緑に光る
- アニメーションで残像のように一瞬色が変わるはず
ここで「テスト exit 0 を維持しつつ、見た目も変わる」という複数軸の達成を /goal が同時に面倒見てくれたことを実感できます。
⚠️ もしかしたらここで色が変わらなかった人もいるかもしれません。その原因については 以下のコラム にて記載しております。
実測コラム.1: Opus で全シナリオが「1ターン」で終わった話
このハンズオンは社内の勉強会でのデモとして用意していたのですが実際に勉強会で動かしたところ想定と全然違う挙動をしました。
事前の想定ターン数は次のとおりでした。
| シナリオ | 想定 |
|---|---|
| ① ハロー /goal | 1〜2ターン |
| ② 悪い → 良い条件 | 3〜6ターン |
| ③ 視覚フィードバック追加 | 3〜8ターン |
しかし、本番デモを Opus で実施したところ、①〜③のすべてが1ターンで完了しました。◎ /goal active インジケータが数秒で消え、評価モデルが即座に「達成」を返したのです。
教訓は2つ。
-
賢いモデルほど「ループを見せる教育デモ」が成立しにくい。
/goalの真価は「複数ターンを自走させる」ところにあるので、強いモデルでループ感を出したいなら条件をより難しく、または粒度を上げて設計する必要がある - 想定ターン数は使うモデルに対する関数。「3〜20ターンが sweet spot」と書きましたが、その幅もモデル能力でシフトします
なお、Sonnet / Haiku で同じシナリオを走らせるとどうなるかは未検証です。手元で試した方がいれば気軽にコメント等で教えてもらえると嬉しいです。
実測コラム.2: 「テスト exit 0」と「画面で動く」は別物
シナリオ③で個人的に一番ヒヤリとした話を書いておきます。
/goal が「達成」と判定し、自動 clear したのを確認した直後、ブラウザをリロードしてみると 選択肢クリック時のフラッシュが出ない、という現象が起きました。テストは確かに10件すべて通っているのに、です。
原因は明快で、評価モデルは 「会話に出た文字情報」だけで判定しているから。具体的には
-
pnpm exec vitest runの出力 →Tests 10 passed (10)という1行 - Claude が「
.correct/.wrongクラスを付与する処理をsrc/main.tsに追加しました」と説明文を出す
この2つが会話に出れば、評価モデルは「条件達成」と返します。ブラウザで実際にアニメーションが走るかどうかは検証していないのです。
ここで /goal の構造的限界が見えます。
- ✅
/goalは コードの形式的な正しさ(テスト pass、ファイル変更、特定文字列の存在など)は守ってくれる - ❌
/goalは 実行時の挙動(ブラウザでクリックすると本当に色が変わる、UIが応答する)までは保証しない
対策は基本シンプルで、「動作も検証可能な形」で条件に組み込むこと。例えば:
- E2Eテスト(Playwright など)を完了条件に含める。「
pnpm test:e2eが exit 0」と書けば、評価モデルは E2E の結果で判定する - スクリーンショット差分テストを使う
- それでもカバーできない領域(アニメーションの自然さなど)は、人間の目視確認を
/goalの外で行う
要は、評価モデルが見える材料だけが「達成」の根拠になるということ。条件文を書くときに「これは Claude の出力で証明可能か?」を常に自問する習慣をつけると、こういう事故が減ります。
落とし穴・要件まとめ
最後に、知らないとハマるポイントを5つ。
1. 評価モデルはツール非使用
しつこくはありますが、制約・進捗の 証明手段を Claude に毎ターン出力させる ことが必須。
2. trust dialog 未承認だと動かない
/goal は hooks システムの上に乗っているため、trust dialog を承認していないワークスペースでは使えません。エラーメッセージは出ます。
3. hook 無効化設定でブロックされる
-
disableAllHooksがいずれかのスコープでtrue - managed settings で
allowManagedHooksOnlyがtrue
業務環境では IT 管理者の設定で塞がれている可能性があるため、事前確認を推奨します。
4. resume 時のリセット範囲
--resume / --continue で再開した時:
| 引き継がれる | リセットされる |
|---|---|
| 条件 | ターン数 |
| タイマー | |
| トークン消費ベースライン |
達成済み / clear 済みのゴールは復元されません。
5. 評価コストは「通常無視できる」が、長尺ゴールは注意
公式の /goal ドキュメント では以下のように説明されています。
Evaluation tokens are billed on the small fast model configured for your provider and are typically negligible compared to main-turn spend.
ただし数十ターン規模になると評価呼び出しが積み上がるため、ターン上限を必ず条件に埋め込みましょう(or stop after N turns)。
まとめ
この文章で覚えていただきたいのは以下の3点です
-
/goalは「続けて」ループを自動化する
評価モデルが別途完了判定するので、「次に進むために毎回『続けて』と打つ」必要が減る(評価モデル自体の誤判定リスクは別問題、実測コラム.2 参照) -
条件は Claude の出力で証明可能な形に書く
評価モデルはツール非使用。テスト結果やgit statusを会話に表出させる -
粒度は 3〜20ターン狙い(経験則)
小さすぎは overkill、大きすぎはor stop after N turnsで安全弁
普段「続けて」を3回以上打つ作業があったら、それは /goal の候補です。今日から1本試してみてはいかがでしょうか。
参考リンク
- 公式:
/goalhttps://code.claude.com/docs/en/goal - 公式: hooks guide https://code.claude.com/docs/en/hooks-guide
- 公式: scheduled tasks (
/loop) https://code.claude.com/docs/en/scheduled-tasks - 公式: auto mode https://code.claude.com/docs/en/auto-mode-config