## 経緯
[[cmux]]なら[[Claude Code]]の通知をいい感じにしてくれると思っていたが、そうでもなさそう & 安定性に不安がある......ので自分で仕組みをつくる。
基本的には[[フック (Claude Code)|フック]]を定義し、[[OSC 777 シーケンス]]を使って通知を行う。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/favicon-64.png" />
<span class="link-card-v2-site-name">Minerva</span>
</div>
<div class="link-card-v2-title">
📜2026-02-24 copilot-plugin-notifyの初期開発記録
</div>
<div class="link-card-v2-content">cmux notifyの不安定さとOSC 777シーケンスの/dev/tty出力問題に対処しつつ、Copilot CLI hooksの制約を調査した結果、自前通知実装を決定し、スクリプトや環境変数のリネームと許可コマンド用の通知抑制設定を行った記録である</div>
<img class="link-card-v2-image" src="https://publish-01.obsidian.md/access/35d05cd1bf5cc500e11cc8ba57daaf88/Notes/attachments/activity.webp" />
<a data-href="📜2026-02-24 copilot-plugin-notifyの初期開発記録" class="internal-link"></a>
</div>
%%[[📜2026-02-24 copilot-plugin-notifyの初期開発記録]]%%
> [!question] `cmux notify` を使わないのか?
> `cmux` コマンドは[[cmux]]の状態によって発動しないこともあり不安定なので。
## [[フック (Claude Code)|フック]]に組み込む
`~/.claude/settings.json` に定義するのは変わってなさそう。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://code.claude.com/docs/_mintlify/favicons/claude-code/pLsy-mRpNksna2sx/_generated/favicon/favicon-16x16.png" />
<span class="link-card-v2-site-name">code.claude.com</span>
</div>
<div class="link-card-v2-title">
Automate workflows with hooks - Claude Code Docs
</div>
<div class="link-card-v2-content">
Run shell commands automatically when Claude Code edits files, finishes tasks, or needs input. Format code, send ...
</div>
<img class="link-card-v2-image" src="https://claude-code.mintlify.app/_next/image?url=%2F_mintlify%2Fapi%2Fog%3Fdivision%3DBuild%2Bwith%2BClaude%2BCode%26appearance%3Dsystem%26title%3DAutomate%2Bworkflows%2Bwith%2Bhooks%26description%3DRun%2Bshell%2Bcommands%2Bautomatically%2Bwhen%2BClaude%2BCode%2Bedits%2Bfiles%252C%2Bfinishes%2Btasks%252C%2Bor%2Bneeds%2Binput.%2BFormat%2Bcode%252C%2Bsend%2Bnotifications%252C%2Bvalidate%2Bcommands%252C%2Band%2Benforce%2Bp%26logoLight%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Flight.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D78fd01ff4f4340295a4f66e2ea54903c%26logoDark%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Fdark.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D1298a0c3b3a1da603b190d0de0e31712%26primaryColor%3D%25230E0E0E%26lightColor%3D%2523D4A27F%26darkColor%3D%25230E0E0E%26backgroundLight%3D%2523FDFDF7%26backgroundDark%3D%252309090B&w=1200&q=100" />
<a href="https://code.claude.com/docs/en/hooks-guide"></a>
</div>
> Open `~/.claude/settings.json` and add a `Notification` hook.
`setting.json` に `hooks` を追加。
```json
{
"hooks": {
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/notify.sh" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "~/.claude/hooks/notify.sh" }]
}
]
}
}
```
`~/.claude/hooks/notify.sh` は以下のようにする。
```bash
#!/bin/bash
notify() {
local title="$1"
local body="$2"
# >dev/tty に出力しないとcopilotにインターセプトされて端末まで伝わらないので注意
printf '\e]777;notify;%s;%s\a' "$title" "$body" >/dev/tty
}
INPUT=$(cat)
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // "unknown"')
case "$EVENT" in
"Notification")
TYPE=$(echo "$INPUT" | jq -r '.notification_type // ""')
MSG=$(echo "$INPUT" | jq -r '.message // ""')
[ "$TYPE" = "idle_prompt" ] && notify "Claude Code" "入力待ち: $MSG"
;;
"Stop")
MSG=$(echo "$INPUT" | jq -r '.last_assistant_message // ""' | cut -c1-50)
notify "Claude Code" "応答完了: $MSG"
;;
esac
```
> [!question] `TaskCompleted` と `SubagentStop` を含めないのは?
> バックグラウンドで[[Claude Code]]が管理しているケースがほとんどであり、ユーザーが通知を受け取るメリットはない (ノイズになる) ため。
## 関連情報
> [!caution]
> 古い情報なので参考程度に。
- [[📜2025-06-25 Claude Codeの作業や回答が終わり人間待ちになったとき通知を表示する]]
- [[📜2025-07-02 Claude Codeで人間が確認待ちの状態になっている場合に通知させる]]
-