Claude Media
Claude Codeの/goalコマンド — 完了条件を渡して目標達成まで自走させる仕組み

Claude Codeの/goalコマンド — 完了条件を渡して目標達成まで自走させる仕組み

Claude Code v2.1.139の/goalコマンドの内部仕様。Stop hookとHaikuによる達成判定、3モードの使い分け、評価可能な条件文の書き方をまとめます。

背景

Claude Codeは通常、1ターンの応答を返すと人間の入力を待ちます。長い作業では「次へ」「続けて」と打ち続けることになり、CIや非対話の運用とは噛み合いませんでした。

v2.1.139で追加された/goalは、この待ち時間を条件で置き換えます。完了条件を1行で渡すと、Claudeはターンをまたいで作業を続け、条件が満たされたところで止まります。「いつ止めるか」を宣言として書けるのが特徴です。

条件を満たしたかどうかを決めるのは、作業しているClaude本人ではありません。ターンが終わるたびに別のモデルが会話を読んで判定します。この仕組みが、条件文の書き方と止まり方のすべてを左右します。

「ESLintエラーが0件になるまで直す」「テストが全部通るまでデバッグする」といった完了条件付きのタスクを、対話・-p(非対話)・デスクトップアプリ・Remote Controlのいずれからでも走らせられます。

コマンドの形と起動経路

3つの形

形式動作
/goal <完了条件>動作ゴールを設定(条件文は最大4,000文字)
/goal動作現在のゴールと評価状況を表示
/goal clear動作アクティブなゴールを解除

clearにはstop / off / reset / none / cancelのエイリアスがあり、どれも同じ意味です。会話を新しく始める/clearでも、アクティブなゴールは消えます。

同時に持てるゴールは1セッションにつき1つで、新しい/goalは前のゴールを置き換えます。/goalを入力した時点でターンが始まるので、別にプロンプトを送る必要はありません。条件文そのものが指示として扱われます。

/goal clearを実行すると、Goal cleared:に続けて条件が表示されます。ゴールが無ければNo goal setと返ります。

経路ごとの使いどころ

起動経路起動方法向いている場面
インタラクティブ起動方法通常のセッション内で/goalを実行向いている場面手元で他の作業をしながら、長い修正を任せる
非対話(-p)起動方法claude -p "/goal ..."向いている場面CIやバッチから完了条件付きのタスクを投げる
デスクトップアプリ起動方法アプリ内で/goalを実行向いている場面GUIで同じ運用をしたい
Remote Control起動方法Remote Controlで操作しているセッション内で実行向いている場面リモートから開いたセッションでも同じ条件文を使う

-pで設定すると、ゴールが解決するまでのループが1回の呼び出しの中で完走します。

claude -p "/goal CHANGELOG.md has an entry for every PR merged this week"

既定のテキスト出力は実行が終わるまで何も表示しないため、ターン数が多いと固まったように見えます。--output-format stream-json --verboseを付けると、ループの進行に合わせてメッセージが流れます。非対話で動くゴールはCtrl+Cで止められます。

ゴールが有効な間の表示

ゴールが有効な間は、◎ /goal activeのインジケータが出て、ゴールの経過時間を示します。引数なしの/goalでは、次の内容を見られます。

  • 現在の完了条件
  • 経過時間
  • 評価が走ったターン数と、現時点のトークン消費
  • 評価モデルが直近に返した理由

ターン数と直近の理由は、最初の評価が走った後に出ます。トランスクリプトには評価のたびに判定が残り、Ctrl+Oで理由まで読めます。

ゴールが達成済みのときも、同じセッションの中なら/goalで達成した条件・所要時間・ターン数・トークン消費を見返せます。

評価の流れと3つの判定

/goalは、セッション限定のprompt-based Stop hookを包んだ実装です。Claude CodeのHooksの仕組みの上に作られています。

手順

1ターンごとに起きること

  1. 1

    条件を渡す

    /goal <条件>で条件をセッションに登録します。条件そのものが最初のターンの指示になります。

  2. 2

    Claudeが作業する

    通常のターンと同じく、ファイルを読み、コマンドを実行します。実行結果は会話に残ります。

  3. 3

    ターン終了時に評価する

    条件と会話履歴が、設定済みのsmall fast model(haikuエイリアスに対応するモデル)に送られます。モデルは3つの判定のどれかと短い理由を返します。

判定

評価モデルが返す3つの判定

  • 未達

    Claudeは返された理由を次のターンの手がかりにして作業を続けます。

  • 達成

    ゴールが解除され、達成した記録がトランスクリプトに残ります。

  • 不可能

    条件が満たせないと評価モデルが判断した場合です。ゴールは自動で解除され、理由つきの失敗記録が残るので、自分で/goal clearを打つ必要はありません。

Claudeが評価に答えるだけでツールを使わないターンが何度も続くと、ループは警告を出して止まり、ゴールは設定されたまま制御が戻ります。次にプロンプトを送ると評価が再開します。

