ターミナルの長いコマンドが終わったら通知する

40 分かかるビルドに付き添うのはもうやめましょう。どんなコマンドの後ろにも 1 行足すだけで、結果がスマートフォンに届きます。すでに席を離れていても。

更新日

目次

学習の実行、フルテスト、docker build、あるいは AI コーディングエージェントに長いタスクを任せる。そのあと選べるのは、どちらも良くない 2 つだけです。プログレスバーを眺めて座っているか、席を離れて 20 分後に戻り、実は 90 秒で失敗していたと知るか。

3 つ目の選択肢があります。1 行で済みます。

その 1 行

Echobell でチャンネルを作り、webhook URL をコピーして、実行するコマンドの後ろに付けます。

pnpm build; curl -sS -X POST https://hook.echobell.one/t/YOUR_TOKEN \
  -H 'content-type: application/json' \
  -d '{"title":"ビルド終了","body":"echobell-web"}'

&& ではなく ; である点に注意してください。&& にすると成功したときだけ通知が飛びます。これはちょうど逆で、失敗こそがいちばん知りたい状況です。

終了コードも一緒に送る

「終わりました」だけの通知は、話の半分でしかありません。ステータスも取りましょう。

pnpm build; s=$?; curl -sS -X POST https://hook.echobell.one/t/YOUR_TOKEN \
  -H 'content-type: application/json' \
  -d "{\"title\":\"ビルド $([ $s -eq 0 ] && echo 成功 || echo 失敗)\",\"status\":\"$s\"}"

s=$? はコマンドの直後に置く必要があります。あいだに何かを挟むと([ テスト自体を含めて)$? が上書きされます。

シェル関数にする

毎回これを打っていては本末転倒です。~/.zshrc~/.bashrc に次を入れておきましょう。

notify() {
  "$@"
  local status=$?
  curl -sS -X POST "$ECHOBELL_HOOK" \
    -H 'content-type: application/json' \
    -d "{\"command\":\"$*\",\"status\":\"$status\",\"host\":\"$(hostname -s)\"}" \
    >/dev/null
  return $status
}

ECHOBELL_HOOK はシェルのプロファイルで設定します。さらに良いのは、dotfiles のリポジトリには一切入れず、コミットしないファイルから export することです。あとはこうするだけ。

notify pnpm test
notify cargo build --release
notify python train.py

最後の return $status は重要です。これがあることで notify は透過的に振る舞い、notify make && ./deploy.sh も期待どおり動きます。

この payload に対して、チャンネルのテンプレートはこう書けます。

タイトル

{{command}} · {{status}}

本文

{{host}} にて

失敗したときだけ鳴らしてほしい

たいていの実行は成功しますし、それをいちいち知る必要はありません。チャンネルを 2 つに分けるときれいに解決します。すべてを受ける通常チャンネルと、条件を付けた着信チャンネルです。

status != "0"

ベッドから起きてでも対応したいものだけ 2 つ目のチャンネルに向ければ、成功した実行は静かに過ぎていきます。

ノート PC を閉じても、SSH が切れても届くように

コマンドを SSH 越しに走らせている場合、ノート PC を閉じるとシェルごと落ちて通知は永遠に飛びません。対処は 2 つ。

tmux —— セッション内で起動してデタッチします。

tmux new -d -s build 'notify pnpm build'

nohup —— 単発なら。

nohup bash -c 'notify pnpm build' >/dev/null 2>&1 &

どちらでもプロセスは接続より長く生き残り、あなたがつないでいるかどうかに関係なく通知は届きます。

AI コーディングエージェント

同じやり方は、長いタスクに取り組む CLI エージェントにもそのまま使えます。

notify codex exec "決済モジュールをリファクタしてテストを流して"

途中で止まって人を待つエージェント(承認待ち、権限確認待ち)には、完了通知は誤った道具です。まだ完了していないからです。その場合はエージェント自身の hook やコールバックが必要で、プッシュよりも電話がふさわしい。エージェントの承認待ちを電話に変えるがその話で、Claude Code の Notification hook と agent_needs_input matcher も扱っています。

両方使いましょう。「詰まった」は hook、「終わった」はシェル関数です。

通知に入れてはいけないもの

コマンドの出力。 失敗したビルドの末尾数行を本文に流し込みたくなりますが、こらえてください。ビルドログにはトークンや接続文字列、顧客データが、多くの人が思うより頻繁に含まれます。そして通知の本文はロック画面に出ます。終了コードだけ送って、ターミナルは自分で見に行きましょう。

チャンネル URL を公開 dotfiles リポジトリに。 この URL を知っていれば誰でもあなたのチャンネルに投稿できます。バージョン管理しないファイルに置き、POST のみ を有効にして、リンクプレビューが誤って発火しないようにしてください。

よくある質問

terminal-notifiernotify-send ではだめですか?

あれはコマンドを実行しているマシン上に通知を出します。目の前に座っているなら十分です。この構成が狙っているのは、座っていないときです。リモートのマシン、閉じたノート PC、別の部屋。

Windows でも動きますか?

考え方は同じで、書き方が違います。PowerShell なら Invoke-RestMethod -Method Post -Uri $env:ECHOBELL_HOOK -ContentType application/json -Body $json が相当し、$? の代わりに $LASTEXITCODE を使います。

時計にも届きますか?

届きます。購読はペアリング済みの Apple Watch にも配信され、「ビルドが終わった」を知るには正直これがいちばん適した形です。

コマンドが 12 時間かかる場合は?

この構成にタイムアウトはありません。コマンドが返った時点で curl が走るだけです。接続が切れてもプロセスが道連れにならないよう、tmux の下で実行してください。

チームメンバーも同じ通知を受け取れますか?

受け取れます。チャンネルを共有すれば、購読者ごとに通知タイプを選べます。共用の学習マシンで「GPU がまた空いた」を複数人が知りたい場合に便利です。

まとめ

シェル関数ひとつ、チャンネルひとつ、失敗だけ受けたいなら条件をひとつ。設定に 2 分ほど、返ってくるのはプログレスバーを眺めていた 20 分です。

iPhone 版 Echobell をダウンロード、または Google Play で入手して、席を立つに足るくらい長いものでまず試してみてください。


関連記事