Claude Code hookをauto-recapより先に試すべき3パターン — commit漏れ・文脈消失・危険操作を自動検知した実録
結論:この3つのhookを先に入れる
auto-recap を検討したが、ノイズ・クォータ消費・重複記録のデメリットを評価してopt-outを維持。代わりに以下の3 hookに着地した。
(A) Stop hook — 会話終了時に未commit / 未push ファイル数を表示
(B) PreCompact hook — コンテキスト圧縮直前にセッションログを自動退避
(C) UserPromptSubmit hook — 「削除/push/リリース」含むプロンプト検出時にgit情報を自動注入
(A) Stop hook — git status の強制表示
# ~/.claude/hooks/stop-git-status.sh
#!/bin/bash
echo "=== git status サマリー ==="
for repo in ~/projects/*/; do
if [ -d "$repo/.git" ]; then
repo_name=$(basename "$repo")
status=$(git -C "$repo" status --porcelain 2>/dev/null)
untracked=$(echo "$status" | grep '^??' | wc -l | tr -d ' ')
modified=$(echo "$status" | grep -v '^??' | wc -l | tr -d ' ')
unpushed=$(git -C "$repo" log --oneline @{u}.. 2>/dev/null | wc -l | tr -d ' ')
if [ "$untracked" -gt 0 ] || [ "$modified" -gt 0 ] || [ "$unpushed" -gt 0 ]; then
echo "[$repo_name] 変更:$modified 未追跡:$untracked 未push:$unpushed"
fi
fi
done
// ~/.claude/settings.json(hooks 部分)
{
"hooks": {
"Stop": [
{
"type": "command",
"command": "bash ~/.claude/hooks/stop-git-status.sh"
}
]
}
}
実装初日、portfolio リポジトリの untracked 84件が一発で可視化された。
git status を毎回手動で打たない限り、untracked は静かに積み上がる。hook で会話の節目に強制表示することで認知できる。
(B) PreCompact hook — セッションログの自動退避
Claude Code のコンテキスト圧縮(PreCompact)直前に、今セッションのトランスクリプトを _inbox/ にコピーする。
# ~/.claude/hooks/precompact-backup.sh
#!/bin/bash
INBOX="$HOME/_inbox/claude-sessions"
mkdir -p "$INBOX"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
SESSION_LOG="$HOME/.claude/current-session.jsonl"
if [ -f "$SESSION_LOG" ]; then
cp "$SESSION_LOG" "$INBOX/session_${TIMESTAMP}.jsonl"
echo "PreCompact backup: $INBOX/session_${TIMESTAMP}.jsonl"
fi
auto-recap で Claude に要約させるより、生ログを手元に残すほうが情報損失が少ない。Claude 側には要約しか残らないが、自分は全文を読み返せる。
(C) UserPromptSubmit hook — 危険操作の事前git情報注入
「削除」「push」「リリース」「本番」「reset」「merge」を含むプロンプトを打ったとき、git 状態を自動注入する。
# ~/.claude/hooks/user-prompt-git-inject.sh
#!/bin/bash
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('prompt',''))" 2>/dev/null)
KEYWORDS="リリース|デプロイ|push|削除|reset|merge|本番"
if echo "$PROMPT" | grep -qE "$KEYWORDS"; then
echo "<git-context-auto-injected>"
echo "現在のブランチ:"
git branch --show-current 2>/dev/null
echo "直近のコミット:"
git log --oneline -5 2>/dev/null
echo "git status (porcelain):"
git status --porcelain 2>/dev/null | head -20
echo "</git-context-auto-injected>"
fi
settings.json 編集後、このhookは同セッション内で即発火した(hot reload の可能性あり)。Output Style は次セッション待ちなのにhookは即時反映という非対称がある。
導入時の落とし穴3つ
落とし穴1: Output Style は次セッションから有効
settings.json を書き換えてもOutput Styleは現セッションには反映されない。セッション開始時に system promptへ焼き込まれる仕様のため。
落とし穴2: PostToolUse lint hook はツールが入っていないと何も起きない
対象リポジトリに Prettier 未設定だと hook は「エラーなしで何もしない」状態になる。
落とし穴3: anthropics/claude-code-action は API 従量課金
Max プランとは別に ANTHROPIC_API_KEY が必要で従量課金が発生。GitHub Actions 経由のClaude 自動化は別課金として設計する必要がある。
まとめ
| hook | タイミング | 効果 |
|---|---|---|
| Stop | 会話終了時 | commit漏れ・untracked放置の検知 |
| PreCompact | 圧縮直前 | セッション生ログの自動退避 |
| UserPromptSubmit | プロンプト送信直前 | 危険操作前のgit状態注入 |
3つとも1時間以内で設定完了できる。auto-recap より先に試す価値がある。
この設計の詳細と実運用記録(untracked 346→4件の整理手順なども)はmasatoman.netの記事にまとめています。
Discussion