はじめに
株式会社Fieldの吉田です。
日頃は大学に通いながら、FieldでHPやLPのデザイン、AIでのシステム開発を行っています。
プログラムを実行している間、処理が終わっているか確認するために何度もターミナルを開くのが面倒だったので、処理が終わったらApple Watchに通知が届く仕組みを作りました。
今回は、以下の4つを実装します。
- Ubuntu:15秒以上かかったコマンドが終了したら通知
- Windows:15秒以上かかったコマンドが終了したら通知
- Claude Code:許可待ちになって約15秒経過したら通知
- Claude Code:15秒以上かかった内部処理や応答が完了したら通知
無料の通知サービス「ntfy」を利用するので、Apple Watch専用アプリを作る必要はありません。
動作環境
- Ubuntu(zsh)
- Windows(PowerShell 5.1)
- iPhone / Apple Watch
- Claude Code
- ntfy
※ Ubuntuはzshを使用していることを前提に説明します。bashの場合は設定方法が異なります。
1. ntfyの準備
ntfyとは?
ntfyは、パソコンなどからスマートフォンに通知を送ることができる無料サービスです。
今回の仕組みは以下のようになります。
Ubuntu ──────────┐
│
Windows ─────────┼──→ ntfy ──→ iPhone ──→ Apple Watch
│
Claude Code ─────┘
iPhoneにntfyアプリをインストールすると、Apple Watchにも通知を転送できます。
① iPhoneにntfyをインストール
以下からntfyをインストールします。
アプリを開いたら、通知を許可してください。
② 通知用のトピック名を生成する
ntfyでは「トピック」という名前を使って通知先を指定します。
例えば、UbuntuとWindowsから別々に通知を送る場合、2つのトピックを使用します。
トピック名は、他人に推測されにくいランダムな文字列にします。
Ubuntuで生成
openssl rand -hex 16
Windows PowerShellで生成
[guid]::NewGuid().ToString("N")
それぞれ実行すると、32文字の英数字が出力されます。
例えば、次のような文字列です。
Ubuntu用:
a1b2c3d4e5f60718293a4b5c6d7e8f90
Windows用:
f9e8d7c6b5a403122130fedcba987654
※ 上記は説明用の例です。実際には自分で生成した文字列を使ってください。
生成した2つの文字列は、後で使うのでメモ帳などに控えておきます。
③ ntfyアプリにトピックを登録する
iPhoneのntfyアプリで、以下の操作をします。
- 「+」をタップする
- 「トピック」にUbuntuで生成した32文字を入力する
- 購読(Subscribe)する
- 同様にWindowsで生成した32文字も登録する
これで2つの通知先が登録されます。
④ 通知のテスト
Ubuntuで以下を実行します。
curl -d "Ubuntu TEST" \
https://ntfy.sh/YOUR_UBUNTU_TOPIC
YOUR_UBUNTU_TOPICには、②でUbuntu用に生成した32文字を入力します。
例えば、
curl -d "Ubuntu TEST" \
https://ntfy.sh/a1b2c3d4e5f60718293a4b5c6d7e8f90
という形です。
Windowsでは以下を実行します。
curl.exe -d "Windows TEST" `
https://ntfy.sh/YOUR_WINDOWS_TOPIC
こちらもYOUR_WINDOWS_TOPICを、Windows用に生成した32文字に置き換えます。
iPhoneに通知が届けば準備完了です。
※ Apple Watchに通知されない場合は、iPhoneの「Watch」アプリ→「通知」でntfyの通知が許可されているか確認してください。iPhoneを使用中は通知がiPhone側に表示される場合があります。
2. Ubuntuで15秒以上のコマンド終了を通知
Ubuntuでは、zshのpreexecとprecmdという機能を使います。
-
preexec:コマンドを実行する直前に動く -
precmd:コマンドが終了して次の入力待ちになる直前に動く
この2つを使って、コマンドの実行時間を測定します。
① 設定ファイルを開く
Ubuntuのターミナルで以下を実行します。
nano ~/.zshrc
.zshrcは、zshを起動するときに読み込まれる設定ファイルです。
② 以下のコードを末尾に追加
# ===== ntfy settings =====
# Replace with your Ubuntu topic
export NTFY_TOPIC="YOUR_UBUNTU_TOPIC"
# Notification threshold (seconds)
export NTFY_THRESHOLD=15
autoload -Uz add-zsh-hook
typeset -gi _watch_start=-1
_watch_preexec() {
_watch_start=$SECONDS
}
_watch_precmd() {
(( _watch_start >= 0 )) || return 0
local elapsed=$(( SECONDS - _watch_start ))
_watch_start=-1
# Ignore commands shorter than 15 seconds
(( elapsed >= NTFY_THRESHOLD )) || return 0
curl -fsS --max-time 8 \
-H "Title: Ubuntu Terminal" \
--data-binary "Command finished (${elapsed} sec)" \
"https://ntfy.sh/$NTFY_TOPIC" \
>/dev/null 2>&1 &!
}
add-zsh-hook preexec _watch_preexec
add-zsh-hook precmd _watch_precmd
変更する場所は以下の1か所だけです。
export NTFY_TOPIC="YOUR_UBUNTU_TOPIC"
YOUR_UBUNTU_TOPICを、先ほどUbuntu用に生成した32文字に置き換えます。
NTFY_THRESHOLD=15は、15秒以上かかったコマンドだけ通知するという意味です。
③ 保存して設定を反映
nanoで編集している場合は、Ctrl + O→Enter→Ctrl + Xで保存して終了します。
その後、以下を実行します。
source ~/.zshrc
④ 動作確認
sleep 16
sleep 16は、何もせず16秒間待機するコマンドです。
16秒後にコマンドが終了し、Apple Watchへ通知が届けば成功です。
これ以降、15秒以上のコマンド終了時に自動で通知されます。
3. Windowsで15秒以上のコマンド終了を通知
Windowsでは、PowerShellのprompt関数とコマンド履歴を利用します。
PowerShellはコマンドの実行開始時刻と終了時刻を記録できるため、その差から実行時間を計算します。
① 設定ファイルを開く
PowerShellで以下を実行します。
New-Item -ItemType Directory -Path (Split-Path $PROFILE) -Force | Out-Null
if (!(Test-Path $PROFILE)) {
New-Item -ItemType File -Path $PROFILE -Force | Out-Null
}
notepad $PROFILE
メモ帳が開きます。
すでに設定ファイルに内容がある場合は、念のためバックアップを取っておきましょう。
② 以下のコードを追加
# ===== ntfy settings =====
# Replace with your Windows topic
$global:WatchNtfyTopic = "YOUR_WINDOWS_TOPIC"
# Notification threshold (seconds)
$global:WatchNtfyThreshold = 15
$global:WatchLastHistoryId = (Get-History -Count 1).Id
function global:prompt {
$entry = Get-History -Count 1
if ($null -ne $entry -and
$entry.Id -ne $global:WatchLastHistoryId) {
$global:WatchLastHistoryId = $entry.Id
$elapsed = (
$entry.EndExecutionTime -
$entry.StartExecutionTime
).TotalSeconds
if ($elapsed -ge $global:WatchNtfyThreshold) {
$message = 'Command finished: {0:N1} sec' -f $elapsed
$body = [System.Text.Encoding]::UTF8.GetBytes($message)
try {
Invoke-RestMethod `
-Uri ("https://ntfy.sh/{0}" -f $global:WatchNtfyTopic) `
-Method Post `
-ContentType "text/plain; charset=utf-8" `
-Headers @{ Title = "Windows Terminal" } `
-Body $body `
-TimeoutSec 5 `
-ErrorAction Stop | Out-Null
}
catch {
Write-Warning $_.Exception.Message
}
}
}
return "PS $($executionContext.SessionState.Path.CurrentLocation)> "
}
変更する場所は以下の1か所だけです。
$global:WatchNtfyTopic = "YOUR_WINDOWS_TOPIC"
YOUR_WINDOWS_TOPICを、Windows用に生成した32文字に置き換えます。
WatchNtfyThreshold = 15は通知するまでの実行時間です。
※ 既存のprompt関数がある場合、このコードはそれを置き換えます。すでにプロンプトをカスタマイズしている場合は調整が必要です。
③ 設定を反映する
メモ帳で保存した後、PowerShellを一度閉じて開き直します。
④ 動作確認
Start-Sleep -Seconds 16
16秒後に通知が届けば成功です。
なお、Windows PowerShell 5.1では日本語メッセージが文字化けする場合があるため、今回は英語のメッセージを使用しています。
4. Claude Codeの許可待ちも通知する
Claude Codeでは、ファイル編集やコマンド実行の際にユーザーの許可が必要になることがあります。
この許可待ちに気づかず、作業が止まってしまうことがあるため、Apple Watchへ通知するようにします。
今回はClaude CodeのHooks機能を使用します。
Hooksとは?
Claude Codeで特定のイベントが発生した際、自動的にプログラムを実行する機能です。
今回はNotification Hookのpermission_promptイベントを使用します。
通常、ターミナルで許可待ちが約6秒続いたときにイベントが発生するため、そこからさらに9秒待って通知を送ります。
Claude Codeが許可を要求
↓
約6秒後にNotification Hookが起動
↓
PowerShellスクリプトで9秒待機
↓
ntfyでApple Watchに通知
① 通知スクリプトを作成
Windows PowerShellで以下を実行します。
New-Item -ItemType Directory -Path "$HOME\.claude\hooks" -Force | Out-Null
notepad "$HOME\.claude\hooks\permission-notify.ps1"
メモ帳が開くので、以下を貼り付けます。
# Wait 9 seconds
Start-Sleep -Seconds 9
# Replace with your Windows topic
$topic = "YOUR_WINDOWS_TOPIC"
$message = "Claude Code is waiting for your approval."
$body = [System.Text.Encoding]::UTF8.GetBytes($message)
try {
Invoke-RestMethod `
-Uri ("https://ntfy.sh/{0}" -f $topic) `
-Method Post `
-ContentType "text/plain; charset=utf-8" `
-Headers @{ Title = "Claude Code - Permission needed" } `
-Body $body `
-TimeoutSec 8 `
-ErrorAction Stop | Out-Null
}
catch {
Add-Content `
-Path (Join-Path $env:TEMP "claude-ntfy-error.log") `
-Value $_.Exception.Message
}
ここでも1か所変更します。
$topic = "YOUR_WINDOWS_TOPIC"
YOUR_WINDOWS_TOPICを、3章のWindowsターミナルで使用したものと同じ32文字に置き換えてください。
新しくトピックを生成する必要はありません。
② Claude CodeにHookを登録
次のファイルを開きます。
notepad "$HOME\.claude\settings.json"
settings.jsonに、以下の設定を追加します。
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\permission-notify.ps1"
],
"async": true
}
]
}
]
}
}
変更する場所
C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\permission-notify.ps1
YOUR_USERNAMEはWindowsのユーザー名に変更してください。
自分のユーザー名はPowerShellで次のコマンドを実行すると確認できます。
$env:USERNAME
例えばhyoshと表示されれば、次のようになります。
C:\\Users\\hyosh\\.claude\\hooks\\permission-notify.ps1
※ settings.jsonにすでに設定がある場合は、ファイル全体を上書きせず、既存のhooksに追加してください。JSONでは同じ名前のキーを重複させないようにします。
③ 通知スクリプトの動作確認
PowerShellで以下を実行します。
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File "$HOME\.claude\hooks\permission-notify.ps1"
約9秒後に以下の通知が届けば成功です。
Claude Code - Permission needed
Claude Code is waiting for your approval.
④ Claude Codeで実際にテスト
Claude Codeを再起動します。
claude
Claude Code内で以下を入力します。
/hooks
Notificationにpermission_promptが登録されているか確認します。
次に、Claude Codeで許可が必要な操作を実行させます。
許可画面が表示されたら、何も操作せず待機します。
約15秒後にApple Watchへ通知が届けば成功です!
※ この仕組みは厳密に「許可待ちが15秒継続している」と再判定するものではありません。待機中に許可しても、通知される場合があります。
5. Claude Codeの処理が15秒以上かかったときも通知する
ここからは追加実装です。
4章までの設定では、Claude Codeの「許可待ち」は通知できますが、Claude Codeが処理を終えたことは通知できません。
また、Windowsのコマンド終了通知だけでは、Claude Code内部の処理終了を検知できません。
例えばPowerShellで、
claude
と実行すると、PowerShellからはclaudeという1つのコマンドが動き続けているように見えます。
そのため、Claude Codeで何度処理が完了しても、PowerShell側の終了通知は発火せず、Claude Code自体を終了したときに初めて通知されます。
そこで、Claude Code内部の処理完了を直接検知するHookを追加します。
5.1 Claude Codeの処理終了を検知する仕組み
Claude Codeには、以下のHookがあります。
| Hook | 動作 |
|---|---|
UserPromptSubmit |
ユーザーが指示を送信したとき |
Stop |
Claude Codeが応答を完了したとき |
PreToolUse |
Claude Codeがツールを実行する直前 |
PostToolUse |
ツールが正常終了したとき |
PostToolUseFailure |
ツールが失敗したとき |
今回は2種類の時間を計測します。
① Claude Codeの応答全体の実行時間
ユーザーが指示を送信
↓
UserPromptSubmit:開始時刻を保存
↓
Claude Codeが処理
↓
Stop:終了時刻を取得
↓
15秒以上なら通知
② Claude Code内部のツール実行時間
PreToolUse:ツール実行開始
↓
PowerShellなどで処理を実行
↓
PostToolUse:ツール終了
↓
15秒以上なら通知
応答全体の完了だけでなく、内部で実行された長時間のツール処理も検知できます。
5.2 応答全体の終了通知スクリプトを作成
まず、Windows PowerShellで以下を実行します。
notepad "$HOME\.claude\hooks\turn-notify.ps1"
開いたファイルに以下を入力します。
param(
[ValidateSet("Start", "Stop")]
[string]$Mode
)
# Replace with your Windows topic
$topic = "YOUR_WINDOWS_TOPIC"
$threshold = 15
$stateDir = Join-Path $env:TEMP "claude-turn-timers"
$log = Join-Path $env:TEMP "claude-turn-notify.log"
try {
# Read Claude Code's JSON as UTF-8
$reader = [System.IO.StreamReader]::new(
[Console]::OpenStandardInput(),
[System.Text.Encoding]::UTF8
)
$data = $reader.ReadToEnd() | ConvertFrom-Json
$id = [string]$data.session_id
if ([string]::IsNullOrWhiteSpace($id)) {
exit 0
}
New-Item -ItemType Directory -Path $stateDir -Force |
Out-Null
$safeId = $id -replace '[^a-zA-Z0-9_-]', '_'
$stateFile = Join-Path $stateDir "$safeId.txt"
$now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
if ($Mode -eq "Start") {
[System.IO.File]::WriteAllText(
$stateFile, $now.ToString()
)
Add-Content $log "START $id"
}
if ($Mode -eq "Stop" -and (Test-Path $stateFile)) {
$start = [long](
[System.IO.File]::ReadAllText($stateFile).Trim()
)
Remove-Item $stateFile -Force
$elapsed = ($now - $start) / 1000.0
Add-Content $log ("STOP elapsed={0:N1}s" -f $elapsed)
if ($elapsed -ge $threshold) {
$message = "Claude Code finished in {0:N1} seconds" -f $elapsed
$body = [System.Text.Encoding]::UTF8.GetBytes($message)
Invoke-RestMethod `
-Uri ("https://ntfy.sh/{0}" -f $topic) `
-Method Post `
-ContentType "text/plain; charset=utf-8" `
-Headers @{ Title = "Claude Code - Task completed" } `
-Body $body `
-TimeoutSec 5 `
-ErrorAction Stop | Out-Null
Add-Content $log "NOTIFICATION SENT"
}
}
}
catch {
Add-Content $log ("ERROR: " + $_.Exception.Message)
}
変更する場所
$topic = "YOUR_WINDOWS_TOPIC"
この部分を、Windows用に生成した32文字に置き換えます。
$threshold = 15は、15秒以上で通知する設定です。
5.3 ツール終了通知スクリプトを作成
続いて以下を実行します。
notepad "$HOME\.claude\hooks\tool-notify.ps1"
以下のコードを保存します。
param(
[ValidateSet("Pre", "Post")]
[string]$Mode
)
# Replace with your Windows topic
$topic = "YOUR_WINDOWS_TOPIC"
$threshold = 15
$log = Join-Path $env:TEMP "claude-tool-notify.log"
$stateDir = Join-Path $env:TEMP "claude-tool-timers"
try {
# Read UTF-8 JSON correctly
$reader = [System.IO.StreamReader]::new(
[Console]::OpenStandardInput(),
[System.Text.Encoding]::UTF8
)
$data = $reader.ReadToEnd() | ConvertFrom-Json
$id = [string]$data.tool_use_id
if ([string]::IsNullOrWhiteSpace($id)) {
exit 0
}
New-Item -ItemType Directory -Path $stateDir -Force |
Out-Null
$key = "{0}_{1}" -f $data.session_id, $id
$key = $key -replace '[^a-zA-Z0-9_-]', '_'
$stateFile = Join-Path $stateDir "$key.txt"
$now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
if ($Mode -eq "Pre") {
[System.IO.File]::WriteAllText(
$stateFile, $now.ToString()
)
exit 0
}
$elapsed = $null
if ($null -ne $data.duration_ms) {
$elapsed = [double]$data.duration_ms / 1000.0
}
elseif (Test-Path $stateFile) {
$start = [long](
[System.IO.File]::ReadAllText($stateFile).Trim()
)
$elapsed = ($now - $start) / 1000.0
}
Remove-Item $stateFile -ErrorAction SilentlyContinue
if ($null -eq $elapsed) {
exit 0
}
$tool = [string]$data.tool_name
Add-Content $log (
"TOOL {0}: {1:N1}s" -f $tool, $elapsed
)
if ($elapsed -ge $threshold) {
$message = "Claude Code: {0} finished in {1:N1} sec" -f $tool, $elapsed
$body = [System.Text.Encoding]::UTF8.GetBytes($message)
Invoke-RestMethod `
-Uri ("https://ntfy.sh/{0}" -f $topic) `
-Method Post `
-ContentType "text/plain; charset=utf-8" `
-Headers @{ Title = "Claude Code - Tool completed" } `
-Body $body `
-TimeoutSec 5 `
-ErrorAction Stop | Out-Null
Add-Content $log "NOTIFICATION SENT"
}
}
catch {
Add-Content $log ("ERROR: " + $_.Exception.Message)
}
こちらも以下の1か所だけ、Windows用の32文字に変更します。
$topic = "YOUR_WINDOWS_TOPIC"
これで、ツール実行時間が15秒以上の場合に通知されるようになります。
5.4 Claude CodeにHookを登録する
次に、作成した2つのスクリプトをClaude Codeに登録します。
Windows PowerShellで次を実行します。
notepad "$HOME\.claude\settings.json"
4章で登録したNotificationに加え、UserPromptSubmit、Stop、PreToolUse、PostToolUse、PostToolUseFailureを追加します。
例えば、Windowsのユーザー名がYOUR_USERNAMEの場合、hooksの部分は次のようになります。
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\permission-notify.ps1"
],
"async": true
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\turn-notify.ps1",
"Start"
]
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\turn-notify.ps1",
"Stop"
]
}
]
}
],
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\tool-notify.ps1",
"Pre"
]
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\tool-notify.ps1",
"Post"
],
"async": true
}
]
}
],
"PostToolUseFailure": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"C:\\Users\\YOUR_USERNAME\\.claude\\hooks\\tool-notify.ps1",
"Post"
],
"async": true
}
]
}
]
}
}
変更する場所
すべてのYOUR_USERNAMEをWindowsのユーザー名に変更してください。
例えばユーザー名がhyoshなら、
C:\\Users\\hyosh\\.claude\\hooks\\turn-notify.ps1
のようになります。
※ これはhooksの設定例です。既存のsettings.jsonにほかの設定やHookがある場合は、ファイル全体を置き換えず、必要な項目を追加してください。編集前にバックアップを取ることをおすすめします。
5.5 動作確認
Claude Codeを再起動します。
claude
次に、Claude Codeへ以下のように指示します。
PowerShellで
Start-Sleep -Seconds 20を実行し、処理が終わったら結果を報告してください。
20秒以上かかったツールが終了すると、次のような通知が届きます。
Claude Code - Tool completed
Claude Code: PowerShell finished in 20.8 sec
さらにClaude Codeの応答全体が15秒以上かかった場合は、以下も届きます。
Claude Code - Task completed
Claude Code finished in 24.9 seconds
Claude Codeそのものを終了しなくても通知が届くことがポイントです。
実際に動いているかは、別のPowerShellで次のコマンドを実行して確認できます。
ツール終了ログ
Get-Content "$env:TEMP\claude-tool-notify.log" -Tail 10
応答完了ログ
Get-Content "$env:TEMP\claude-turn-notify.log" -Tail 10
私の環境では、以下のようなログが出力されました。
TOOL PowerShell: 20.8s
NOTIFICATION SENT
START ...
STOP elapsed=24.9s
NOTIFICATION SENT
NOTIFICATION SENTが表示されていれば、ntfyへの送信処理が成功しています。
なお、ツール終了と応答全体の完了が両方15秒以上の場合は、通知が2件届くことがあります。
6. よくあるエラーと対処法
通知が「????」になる
Windows PowerShell 5.1では、日本語の文字コードが原因で通知が文字化けする場合があります。
今回は通知メッセージを英語に統一して対処しています。
手動通知は届くのに、自動通知が届かない
Ubuntuでは、以下でトピックが設定されているか確認します。
echo "$NTFY_TOPIC"
何も表示されなければ.zshrcの設定が正しく読み込まれていません。
source ~/.zshrc
を実行して再確認します。
Windowsでは、以下でトピック名を確認します。
$global:WatchNtfyTopic
設定した32文字が表示されるか確認してください。
Claude Codeを終了したときにしか通知が届かない
これは、PowerShellがClaude Code全体を1つのコマンドとして扱っているためです。
Claude Codeを起動した状態で処理終了通知を受け取るには、5章のStopやPostToolUse Hookを利用します。
Claude Codeの日本語を含む処理でJSON解析エラーが発生する
今回の実装で特に苦労した部分です。
最初はClaude Codeから送られてくるJSONを、次のように読み込んでいました。
$data = [Console]::In.ReadToEnd() | ConvertFrom-Json
しかし、Windows PowerShell 5.1では、標準入力の文字コードがUTF-8として正しく解釈されず、日本語が文字化けする場合があります。
例えば、日本語のコマンドや応答がJSONに含まれていると、ConvertFrom-Jsonで解析エラーになりました。
そこで、次のように修正しました。
$reader = [System.IO.StreamReader]::new(
[Console]::OpenStandardInput(),
[System.Text.Encoding]::UTF8
)
$data = $reader.ReadToEnd() | ConvertFrom-Json
これにより、標準入力をUTF-8として明示的に読み取れます。
実際にこの修正を行ったことで、それまでエラーになっていたClaude Codeのツール終了通知が正常に送信されるようになりました。
バックグラウンド実行には注意
今回のUbuntu・Windowsのコマンド終了通知は、基本的に対話型ターミナルで実行したコマンドが対象です。
nohupや&などでバックグラウンド実行した処理は、実際の処理終了を検知する別の仕組みが必要になります。
また、SSH接続先で実行したコマンドを個別に監視したい場合は、接続先のシェルにも設定する必要があります。
おわりに
今回はntfyを利用して、Ubuntu・Windows・Claude CodeからApple Watchへ無料で通知する仕組みを作りました。
最終的には、以下の4つを実現できました。
| 監視対象 | 通知条件 |
|---|---|
| Ubuntuターミナル | コマンドが15秒以上で終了 |
| Windows PowerShell | コマンドが15秒以上で終了 |
| Claude Codeの許可待ち | 許可待ち開始から約15秒 |
| Claude Codeの内部処理・応答 | 15秒以上で終了 |
一度設定してしまえば、長時間のプログラム実行やClaude Codeの許可待ち、処理終了などをApple Watchから確認できます。
特に、Claude Codeを起動したまま別の作業をしている場合に便利です。
無料で実現できるので、ぜひ試してみてください。
― Happy coding ―