最近、4窓くらいでClaude Codeを並行で走らせて作業しているんだけど、どの窓がいつ終わったのか・どれが入力待ちで止まってるのかが分かりづらい。OSの通知バーに出ても一瞬だし、結局ショートカットで窓を切り替えて確認してた。
なので、各窓の作業完了や入力待ちを音声で読み上げるようにした。音声合成はVoiSona Talkを使ってる。最初は無料の田中傘で試して、形になってから月額のボイスに切り替えた。
構成
細かいスクリプトは省くとして、役割分担はこんな感じ。
- Skill: 作業の最後に
VOICE_NOTIFY: {プロジェクト名}。{状態}。{要約}の一行だけを必ず出させる - Hook: Stop / Notification でその行を拾って音声を鳴らす
設定のコツ
使いながら調整した結果、押さえとくと良かった点をまとめた。shellの中身は長過ぎて読むの大変だろうから、たぶんこっちのほうが流用が効くと思う。
- 読み上げは短く、状態は決め打ち
- 要約は80文字以内、状態は「作業完了 / テスト失敗 / 確認待ち / エラー停止 / 追加指示待ち」から選ばせる
- 聞いた瞬間に判別できればよくて、情報量はむしろ削る
- 英単語はカタカナで書かせる
- VoiSona Talkは英単語をアルファベット読みする(
commitが「シーオーエムアイティー」になる) - コマンド名や技術用語はカタカナで出させる(コミット、プッシュ、マージ)
- VoiSona Talkは英単語をアルファベット読みする(
- プロジェクト名は読みやすい呼び名に変換する
cwdから推定したリポジトリ名をそのまま読むと微妙obsidian → オブシディアン、kyokomi → きょこみみたいなエイリアス辞書を持たせる
- 状態に合わせて声のテンションを変える
- 要約の頭に入れた状態語(完了 / 失敗 / 確認…)から読み上げの感情を自動で決める
- 完了は落ち着いた明るさ、失敗・エラーはしょんぼり、確認待ちは淡々と。声色で結果のニュアンスが伝わる
- 一応
::style=で明示指定もできるけど、基本は状態語まかせで十分だった
- 中身のないStopでは黙らせる
- Stopフックは作業の途中(サブエージェントを動かしてる最中とか)でも何度も発火する
- 毎回「作業完了です」と読むと、未完了なのに完了と誤通知するし、定型文を連呼してうるさい
VOICE_NOTIFY行が出ているStopだけを本当の完了とみなして、無ければ無音にした
- 承認待ち・入力待ちは「何を聞かれてるか」まで読む
- 「承認待ちです」だけだと結局ターミナルを見にいくことになる
- 直前のClaudeの発言の最後の一文(質問本体)や、保留中のツール名(
Bash→ コマンド実行)を添えて読ませる - 何の承認待ちかが耳で分かると、見にいくかどうかを音声だけで判断できる
- 複数窓で同時に鳴っても破綻させない
- キューで一個ずつ順番に読む
- 同じ通知が短時間に続いたらクールダウンでスキップ
- 音声エンジンが落ちててもフォールバックする
- VoiSona Talkに繋がらなければ macOS の
sayで読む - 通知が無言で消えると困るので保険として(いらないかもしれない)
- VoiSona Talkに繋がらなければ macOS の
- VoiSona Talk側のキューは定期的に掃除する
- 再生済み(succeeded/failed/canceled)のリクエストがAPIのキューに残り続けて、100件溜まると
409 Request queue is fullを返して合成できなくなる(=無言になる) - 最初これに気づかず急に読み上げが止まってハマった
- 合成のたびに終端状態の残骸を消すようにして回避した
- 再生済み(succeeded/failed/canceled)のリクエストがAPIのキューに残り続けて、100件溜まると
- どのエンジンで鳴ったかをログに残す
- VoiSona Talk /
say/ 無音、どれで再生したかを記録しておくと調査のときに便利 - 普段は鳴ってるはずなのに
sayばかり出てたら「VoiSona Talkへの送信が失敗してフォールバックしてるな」とすぐ当たりが付く - さっきの100件詰まりに気づけたのもこのログから
- VoiSona Talk /
所感
手も目も塞がらないまま完了や入力待ちが分かるので、窓を切り替えて確認する回数が減った。使いながら調整していくのも含めて、複数窓でClaude Codeを回してる人にはわりと良いと思う。