評価モデルはツールを呼ばない

評価モデルが読むのは会話の履歴だけで、BashやReadのようなツールは呼びません。そのため、条件は「Claudeの出力に証拠が現れる形」でなければ判定されません。

くらべる

同じ目的でも、書き方で判定の可否が変わる

NG

判定しにくい書き方

/goal mainブランチのCIパイプラインが通っている

評価モデルはCIを確かめに行けません。会話に「通った」という痕跡が出るまで、未達の判定が続きます。

OK

判定できる書き方

/goal npm test が exit 0 で npm run lint がエラーを出さない

Claudeがコマンドを実行し、結果が会話に残ります。評価モデルはその出力を根拠にできます。

「Claude自身がコマンドを実行して、結果を会話に残す」流れを条件文の中で設計する、という発想です。アプリ全体の成功基準を測定可能な形に定量化する考え方とも、根っこは同じです。

効く条件文の書き方

3つの要素

複数のターンにわたって成立する条件には、次の3つを入れておくと判定が安定します。

  • 測定可能な単一の終了状態: テスト結果、ビルドの終了コード、ファイル数、空になったキュー
  • 検証手段の明示: 「npm testがexit 0で終わる」「git statusがクリーンである」のように、Claudeが何で証明するか
  • 変更してはならない制約: 「他のテストファイルは変更しない」「mainには直接pushしない」

3つのうち、見落としやすいのが制約です。評価の指標だけを書くと、達成のために意図しないファイルを書き換える余地が残ります。

/goal `npm test` が exit 0 で `npm run lint` がエラーを出さない。ただし、テストファイル `*.test.ts` の中身は変更せず、実装側のみ修正すること

打ち切りラインを条件に含める

走り続ける時間を区切りたいときは、ターン数や時間の条件を文の中に入れます。Claudeは毎ターン、その条件に対する進捗を報告し、評価モデルは会話からそれを判定します。

