SessionStartフックやSetupフックを設定したが、ちゃんと動くかを会話を始める前に確認したい人向け
SessionStartフックやSetupフックを書き換えた直後、本セッションを開く前にスクリプトが想定どおり動くか1回だけ確かめたいときに <code>claude --init-only</code> を叩く。フックスクリプト内で <code>echo ... >> ~/hook-debug.log</code> のようにログファイルへ追記する形にしておき、<code>--init-only</code> で起動経路を走らせたあと <code>tail ~/hook-debug.log</code> で書き出された内容を目視確認、問題なければ通常の <code>claude</code> 起動に進む、という流れで使う。
会話セッションは開かず、起動まわりの仕込みだけを走らせて即終了する起動指定です。具体的には Setup フックの init 種別と、SessionStart フックの2種類を実行して、対話画面に入る前にそのまま claude プロセスが終わります。
フックを書いている最中の動作確認用の入り口、と理解するのが一番近いです。
噛み砕くと「フックの試運転モード」
新しい職場でPCを支給されたとき、いきなり業務メールを開くより先に、起動時の初期化スクリプトが正しく動くか管理者が一度だけ走らせて確かめる、みたいな儀式があります。--init-only はあれです。
普段 claude を叩くと、SessionStart フックが裏で走ったあと、対話画面が立ち上がって入力待ちになります。Setup フックは普段の claude 起動では動かない設計で、--init-only や --init などの初期化系の起動指定を渡したときに走る別カテゴリです。
--init-only はその「対話画面が立ち上がる」直前で打ち止め。フックだけ走らせて、エラーがあれば stderr に出して、プロセスごと終わります。Setup フックが echo で吐いた通常の文字出力は、ターミナルには表示されずにデバッグログだけに記録されます。SessionStart フックの標準出力は本来 Claude の会話コンテキストに渡るしくみですが、--init-only では会話が開かないので、その経路は使われません。
だから「フックは書いたけど、ちゃんと動くか会話を始める前に1回試したい」場面に直接効きます。とはいえ、画面で出力を目視確認したいなら、フックスクリプト側でログファイルに書き出す仕込みが必要です。
大事な前提:Setup フックと SessionStart フックが両方走る
このオプ指定を叩くと、公式 docs の記述どおり Setup フックと SessionStart フックが両方実行されます。片方ではない。両方が1回ずつ走り、終わったらプロセス終了です。どちらが先に走るかは公式 docs に明示されていないので、両方のフックが動くことを前提に確認してください。
つまり「SessionStart フックだけ確かめたい」つもりで叩いても、Setup フック側に設定済みのスクリプトがあれば一緒に動きます。逆もしかりで、Setup フックの試運転のつもりで叩いても、SessionStart 側のスクリプトが勝手に走ります。
「片方だけのつもりで叩いたら、もう片方も走ってログ出力が混ざって何が何だか分からなくなった」みたいな混乱が起きやすい。両方とも動く前提で結果を読みましょう。
「SessionStart で最新の変更履歴を Claude に渡す」を例に、実演する
題材は「SessionStart フックで git log の最新1件を Claude に流し込む」スクリプト。次のセッションを開く前に、プロジェクトの最新の変更情報を Claude が把握した状態にしたい、というよくある使い方です。
ただし注意点。--init-only では会話が開かないので、SessionStart フックが echo で吐いた文字は画面に出てきません。公式 docs にも「標準出力はデバッグログ行き」と明記されています。動作確認のためには、フックスクリプト側でログファイルに書き出す仕込みが要ります。
ステップ1: フック用のスクリプトを書く
ホームディレクトリの設定フォルダに .sh ファイルを置きます。中身はこれだけ。
#!/bin/bash
echo "Last change: $(git log -1 --oneline)" >> ~/hook-debug.log
exit 0
ポイントは >> ~/hook-debug.log の部分。標準出力をそのまま吐くだけでは画面に出てこないので、ホームに hook-debug.log というログファイルを作って、そこに追記する形にしています。これで --init-only で叩いたあとに tail でファイルを読めば、フックが実際に動いたか目視確認できます。
保存先は例えば ~/.claude/hooks/session-start-last-commit.sh。実行できる状態にしておくため、chmod +x コマンドで実行許可を付ける、という1ステップが要ります。
ステップ2: フック設定ファイルに登録する
同じくホームの設定ファイル ~/.claude/settings.json に、SessionStart フックとして登録します。
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/session-start-last-commit.sh"
}
]
}
]
}
}
ステップ3: いきなり会話を開かず、まず動作確認
普通だったらこの状態で claude を叩いて対話画面を開くんですが、本セッションを汚す前にスクリプトが想定どおり動くかを確かめたい。ここで --init-only の出番です。
$ cd ~/projects/my-fish-site
$ claude --init-only
$ echo $?
0
対話画面は立ち上がらず、フックの実行が終わるとそのままターミナルに戻ってきます。echo $? で直前のコマンドの終了コードを確認し、0 が返れば --init-only 自体は問題なく終わっています。
ステップ4: ログファイルでフックの動作を確認する
本当にフックが動いたかを目視確認するには、ステップ1で書き出し先に指定した ~/hook-debug.log を読みます。
$ tail -n 5 ~/hook-debug.log
Last change: 4a2b1f3 fish一覧ページの並び順を学名昇順に変更
スクリプトが書いたとおりに git log -1 --oneline の結果がログファイルに記録されていれば、SessionStart フックは正常に動いている、という判定。--init-only 自体は標準出力をターミナルに出さないので、この「ログファイル経由で確認」というひと手間が動作確認の基本パターンになります。
ステップ5: ここで初心者がやりがちな勘違い
「--init-only なら SessionStart だけ動くんでしょ」と勘違いして、Setup フックに別のスクリプト、例えば社内認証トークンの再取得スクリプトを置きっぱなしにすると、それも一緒に走ります。テスト目的で --init-only を叩いただけのつもりが、本番用の Setup スクリプトが裏で動いて環境を書き換えていた、という事故が起きやすい。
確認したいフック以外は、設定ファイルから一時的に外すか、テスト用の別設定ファイルを用意するのが安全です。
ステップ6: スクリプトを直したら、また同じ手順
ログファイルの内容が想定と違ったら、ステップ1のスクリプトを書き直して、ステップ3の claude --init-only をもう一度叩く。会話セッションを毎回開く必要がないので、フックの書き換えサイクルがだいぶ速く回せます。
つまり --init-only は何をしてくれるのか
- やってくれる: Setup フックの
init種別と SessionStart フックを1回ずつ走らせて、終わる - やってくれない: 会話セッションは開かない。Claude に質問を投げることもできない。フック以外、例えば PreToolUse や PostToolUse のようなツール系フックは対象外で走らない。Setup・SessionStart の標準出力はターミナルに表示されない
- 意味が薄い場面: そもそも Setup や SessionStart フックを何も設定していないプロジェクトで叩いても、ほぼ何も起きずに終わる。試運転対象がないので
使いどころ3シナリオ
シナリオ1: SessionStart で「最新の変更履歴」を毎回 Claude に流す仕込みを作るとき
料理ブログのプロジェクトで、セッションを開くたびに「いま編集途中の記事ファイルが何か」を Claude に最初から知っておいてもらいたい。git status -s の結果を SessionStart フックでログファイルに書き出すスクリプトを用意して、--init-only で叩く。終了コードが 0 なら起動経路は OK、続けて tail ~/hook-debug.log で「実際に書き出されたテキストはこれ」を目視確認する流れです。出力が想定と違っていたら、会話を開く前にスクリプトを直せます。
シナリオ2: Setup フックで起動時の環境を整える運用を新しく組んだ初日
家計簿アプリのプロジェクトで、Setup フックに「CLAUDE_ENV_FILE 経由で NODE_ENV=development を立てる」スクリプトを置いた直後。本番セッションを開く前に claude --init-only を叩いて、エラーが出ないか1回試す。Setup フックの標準出力はデバッグログ行きなので、設定値が正しく書かれたかは CLAUDE_ENV_FILE の中身を cat で読んで確認するのが手堅い。エラー出力に関しては、終了コード 2 以外の異常は --verbose を付けないと画面に出てこないので、初回は claude --init-only --verbose で叩くと安心です。
シナリオ3: OSS を git clone してきた直後、相手の SessionStart フックが何を吐くか確かめたいとき
GitHub から見知らぬプロジェクトを手元に複製してきて、ルートに .claude/settings.json が入っていた。そのプロジェクト独自の SessionStart フックが組まれているはずですが、いきなり会話を開いて Claude に何かさせる前に、何が起きるかを --init-only で確かめておきたい。フック内容を読んで、書き出し先のログファイルがあればそこを tail、なければ --verbose 付きで叩いて stderr に出る情報を拾う。安心感が違います。
初心者が踏みやすい落とし穴
- 標準出力がターミナルに出ない仕様を忘れる。Setup フックの標準出力はデバッグログ行き、SessionStart フックの標準出力は本来は会話コンテキスト行きだが
--init-onlyでは会話が開かないので使われない。echoで吐けば画面に出る、と思い込んでいると「フックが動いていない」と勘違いします。動作確認したいならスクリプト内で>> ~/hook-debug.logのようにログファイル書き出しを仕込むこと - Setup フックも一緒に走ることを忘れる。SessionStart の動作確認のつもりが、Setup 側のスクリプトも実行されている。本番用の認証取得スクリプトを Setup に置きっぱなしにしてテストで叩く、はリスクが高い
- フックを何も設定していないのに叩いて「何も起きない」と困惑する。
--init-onlyはあくまでフック実行のための入り口。試運転対象のスクリプトがsettings.jsonにいなければ、起動して即終了するだけ - PreToolUse や PostToolUse 等のツール系フックは試運転できない。それらはツール実行時に走るフックなので、会話セッションを開かないと発火しない。
--init-onlyの対象は Setup と SessionStart の2種類のみ - 失敗時の終了コードを取りこぼす。Setup フックは「ブロック不可」設計で、エラーが出ても実行は続行されます。エラー出力の表示ルールが2段階あって、終了コード 2 のときは
--verboseなしでも画面に出ますが、それ以外の非ゼロ終了コードは--verboseを付けないと画面に出てきません。初回試運転は--verbose併用が安心です --initと混同する。似た名前の--initは-p用、つまり print モードで Setup フックだけ走らせて print セッションを開きます。--init-onlyは print モードと無関係で、会話セッションも開かない。両者は別物- 設定値の永続化を本セッションでも期待してしまう。
CLAUDE_ENV_FILE経由で書いた値は、そのclaudeプロセス内のフック・Bash 実行から見えるだけ。--init-onlyで叩いた時点でプロセスが終わるので、ターミナル本体には影響しません - 会話を開かないのにトークン課金されると勘違い。
--init-onlyは Claude の API を叩かない。会話セッションを開かないので。フック側で API を呼ぶスクリプトを書いていない限り、Claude のトークン消費はゼロです
書き方
claude --init-only
やってみるとこうなる
入力
$ cd ~/projects/my-fish-site
$ claude --init-only
$ echo $?
0
$ tail -n 5 ~/hook-debug.log
出力例
対話画面は立ち上がらず、フックの実行が終わるとターミナルに戻る。
$ echo $?
0
$ tail -n 5 ~/hook-debug.log
Last change: 4a2b1f3 fish一覧ページの並び順を学名昇順に変更
このページに出てきた言葉
- フック
- Claude Codeが起動時やツール実行前後など特定のタイミングで自動で呼び出す、自前のスクリプトの仕組み
- Setupフック
- 起動の準備段階で走るフック。種別として <code>init</code> または <code>maintenance</code> を指定する。普段の <code>claude</code> 起動では動かず、<code>--init-only</code> や <code>--init</code> など初期化系の起動指定でだけ発火する
- SessionStartフック
- 会話セッションが立ち上がる直前に走るフック。プロジェクト情報をClaudeに渡す用途などで使う
- 種別 (matcher)
- フック設定で「どの条件のときに走らせるか」を絞り込むキー。Setupフックでは <code>init</code> と <code>maintenance</code>
- 会話セッション
- <code>claude</code> を普通に叩いたときに開く、Claudeと対話する画面のこと
- 標準出力 (stdout)
- プログラムが通常の文字を吐き出す経路。Setupフックの標準出力はデバッグログ行きで、ターミナルには表示されない
- stderr
- プログラムがエラー用の文字を吐き出す経路。標準出力とは別ルート
- デバッグログ
- Claude Codeが動作の詳細を裏で記録しているログファイル。Setupフックの標準出力もここに書かれる
- CLAUDE_ENV_FILE
- Setupフック内で参照できる設定値。ここで指定されたファイルに <code>export</code> を書き足すと、後続のフックやBash実行で値として読める
- --verbose
- コマンドに足す追加スイッチ。普段は省略される細かい情報まで画面に出してくれる
- プロジェクト
- ファイル一式と変更履歴をまとめて保存してある作業フォルダ。GitHub上で見えるあれ
- git clone
- プロジェクト一式を、自分のパソコンに丸ごとコピーするgitのコマンド