DEEP RESEARCH / 開発運用・自動化
Stop/SubagentStop/Notification)でエージェントの区切りを捕捉、②ポーリング型番人スクリプトでhooksが拾えない真の重い処理(学習・量産)の完了を捕捉、③通知チャネル(Toast / Webhook / モバイルpush)へ確実に着地。AIエージェント単体は「終わるまで黙って待ち放置」しがちなので、外部の番人とフックを必ず併設するのが2026年の正解。
長時間タスクの完了通知が「届かない/放置される」根本原因は2つに集約される。
run_in_background:true でバックグラウンド実行したシェルは、完了してもメインエージェントに自動通知されず、次のプロンプトが来るまで BashOutput をチェックしない(公式リポジトリの未解決feature request [10])。=「終わったのに気づかず黙って待つ」が構造的に起きる。これを潰すのが3層冗長化。どれか1つではなく重ねるのが100点設計。
| 層 | 役割 | 主な実装 | 拾える完了 |
|---|---|---|---|
| 層1 hooksCC | エージェントの「区切り」を捕捉し音/通知/外部送信を発火 | settings.json の Stop/SubagentStop/Notification [1] | CCのターン終了・サブエージェント終了・入力待ち |
| 層2 番人PS | 真の重い処理の完了をポーリングで検知→通知→次工程起動 | ファイル/ロック/プロセス監視スクリプト(本DR §4-3) | 学習完了・量産完了・ビルド成果物出現 |
| 層3 チャネルNETMOB | 「届け先」。デスク・スマホ・チャットへ着地 | BurntToast Toast / Discord・Slack webhook / ntfy push [4][5][8] | (上2層から呼ばれる出力先) |
Stop フックに powershell New-BurntToastNotification を1行登録するだけで「CCが返答を終えたらToast」が動く。これに層2の番人を足せば「学習が裏で終わったらスマホにpush」まで到達。
Stop フックを入れましょう。「完了通知」は単機能だが、2025〜2026にかけて環境が3つ動いたため再設計が必要になっている。
Claude Code が run_in_background / BashOutput / KillShell / /bashes を備え、デプロイ・学習・量産をエージェント任せで裏回しするのが普通になった [10]。一方で「完了をメインエージェントへ通知する」機能は2026年6月時点でも未実装の要望段階(Issue #6854 / #9905 等 [10])。=ギャップを各自が埋める必要がある=本DRの存在意義。
個人開発者の定番だった LINE Notify はサービス終了済み[6][7]。移行先は LINE Messaging API(無料は月200通・送信先のuserId明示が必要)か、Discord / Slack / ntfy への乗り換えが主流に [6]。古い記事のLINE Notifyコードをコピペすると今は動かないので注意。
BurntToast モジュール(PSGallery)が枯れて、Win10/11/Server で New-BurntToastNotification 一発で音・アイコン・進捗バー・ボタン付きToastを出せる [4][12]。「ジョブ完了の合図」が最頻ユースケースと明言されている [4]。
本テーマは「競合企業」ではなく通知手段が比較対象。Windows + Claude Code 前提で実用順に並べる。
| # | 手段 | 種別 | 導入難度 | スマホ届く | 無料 | 所感(推奨度) |
|---|---|---|---|---|---|---|
| 1 | BurntToast(PSデスクトップToast) | PS | 低 | × | ○ | ★★★ Win在席時の本命。音+アイコン+ボタン |
| 2 | Claude Code hooks(Stop等) | CC | 低 | △(連携先次第) | ○ | ★★★ エージェント区切り捕捉の基盤 |
| 3 | ntfy.sh(push) | MOB | 低 | ◎ | ○ | ★★★ curl一発でスマホ。APIキー不要 [8] |
| 4 | Discord webhook | NET | 低 | ◎(アプリ) | ○ | ★★★ 履歴/embed/複数端末。最も手軽な恒久ログ [5] |
| 5 | Slack incoming webhook | NET | 低 | ◎(アプリ) | ○ | ★★ チーム共有向き。Block Kitで装飾 [9] |
| 6 | ターミナルベル(\a / OSC 777) | CC | 最低 | × | ○ | ★★ 0依存。端末がフォーカス外でも鳴る |
| 7 | msg.exe(Windows標準) | PS | 最低 | × | ○ | ★ モジュール不要だが古い見た目・消えやすい |
| 8 | LINE Messaging API | MOB | 中 | ◎ | △(月200通) | ★★ Notify後継。userId取得が手間 [6] |
| 9 | node-notifier(クロスPF) | PS | 中 | × | ○ | ★★ Node環境ありなら3OS共通コード [11] |
| 10 | code-notify(CC/Codex/Gemini用OSS) | CC | 低 | × | ○ | ★★ hooks自動設定の既製品。雛形参照に [3] |
登録先は ~/.claude/settings.json(全プロジェクト共通)か .claude/settings.json(プロジェクト固有)[1]。トフィーさん環境では C:\Users\todak\.claude\settings.json。
| イベント | 発火タイミング | matcher | stdin主フィールド |
|---|---|---|---|
Stop | CCがメインの返答を終えた時 | 非対応(常時) | session_id / cwd / transcript_path |
SubagentStop | サブエージェント(Task)終了時 | agent_type(Explore等) | agent_id / agent_type |
Notification | 権限要求・アイドル等 | permission_prompt / idle_prompt 他 | notification_type / message |
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "powershell -NoProfile -Command \"New-BurntToastNotification -Text 'Claude Code', 'タスク完了・確認してください' -Sound 'Notification.Default'\"",
"timeout": 15
}
]
}
],
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [
{
"type": "command",
"command": "powershell -NoProfile -Command \"New-BurntToastNotification -Text 'Claude Code', '入力/許可待ちです'\"",
"timeout": 10
}
]
}
]
}
}
commandを長くするとJSONエスケープ地獄になるので、スクリプトに切り出すのが正解。
# Claude Code Stop フック本体(stdinでhook JSONを受ける)
$ErrorActionPreference = 'SilentlyContinue'
$raw = [Console]::In.ReadToEnd()
$hook = $raw | ConvertFrom-Json
$cwd = $hook.cwd
$msg = "CC完了: $([IO.Path]::GetFileName($cwd)) $(Get-Date -f 'HH:mm:ss')"
# --- 層3-a: デスクトップToast ---
Import-Module BurntToast -ErrorAction SilentlyContinue
New-BurntToastNotification -Text 'Claude Code', $msg -Sound 'Notification.Default'
# --- 層3-b: Discord webhook(外出時スマホへ) ---
$wh = $env:DISCORD_WEBHOOK # 環境変数に置く(URLハードコード禁止)
if ($wh) {
$payload = @{ content = ":white_check_mark: $msg" } | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $wh -Method Post -ContentType 'application/json' -Body $payload
}
exit 0
"Stop": [
{ "hooks": [ {
"type": "command",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File C:\\Users\\todak\\.claude\\hooks\\on_stop.ps1",
"timeout": 20
} ] }
]
どうしてもモジュールを入れたくない時。Notification フックで端末通知シーケンスを返すと、対応端末がOSトーストを出す [1]。
# PowerShellでベルを鳴らすだけのフック command
powershell -NoProfile -Command "[Console]::Beep(880,200)"
# 初回のみ
Install-Module BurntToast -Scope CurrentUser -Force
# 基本
New-BurntToastNotification -Text '学習完了', '1500 step / 2.2s-it' -Sound 'Notification.Default'
# アイコン付き(成果物サムネ等)
New-BurntToastNotification -Text 'R18量産完了', '96枚 / output' -AppLogo 'D:\thumb.png'
# 進捗バー(番人から繰り返し更新)
$pb = New-BTProgressBar -Status '生成中' -Value 0.6
New-BurntToastNotification -Text '画像量産' -ProgressBar $pb
msg %USERNAME% "ビルド完了: 確認してください"
# bash
curl -s -H "Content-Type: application/json" -X POST \
-d '{"content":":white_check_mark: deploy 完了 (exit 0)"}' \
"$DISCORD_WEBHOOK"
# embed(タイトル/色/ホスト名フッタ)
curl -s -X POST -H "Content-Type: application/json" \
--data "{\"embeds\":[{\"title\":\"学習完了\",\"description\":\"loss 0.04 / 3000 step\",\"color\":3066993,\"footer\":{\"text\":\"$(hostname)\"}}]}" \
"$DISCORD_WEBHOOK"
curl -X POST -H 'Content-type: application/json' \
--data '{"text":":rocket: デプロイ完了 d632da4a"}' \
"$SLACK_WEBHOOK_URL"
スマホにntfyアプリを入れ、推測されにくいトピック名を購読するだけ。curlで即push。
# 最小
curl -d "学習完了 2.2s/it" ntfy.sh/todak-secret-7x9q2
# タイトル・優先度・タグ付き
curl -H "Title: R18量産完了" -H "Priority: high" -H "Tags: white_check_mark,art" \
-d "96枚 / oudou_r18 / 確認を" \
ntfy.sh/todak-secret-7x9q2
# PowerShellから
Invoke-RestMethod -Uri "https://ntfy.sh/todak-secret-7x9q2" -Method Post -Body "ビルド完了"
Authorization: Bearer tk_xxx)。# Notifyは終了済。後継はchannel access token + userId(or groupId)を明示
curl -X POST https://api.line.me/v2/bot/message/push \
-H "Authorization: Bearer $LINE_CHANNEL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to":"Uxxxxuserid","messages":[{"type":"text","text":"学習完了"}]}'
# 無料は月200通(送信人数×通数)
const notifier = require('node-notifier');
notifier.notify({ title: 'Build', message: '完了 (exit 0)', sound: true });
hooksは「CCの区切り」しか拾えない。裏で走る本物の重い処理(学習・量産・長ビルド)の完了は、独立した番人が監視する。設計は3要素:完了検知 → 通知発火 → 次工程自動起動。
| 方式 | 検知トリガ | 信頼度 | 使い所 |
|---|---|---|---|
| ① 完了マーカーファイル | 処理側が最後に DONE.flag を書く | ◎最高 | 自分で書けるスクリプト全般。最推奨 |
| ② 成果物の出現/枚数 | output に N 枚揃った | ○ | 画像量産・レンダ |
| ③ プロセス消滅 | PIDが消えた | △ | 外部exe。異常終了と区別不可 |
| ④ ログ末尾の合言葉 | ログに Training complete | △ | ログ形式が安定している時のみ |
param(
[string]$Marker = "D:\projects\fanza3_mass\out\DONE.flag", # ①完了マーカー
[string]$Label = "R18量産",
[int] $Every = 30, # 秒
[int] $Timeout = 14400, # 4h で諦め
[string]$Next = "" # 次工程スクリプト(任意)
)
$ntfy = "https://ntfy.sh/todak-secret-7x9q2"
$start = Get-Date
Write-Host "[watcher] $Label 監視開始 marker=$Marker"
while ($true) {
if (Test-Path $Marker) {
$info = Get-Content $Marker -Raw # 例: "exit=0 count=96"
$msg = "$Label 完了 $info $(Get-Date -f 'HH:mm:ss')"
Import-Module BurntToast -EA SilentlyContinue
New-BurntToastNotification -Text "完了通知", $msg -Sound 'Notification.Default'
try { Invoke-RestMethod -Uri $ntfy -Method Post -Headers @{Title=$Label} -Body $msg } catch {}
# ③次工程の自動起動(チェーン)
if ($Next -and (Test-Path $Next)) {
Write-Host "[watcher] 次工程起動: $Next"
Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$Next`""
}
break
}
if (((Get-Date) - $start).TotalSeconds -gt $Timeout) {
$m = "$Label が $([int]($Timeout/60))分で未完了。ハング疑い・要確認"
Import-Module BurntToast -EA SilentlyContinue
New-BurntToastNotification -Text "⚠ タイムアウト", $m
try { Invoke-RestMethod -Uri $ntfy -Method Post -Headers @{Title="TIMEOUT";Priority="urgent"} -Body $m } catch {}
break
}
Start-Sleep -Seconds $Every
}
処理側(学習/量産スクリプト)は最後にこう書くだけ:
# Python なら
with open(r"D:\projects\fanza3_mass\out\DONE.flag","w",encoding="utf-8") as f:
f.write(f"exit=0 count={len(imgs)}")
# bash なら
echo "exit=$? count=$(ls out/*.png | wc -l)" > /d/projects/fanza3_mass/out/DONE.flag
run_in_background と末尾 & を二重に付けると実行されない。どちらか一方に。進捗は print(...,flush=True) かログファイルpollで(| tail はバッファして完了まで無音)。「番人が次工程を起動」の発展形として、番人がCCを自己ウェイクアップさせ、完了を“報告”まで自走させるパターン。前述のとおりCCはBG完了を自動検知しない[10]ので、外部から起こす。
# 完了検知後、CCをheadlessで叩いて要約+次判断をさせる
claude -p "out/DONE.flag を読み、量産結果を3行で要約し、不良が無ければ次のVolをsmoke起動して。" `
--output-format text >> D:\logs\cc_report.log 2>&1
CCの Stop フックは終了コード2 or {"decision":"block","reason":...} を返すと停止を差し止めて会話を継続できる[1]。「未確認の成果物がある間は止めない」という自走ループに使える(暴走防止のため必ずカウンタ/上限を付ける)。
# on_stop.ps1 内(自走させたい時のみ・要ガード)
$pending = (Test-Path "D:\out\UNVERIFIED.flag")
$loops = [int](Get-Content "D:\out\loopcount.txt" -EA SilentlyContinue)
if ($pending -and $loops -lt 3) {
($loops+1) | Set-Content "D:\out\loopcount.txt"
'{"decision":"block","reason":"未検証の成果物あり。全コマ目視と4AIゲートを実行して。"}'
} else {
Remove-Item "D:\out\loopcount.txt" -EA SilentlyContinue
}
導入コストはほぼゼロ(OSS/標準機能)。価値は「放置で溶ける時間」の回収で測る。
| 項目 | 導入前 | 導入後 | 差分 |
|---|---|---|---|
| 学習完了の気づき遅延 | 平均30〜240分放置(席外し) | 完了即push | 1回あたり最大4hのGPU空回り回避 |
| 量産完了→次Vol着手 | 手動で見に行く・忘れる | 番人が次工程自動起動 | 人手の確認往復ゼロ |
| 異常終了の発見 | 翌朝気づく等 | タイムアウトでurgent push | 無駄電力・再走遅延を即停止 |
| 導入の実コスト | — | BurntToast/ntfy/webhook 全無料 | ¥0 |
参考:MEMORY記録の「LoRA学習中にcomfy常駐で56s/it(正常の17倍)に4時間気づかず空回り」事案は、本DRの番人+タイムアウトpushがあれば早期に異常検知できた典型ケース。
| リスク | 内容 | 対策 |
|---|---|---|
| 誤“完了”報告 | プロセス消滅だけで成功判定→異常終了を成功と誤報 | マーカー/成果物で裏取り・exit code/枚数を本文に |
| 無限自走 | Stopブロックの自己ウェイクでトークン枯渇(Issue #11716) | ループ上限・時間上限・自己目視ゲート必須 |
| 古いコピペ | LINE Notifyコードが今は動かない(2025/3終了) | Messaging API / Discord / ntfy へ |
| 秘密の露出 | webhook URL/トークンをコードや公開repoに直書き | 環境変数・keys.jsonへ。ntfyトピックは乱数長名 |
| JSONエスケープ事故 | settings.jsonのcommandに長いPSを書いて壊れる | .ps1へ分離・-Fileで呼ぶ |
| ExecutionPolicy | スクリプトが実行拒否される | -ExecutionPolicy Bypass をフックに付与 |
| パイプ無音 | | tail で完了まで進捗が出ない | flush print / ログpoll / 「[3/6]」逐次出力 |
| BG二重化 | run_in_background+&で実行されない | どちらか一方のみ |
Install-Module BurntToast/~/.claude/settings.json に Stop フック1行(§4-1①)Notification フックで権限/アイドル待ちもToast化on_stop.ps1 へ分離しcwd/時刻入りに格上げ(§4-1②)on_stop.ps1 にntfy送信追記DISCORD_WEBHOOK に格納、embed送信を確認DONE.flag 書き出しを追加(exit/枚数入り)_done_watcher.ps1 を導入→Toast+ntfy+タイムアウトpushを実走確認claude -p 自己ウェイクで完了要約を試す(上限ガード付き)& と run_in_background を二重化していないか| # | テンプレ | 1行起点 |
|---|---|---|
| 1 | CC完了Toast | settings.json Stop に BurntToast 1行(§4-1①) |
| 2 | 権限待ちToast | Notification matcher=permission_prompt |
| 3 | stdin内容入り通知 | on_stop.ps1(§4-1②) |
| 4 | Discord完了embed | curl embed(§4-2) |
| 5 | ntfyスマホpush | curl -d "完了" ntfy.sh/乱数 |
| 6 | マーカー番人 | _done_watcher.ps1(§4-3) |
| 7 | タイムアウト警報 | 番人の Timeout 分岐(urgent push) |
| 8 | 次工程チェーン | 番人の -Next で Start-Process |
| 9 | 自己ウェイク報告 | claude -p "DONE.flag要約して" |
| 10 | DONE.flag書き出し | 処理末尾に exit/枚数を1行書く(§4-3) |
_mem_guard_2026-05-22.py(30秒毎RAM監視)・_cc1_train_comfy_guard_2026-06-14.sh(lock監視)が既にポーリング常駐型。これらに完了通知(ntfy/BurntToast)を1ブロック足すだけで本DRの番人になる。ゼロから作らなくてよい。grok_router_costs.jsonl 同様、番人の検知/通知も jsonl に追記すれば「いつ何が完了/誤報したか」が後追いできる。_cc1_4ai_eval/_cc1_count_gate を次工程に繋げば「完了通知=合格通知」に格上げできる(誤“完了”の構造的防止)。D:\projects\_keys\keys.json に集約(ハードコード禁止のMEMORYルール踏襲)。| DR | 関連性 |
|---|---|
DR_CC暴走防止_02_AIの確認前『完了』報告(ハルシネ)_2026-05-31.html | 直接関連。 本DR §4-3/§9 の「誤完了防止・自己目視ゲート」と表裏一体。併読推奨 |
DR_R18可の通知手段2026_メルマガLINE代替_2026-06-01.html | 通知チャネル(LINE代替)の知見が一部重なる。ただし用途はマーケ向けで本DR(開発者向け完了通知)とは別物 |
DR_プッシュ通知リエンゲージメント継続率完全戦略_2026.html | push技術の周辺。用途はユーザーリテンションで別領域 |