/goal TypeScriptのエラーが全て解消、もしくは20ターン経過したら停止
/goal /docs/api/* の全エンドポイントに使用例が記載されている、もしくは5ターン進捗がなければ停止

権限モードは変わらない

/goalは権限モードを変えません。Manual modeのままなら、設定で許可していないツール呼び出し(たとえば上の例のテスト実行)は、これまでどおり確認を求めます。

席を離れて回すなら、auto modeで/goalを実行します。auto modeはツール承認のプロンプトを減らし、/goalはターン継続のプロンプトを減らす、という分担です。

止まった・動かないときの切り分け

ゴールが想定どおりに進まないときは、画面に出る文言から原因を絞れます。

画面の文言・症状原因次の一手
Goal cleared after an unrecoverable error原因認証失敗、クレジット残高の枯渇、自動コンパクトで解消しないコンテキスト超過、利用できないモデルのいずれか次の一手原因を直し、/goal <条件>で設定し直す
Goal still active原因サーバーの過負荷や接続断など、待てば直る失敗次の一手自動で再試行される。3回再試行しても直らなければ一時停止
Goal paused原因APIのレート制限、claude.aiの使用上限、フックによるターン終了など、再試行しても同じ失敗になるもの次の一手原因を取り除く。使用上限のリセット待ちに入っていれば、リセット後に自動で再開
評価がしばらく走らない原因サブエージェントやバックグラウンドのシェルが動いたまま次の一手バックグラウンド作業が無い状態でターンが終わった時点で評価される
/goalが使えない原因信頼していないフォルダ、disableAllHooks、allowManagedHooksOnly次の一手コマンドが理由を表示する

認証失敗でクリアされるのは、Claude Codeが自分で認証情報を管理している場合です。デスクトップアプリやクラウドセッションのようにホストが管理しているときは、ホスト側が復旧するためゴールは有効のまま残ります。同じ理由で未達が何十回も続く場合は、Stop hookの再発火の報告に症状と止め方があります。

Goal still activeとGoal pausedの通知は、インタラクティブなセッションでv2.1.269以降の場合に出ます。どちらの状態でも、メッセージを送ればすぐ次のターンが始まります。

最後の行にあるallowManagedHooksOnlyは、管理者がmanaged settingsで設定する項目です。企業環境では事前に確かめておく項目で、及ぼす連鎖的な影響はhookを組織限定にする際の連鎖的な影響にまとめています。

バックグラウンド作業を待っているとき

サブエージェントやバックグラウンドのシェルが動いたままターンが終わると、そのターンの評価は見送られます。作業が終わった結果は新しいターンとして届くので、自分でプロンプトを打つ必要はありません。

待ちが30分続くと、状況確認が入ります。確認では動いているタスクの一覧を示し、進んでいれば待つこと、止まっていれば直すか止めることをClaudeに促します。

2回目以降は間隔が2倍ずつ伸びます。既定では最初の確認の1時間後、その後は2時間おきです。アイドル中のセッションでは、確認のために自動でターンが始まり、1つのゴールにつきプロンプトの合間に最大3回までです。非対話では、ターン終了時の確認だけが使われます。

環境変数CLAUDE_CODE_GOAL_CHECKIN_MINUTESで最初の間隔を変えられ、0にすると確認と、先の表の自動再試行がどちらも止まります。

セッションを再開したとき

アクティブなゴールは、--continue、ID・名前・トランスクリプトのパスを渡した--resume、セッション一覧からの再開のどれでも復元されます。セッション一覧からの復元はv2.1.239で加わりました。それ以前は、一覧から選ぶ経路だけが復元されませんでした。

復元されるのは条件だけで、ターン数、タイマー、トークン消費の基準値はゼロに戻ります。達成済み、または解除済みのゴールは復元されません。

CIで回すときの設定

非対話モードを使うと、CIから完了条件付きのタスクを投げられます。

# .github/workflows/claude-autofix.yml(概念的な例)
- name: Run Claude until lint passes
  run: |
    claude -p "/goal \`npm run lint\` のエラーが0件、もしくは30ターン経過で停止" \
      --max-turns 30 \
      --max-budget-usd 5 \
      --output-format stream-json --verbose
  env:
    CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

条件文の中の「30ターン」は評価モデルが会話から読み取る打ち切りで、--max-turnsはCLI側の上限です。--max-turnsは非対話モード専用で、上限に達するとエラーで終了します。

予算の上限も別に持てます。v2.1.287のclaude --helpには、次の行が出ます。

claude --version
claude --help | grep -A1 max-budget-usd
2.1.287 (Claude Code)
  --max-budget-usd <amount>             Maximum dollar amount to spend on API
                                        calls (only works with --print)

同じclaude --helpに--max-turnsの行は無く、CLIリファレンスに載っています。ヘルプ一覧だけを頼りにすると見落とすフラグです。

Claude Code RoutinesのGitHubトリガーと組み合わせれば、PRの作成を契機に「テストが全部通るまで修正」を走らせる流れも組めます。

/loop・Stop hook・自動モードとの使い分け

似た目的の仕組みと並べると、違いは「次のターンを何が始めるか」に集約されます。

観点/goal/loopStop hook自動モード
次のターンが始まる契機/goal前のターンの終了(対話セッションでは、待機中の確認や再試行の時刻)/loop時間間隔の経過Stop hook前のターンの終了自動モード新しいターンは始めない
止まる条件の判定/goal評価モデルが達成・不可能を判定/loop自分で止める、またはClaudeが完了と判断Stop hook自前のスクリプトやプロンプト自動モードClaudeが完了と判断

/goalとStop hookは、どちらもターンのたびに走ります。違いは置き場所です。/goalは入力した条件がそのセッションにだけ効き、Stop hookは設定ファイルに書くので該当範囲のすべてのセッションに効きます。

Stop hookはスクリプトを走らせて決定論的に判定できます。評価モデルが会話から読めない外部の状態を見たい場合は、こちらが選択肢になります。

/loopは時間間隔で次のターンを始め、/goalは条件の達成で止まります。時刻で回したい作業か、状態が整うまで回したい作業か、で選ぶ形です。

ここに挙げた4つは、いずれも開いているセッションを動かし続ける仕組みです。夜間のバッチや朝のトリアージのように、セッションと無関係にスケジュールで走らせたい場合は、クラウド側で動くClaude Code Routinesの領分です。

評価モデルの差し替えとコスト

評価に使われるのは、設定されているsmall fast modelです。差し替えるには環境変数ANTHROPIC_DEFAULT_HAIKU_MODELを設定します。

この変数は/goalだけに効くものではありません。Claude Codeがsmall fast modelを使うすべての場所で読まれ、haikuのエイリアスもそのモデルに解決され、会話の要約などのバックグラウンド処理もそのモデルで動きます。評価の精度を上げたくて差し替えると、副作用が他の処理にも及びます。

評価は、セッションが使うプロバイダーの上で動きます。評価に使ったトークンはsmall fast modelの課金で、メインのターンに比べて通常は無視できる程度というのが公式の説明です。ターンごとに評価が走るため、ターン数が増えるほど積み上がります。CIでは--max-budget-usdのような上限と組み合わせると、全体の見通しを立てやすくなります。

まとめ

/goalの判定は、会話に現れた証拠だけを根拠にします。条件文には終了状態・検証コマンド・守る制約と、ターン数の打ち切りを入れておくと、止まり方が読みやすくなります。

無人で回す場合は、権限モードとCIの上限(--max-turns、--max-budget-usd)を別に決める必要があります。/goalはv2.1.139以降のClaude Codeで使え、claude updateのあとclaude --versionで版を確かめられます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/goal
  2. code.claude.com/docs/en/changelog
  3. code.claude.com/docs/en/env-vars
  4. code.claude.com/docs/en/cli-reference
この記事を共有:XはてブLinkedIn