施策の PR をマージした後、「次に何をやるんだっけ」と数日空白ができることが何度かありました。仕様上は「次フェーズに入る」のが自明でも、Issue として明示されていないと忘れます。
Claude Code の SessionEnd hook を使って、施策完了時に次段階の Issue を自動起票 する仕組みを作りました。設計と運用してみての気づきを書きます。
何が起きていたか
「完了」の解像度の低さ
施策を /spec ワークフローで進めて、PR がマージされる。そこで「施策完了」と認識して別の作業に移る。が、本来は次のような 連続したフェーズ が想定されていました。
1Phase A: 機能実装(PR マージ)2 ↓ 1〜3 日後3Phase B: 翌日監視・指標確認4 ↓ 1 週間後5Phase C: 効果測定レポート6 ↓ 必要なら7Phase D: 改善 PRPR マージ → 別の作業に移る → Phase B〜D が抜け落ちる。気づいたら 1 ヶ月後で「あの施策、結局効果あったんだっけ?」状態。
Issue が手動だと忘れる
GitHub Issue を立てておけば追えるのですが、PR マージ時に 手動で次フェーズの Issue を起票する のは結構面倒で、忘れます。
「自動化したい」と思ったとき、ちょうど Claude Code の hooks 機能が使えると気づきました。
設計:SessionEnd hook で次 Issue を起票
Claude Code の hooks 概要
Claude Code には複数のライフサイクル hook があります(SessionStart, PreToolUse, PostToolUse, SessionEnd など)。シェルコマンドを設定で書ける形です。
1{2 "hooks": {3 "SessionEnd": [4 {5 "hooks": [6 {7 "type": "command",8 "command": "bash .claude/hooks/session_end.sh"9 }10 ]11 }12 ]13 }14}起票判定のロジック
毎セッション終了時に Issue を立てると Issue が爆増します。特定の条件を満たしたときだけ起票するようにしました。
1#!/bin/bash2set -euo pipefail3
4# 直近の commit メッセージから施策完了マーカーを検出5last_commit_msg=$(git log -1 --pretty=%s)6
7# 施策完了パターン: 「feat(measure-xxx): C-11 マージ」など8if [[ "$last_commit_msg" =~ ^feat\(measure-([a-z0-9-]+)\):.*C-11 ]]; then9 measure_name="${BASH_REMATCH[1]}"10 create_followup_issues "$measure_name"11fi「コミットメッセージのパターン」をトリガーにすると、誤発動が減ります。/spec ワークフローの最終ステップ C-11 のコミットだけが対象になります。
Issue テンプレート
施策ごとに「次にやるべきこと」が違うので、テンプレートを .docs/issue_templates/ に置いて、施策名で選びます。
1create_followup_issues() {2 local measure="$1"3 local template_dir=".docs/issue_templates"4
5 # Phase B: 翌日監視6 local body_b=$(cat "$template_dir/post_deploy_monitoring.md" \7 | sed "s/{measure}/$measure/g")8 gh issue create \9 --title "[$measure] Phase B: 翌日監視・指標確認" \10 --label "phase-b,auto-generated" \11 --body "$body_b"12
13 # Phase C: 1 週間後の効果測定14 gh issue create \15 --title "[$measure] Phase C: 効果測定レポート" \3 collapsed lines
16 --label "phase-c,auto-generated" \17 --body "$(cat "$template_dir/effect_measurement.md" | sed "s/{measure}/$measure/g")"18}Issue の本文に「いつやる」を入れる
ただ Issue を立てるだけだと優先順位がつかないので、**「実施推奨日」**を本文に書きます。
1## 実施推奨日22026-05-09(PR マージから 1 週間後)3
4## チェックリスト5- [ ] launchd ジョブのログを確認6- [ ] エラー件数の推移を確認(before/after)7- [ ] アラート発生件数の推移を確認8- [ ] 効果測定レポートをコメント追記gh issue list --label phase-c --state open で「今週やるべきこと」が一覧できます。
運用してみての気づき
効いた点
1. 「次やること」が消えなくなる
PR マージから 1 週間経つと、自分でも何をやっていたか忘れます。Issue に「実施推奨日」とチェックリストが残っていると、その日に GitHub の Issue 一覧を見れば思い出せます。
2. 施策ごとの「フォローアップ密度」が見える
gh issue list --label auto-generated --state closed で、過去の施策がきちんとフォローアップまで完了しているかが見えます。「Phase B は完了したが Phase C が未着手」のパターンが可視化されました。
3. AI エージェントへの委譲がしやすくなる
Issue があれば「この Issue の内容を実行してほしい」と Claude Code に渡せます。フォローアップ作業も AI に任せやすくなりました。
踏んだ罠
罠 1: hook が毎セッションで発火して Issue 重複
最初は SessionEnd で無条件に起票していたので、同じ施策で 同じ Issue が 5 個 立ったことがありました。
修正: コミットメッセージのパターンマッチで、C-11 を含むものだけに絞り込み + Issue タイトルで重複検査。
1# 既存 Issue のチェック2existing=$(gh issue list --label "phase-b" --search "[$measure]" --json number)3if [[ "$existing" != "[]" ]]; then4 echo "Issue already exists for $measure, skipping"5 return6fi罠 2: hook 内のエラーがセッションを止める
hook の bash スクリプトでエラーが起きると、Claude Code のセッション自体に影響が出ました(具体的には次セッション起動時に hook 失敗のメッセージが)。
修正: hook 内では絶対に exit 非ゼロを返さない。
1# 末尾2exit 0 # 何があっても 0 で終わるエラーログだけは別ファイルに残して、後で見られるようにします。
1{2 set -euo pipefail3 # ... main logic4} 2>> /tmp/session_end_hook.log || {5 echo "$(date) hook failed, see log" >> /tmp/session_end_hook.log6}7exit 0罠 3: gh コマンドの認証
CI 環境やリモート環境で hook が動くとき、gh コマンドの認証が通っていないと黙って失敗します。
1if ! gh auth status &>/dev/null; then2 echo "gh not authenticated, skipping issue creation" >&23 exit 04fi認証チェックを先に入れて、未認証なら何もしない方針にしました。
罠 4: テンプレートの変数置換ミス
sed "s/{measure}/$measure/g" で施策名を埋め込んでいましたが、施策名にスラッシュやドル記号が含まれると sed がエラーになります。
修正: bash の文字列置換を使う。
1body=$(cat "$template_dir/post_deploy_monitoring.md")2body="${body//\{measure\}/$measure}" # bash 内蔵の置換特殊文字を含む文字列でも安全です。
さらなる発展
Issue → AI エージェントへの自動委譲
Issue 起票時に claude-code-bot のようなラベルをつけると、別の自動化で AI エージェントに委譲する仕組みも考えられます(GitHub Actions と Claude Code SDK の組み合わせ)。
ただし、本番環境への影響がある作業を完全自動化するのはリスクが高いので、人間のレビューが入る Issue にとどめる 設計にしています。
Issue の自動クローズ
「実施推奨日」を過ぎた Issue が放置されているケースを検知し、毎週月曜にリマインドする bot も使っています。
1on:2 schedule:3 - cron: "0 0 * * 1" # 毎週月曜 0:004jobs:5 remind:6 runs-on: ubuntu-latest7 steps:8 - run: |9 gh issue list --label "auto-generated" --state open \10 --json number,title,createdAt \11 | jq -r '.[] | select((now - (.createdAt | fromdate)) > 604800) | .number' \12 | xargs -I {} gh issue comment {} --body "1 週間以上未着手です"まとめ
| 観点 | 設計方針 |
|---|---|
| トリガー | コミットメッセージのパターンマッチ(誤発動防止) |
| Issue 内容 | 実施推奨日 + チェックリスト |
| 重複防止 | 既存 Issue のタイトル検索 |
| エラー処理 | hook 内では exit 0、ログだけ残す |
| 拡張性 | 施策ごとにテンプレートを差し替え可能 |
PR マージ時の「次何やるんだっけ」空白は、自動 Issue 起票で構造的に埋められる問題でした。
Claude Code の hooks 機能はシェルスクリプトを書けるので、GitHub の gh コマンドと組み合わせて、ワークフローの隙間を自動化するのに非常に有効です。施策の連続性を保つ仕掛けとして、運用負荷を下げる効果が大きかった改善でした。