VS Code版CodexのStopフックで応答終了をWindowsに通知する
作成日:2026.10.04
VS Code版CodexのStopフックとPowerShellを使い、最後の応答をWindows通知に表示する方法を紹介します。hooks.jsonの設定と非同期実行、日本語が文字化けした際のUTF-8による対処、通知が出ない場合の確認点をまとめます。
目次
VS CodeのCodex拡張に時間のかかる調査やテストを任せていると、別のウィンドウで作業している間に応答が終わっていても気づきにくいことがあります。
そこで、CodexのStopフックからPowerShellスクリプトを呼び出し、最後の応答をWindowsの通知に表示するようにしてみました。今回はその設定と、通知の日本語が文字化けしたときの対処を紹介します。
Stopフックで通知する仕組み
Hooksは、Codexの処理中に発生するイベントに合わせて、スクリプトなどを実行する仕組みです。今回は応答が終了するときのStopイベントを使います。
Codexの応答が終了
↓ Stopイベント
PowerShellスクリプトへJSONを渡す
↓ 最後の応答を取り出す
Windowsに通知する
コマンド形式のフックには、イベントの情報がJSONとして標準入力から渡されます。hook_event_nameにはイベント名、last_assistant_messageには最後の応答が入ります。最後の応答がない場合もあるため、そのときは固定のメッセージを表示します。
なお、Stopイベントが発生したことは、依頼した作業やテストが成功したことを意味しません。「テスト失敗」「追加確認が必要」といった応答も、そのまま通知する使い方です。
今回の対象環境
- Windows
- Visual Studio CodeのCodex拡張
- PowerShell 7(
pwsh.exe) - ユーザー設定の
hooks.json
2026年10月1日の作業では、VS CodeのCodex拡張でStopフックが認識され、実行を許可する確認画面が表示されました。設定とイベントの仕様は、2026年10月4日時点のOpenAI公式のHooks資料と照合しています。
以下のスクリプトは、この作業で使った例です。
まず、通常のPowerShellでpwsh.exeを呼び出せるか確認します。
Get-Command pwsh.exe
pwsh.exe -NoProfile -Command '$PSVersionTable.PSVersion'
通知用のPowerShellスクリプトを作る
例として、次の場所へnotify-complete.ps1をUTF-8で保存します。<ユーザー名>は、自分のWindowsユーザーのフォルダー名へ置き換えてください。
C:\Users\<ユーザー名>\.codex\notify-complete.ps1
スクリプトの内容は次の通りです。
$ErrorActionPreference = 'Stop'
try {
# フックから渡された標準入力をUTF-8として読む
$utf8 = [System.Text.UTF8Encoding]::new($false)
$standardInput = [Console]::OpenStandardInput()
$reader = [System.IO.StreamReader]::new(
$standardInput,
$utf8,
$true,
4096,
$true
)
try {
$eventJson = $reader.ReadToEnd()
} finally {
$reader.Dispose()
}
$eventData = $eventJson | ConvertFrom-Json
if ($eventData.hook_event_name -eq 'Stop') {
$message = 'Codexの応答が終了しました。'
if ($eventData.last_assistant_message) {
$summary = [string]$eventData.last_assistant_message
if ($summary.Length -gt 180) {
$length = 180
# 絵文字などのサロゲートペアを途中で切らない
if ([char]::IsHighSurrogate($summary[$length - 1])) {
$length--
}
$summary = $summary.Substring(0, $length) + '…'
}
$message = $summary
}
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$notification = [System.Windows.Forms.NotifyIcon]::new()
try {
$notification.Icon = [System.Drawing.SystemIcons]::Information
$notification.BalloonTipIcon =
[System.Windows.Forms.ToolTipIcon]::Info
$notification.BalloonTipTitle = 'Codex'
$notification.BalloonTipText = $message
$notification.Visible = $true
[System.Media.SystemSounds]::Asterisk.Play()
$notification.ShowBalloonTip(5000)
# 通知直後にプロセスが終了しないよう、少し待つ
Start-Sleep -Seconds 6
} finally {
$notification.Dispose()
}
}
} catch {
# stdoutにはフックのJSONだけを返す
[Console]::Error.WriteLine('Codex通知を表示できませんでした。')
}
Write-Output '{"continue":true}'
exit 0
通知にはSystem.Windows.Forms.NotifyIconを使っています。最後の応答が長いと読みにくいため、文字列の長さが180を超えた場合は省略し、末尾へ「…」を付けています。長さは.NETの文字列で判定し、絵文字などを途中で切らないよう補っています。これはスクリプトで決めた省略の長さで、Windows通知が必ずこの長さまで表示できるという意味ではありません。
JSONの解析や通知処理でエラーになった場合は、標準エラーへ短いメッセージを出し、末尾でJSONを返して終了します。finallyでは、標準入力の読み取りと通知に使ったオブジェクトを破棄します。
{"continue":true}はフックの出力であり、作業の成功を知らせる値ではありません。今回の用途では、通知するためにCodexへ追加の作業を要求する必要もありません。
通知後に待機する理由
元の作業では、通知を出した直後にPowerShellのプロセスが終了しないよう、6秒待機させました。この待機時間は通知の表示を保証するものではなく、環境に応じて調整が必要です。
ShowBalloonTip(5000)と書いていますが、必ず5秒表示されるわけではありません。MicrosoftのNotifyIcon.ShowBalloonTipの資料では、表示時間はシステムのアクセシビリティ設定などに左右されると説明されています。
hooks.jsonへStopフックを登録する
ユーザー設定のhooks.jsonは、通常は次の場所に置きます。
C:\Users\<ユーザー名>\.codex\hooks.json
今回使用した設定は以下の内容です。スクリプトのパスは自分の環境に合わせてください。JSON文字列の中では、パスのバックスラッシュを\\、パスを囲む引用符を\"と書きます。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "pwsh.exe -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\<ユーザー名>\\.codex\\notify-complete.ps1\"",
"timeout": 10,
"async": true
}
]
}
]
}
}
既存のhooks.jsonがある場合は、他のフックを残してStopの設定を追加します。ユーザー設定とプロジェクト設定の両方へ同じフックを登録すると、重複して実行される可能性があるため、登録場所も確認してください。
commandでは、PowerShell 7から先ほどのスクリプトを実行しています。-NoProfileでプロファイルの読み込みを省略し、-ExecutionPolicy Bypassは今回の起動プロセスに対する指定として使っています。恒久的な実行ポリシーは変更しません。内容を確認した自分のスクリプトに使い、組織のポリシーがある環境ではその制約に従ってください。詳しくはpwshの起動オプションの資料を参照してください。
asyncで通知処理を非同期にする
async: trueは、フックの処理をバックグラウンドで実行する設定です。スクリプトの中では6秒待機しますが、Codexはフックの終了を待たずに処理を進めます。
timeout: 10の単位は秒です。非同期でもタイムアウトは適用されるので、PowerShellの起動、JSONの読み取り、通知後の待機を含めて時間内に終わる必要があります。
非同期フックは元の処理をブロックしたり、追加の応答を要求したりする用途には使えません。また、Codexのセッションが終了すると、実行途中の非同期フックはキャンセルされます。通知処理中にVS Code側のセッションを閉じる場合も、この点に注意してください。仕様は公式資料のバックグラウンド実行の説明にまとまっています。
フックの実行を許可する
私の環境では、VS CodeのCodex拡張がフックを認識した際に、ローカルコマンドの実行を確認する画面が表示されました。実行元がユーザー設定であること、イベントがStopであること、コマンドが自分のスクリプトを指していることを確認して許可します。
フックの定義を変更すると、改めて信頼の確認が必要になる場合があります。設定後にフックが認識されない場合は、Codex拡張やVS Codeを再起動して設定を読み直し、確認画面やエラーを確認してください。
日本語が文字化けしたときの対処
最初は、フックの標準入力を次のように読んでいました。
$eventJson = [Console]::In.ReadToEnd()
この状態でも通知は表示されましたが、英数字は正常で、日本語だけが「縺…」のように崩れてしまいました。標準入力のデータとPowerShell側で使う文字コードが一致していない可能性を考え、UTF-8を明示する方法へ変更しました。
$utf8 = [System.Text.UTF8Encoding]::new($false)
$standardInput = [Console]::OpenStandardInput()
$reader = [System.IO.StreamReader]::new(
$standardInput,
$utf8,
$true,
4096,
$true
)
try {
$eventJson = $reader.ReadToEnd()
} finally {
$reader.Dispose()
}
OpenStandardInput()で標準入力のストリームを開き、StreamReaderへUTF-8を渡して読みます。第3引数の$trueはBOMによる文字コードの検出、第5引数の$trueはReaderを破棄しても元のストリームを閉じない指定です。引数の意味はStreamReaderのコンストラクターの資料で確認できます。
この変更後、私の環境では応答が文字化けせずに、そのまま通知に表示されるようになりました。[Console]::Inで読むと常に文字化けするという話ではありませんが、外部プロセスから受け取るJSONの文字コードを明示しておくと、処理の意図も分かりやすくなります。
動作確認と通知が出ない場合の確認
設定後は、VS CodeのCodex拡張へ短い依頼を送って確認します。例えば、次のような内容です。
ファイルや設定は変更せず、
「変更なし。日本語通知のテストです。」
と返してください。
応答が終わった後、タイトルが「Codex」、本文が「変更なし。日本語通知のテストです。」となれば、日本語を含めた通知を確認できています。
通知が出ない場合は、次の順番で確認すると切り分けやすいかと思います。
- フックが認識され、実行を許可されているか。
hooks.jsonのJSON、スクリプトのパス、pwsh.exeの解決先が正しいか。- Codex側にフックのエラーやタイムアウトが出ていないか。
- Windowsの通知設定や応答不可モードなどで、通知が抑制されていないか。
応答が長い場合は省略されますし、複数の通知が短時間に重なると、すべてを画面で確認できるとは限りません。他のStopフックがCodexへ追加作業を要求する構成では、応答終了のたびに再通知される可能性もあります。結果を確実に確認したい場合は、Codexの会話と実行ログも確認してください。
また、最後の応答を通知するため、業務情報などが画面へ表示される点にも注意が必要です。本文を表示したくない場合は、スクリプトのlast_assistant_messageを読む部分を省き、固定の終了メッセージだけを使うとよいでしょう。
まとめ
今回は、VS Code版CodexのStopフックからPowerShellを実行し、最後の応答をWindows通知へ表示する方法を紹介しました。
今回つまずいたのは、標準入力から読んだ日本語が文字化けする点でした。UTF-8を指定したStreamReaderへ変更することで改善しています。また、async: trueにしておくと、通知後の待機でCodexの処理を待たせずに済みます。
Codexへ作業を任せた後に、別のウィンドウで作業することが多い場合には便利な設定かと思います。
奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。
これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。
【制作会社・企業様向けサポート】
Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。
ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。
ChatGPT・GitHub・Codexで設計から実装・レビューまで進める方法
2026.08.09
Codexにいきなりアプリ開発を依頼するのではなく、ChatGPTで設計と作業分解を行い、GitHub Issueへ整理してからCodexで実装する流れを紹介します。pushやPull Request、レビュー、手戻りとトークン消費を抑える考え方も説明します。
Windows版Codexで「CreateProcessAsUserW failed: 5」が出たときのPowerShell確認と対処
2026.08.07
Windows 11のCodexで、Get-Contentなどの読み取りコマンド実行時に「CreateProcessAsUserW failed: 5」が発生した事例をもとに、エラー内のpwsh.exeのパスやwhere.exe pwsh、Get-Commandの結果を確認し、PowerShellの導入形態を見直して改善するまでの切り分け手順を紹介します。
Windows 11でCodexを使い分ける:VS Code拡張・アプリ・CLIの違い
2026.08.03
Windows 11でCodexを使う場合の、VS Code拡張、Codexアプリ、CLIの使い分けを紹介します。既存プロジェクトの修正には、コードや差分を確認しやすいVS Code拡張が向いています。一方、新規プロジェクトのMVPをまとめて作る場合は、CodexアプリまたはCLIが便利です。Gitのcommitやpushを行う前に確認すべきポイントも説明します。
CodexをVS Codeで使い始める:Windows環境での基本操作と文字化け対策
2026.08.02
Windows 11のVisual Studio CodeにCodex拡張を導入し、ファイルの説明や小さな修正を依頼する基本的な使い方を紹介します。PowerShell 7のターミナル経由で日本語ファイルを扱う際の文字コード問題や、文字化けを防ぐための確認方法についても解説します。