waitbus について
waitbusは、単一ワークステーション上のエージェント、スクリプト、サービスがCI・テスト・コンテナ・ファイルシステムのイベントを配信し、待機するためのイベントバスです。イベントはSQLiteに保存されて再生でき、ポーリングやクラウドを必要としません。
主な機能
- 015種類の組み込みイベントソース
- 02複合条件によるブロッキング待機
- 03イベント配信とSQLite再生ログ
- 04プラグイン式イベントソース
- 05LinuxとmacOSのデーモン対応
活用シーン
- 01テスト、ビルド、CIの完了待ち
- 02エージェント間での失敗イベント共有
- 03ファイルやコンテナイベントでのスクリプト起動
MCP 対応
waitbusはMCP SDKを使用しますが、入力にはMCPクライアントに公開する具体的なインターフェースの説明がありません。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
5掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| repo | string|null | いいえ | 絞り込み対象の owner/repo。null の場合は、設定済みのすべてのフィルターを返します(pr_aggregate ビューでは必須)。 |
| view | enum | はい | 返す CI ビューを指定します。'status':リポジトリごとの最新 workflow_run。'failed_jobs':最近の失敗した workflow_job 行。'pr_aggregate':1 件のプルリクエストに関するすべての実行とジョブ(repo と pr_number が必要)。status | failed_jobs | pr_aggregate |
| limit | integer | いいえ | failed_jobs ビューで返す失敗ジョブの最大数(新しいものから順)。 |
| pr_number | integer|null | いいえ | プルリクエスト番号。pr_aggregate ビューでのみ必須。 |
詳細
waitbus:ワークステーション上でローカルに動作する、ハーネス間ステータスバス。エージェントのための D-Busに、リプレイログと待機プリミティブを追加
すべてのローカルソースを一度に対象に、ブロックして待機し、照会できる単一の wait 動詞です。マシン上のエージェント、CI ジョブ、テスト、コンテナのいずれかが完了または失敗すると、同じマシン上のほかのすべてのツールに通知されます。Claude Code、Cursor、スクリプト、CI も対象です。サーバー通知に対応するクライアントにはプッシュで通知され、それ以外のクライアントではブロックする waitbus wait を一度実行するだけです。waitbus のクラウドも、アカウントも、テレメトリーもありません。処理はすべてマシン上で行われます。
以下は、Pydantic AI のエージェントと LangGraph のエージェントです。異なる 2 つのフレームワークが別々の OS プロセスとして動作し、両方が 1 つのローカル waitbus バスで待機します。一方が失敗すると、もう一方のフレームワークで動くピアと、ライブの waitbus top 表示が、単一の失敗ブロードキャストに反応します。

実際のフレームワークと waitbus の subscribe/emit を使用しています。エージェントの LLM は決定論的なフェイクで、失敗は注入されたイベントなので、この動画は完全にオフラインで再生できます。主張を再現して確認するには(録画を見るだけでなく)、手軽な単一エージェントのチュートリアル(クローンもインストールも不要)なら uvx waitbus demo を実行してください。上記のとおり、2 つのフレームワークを使った実証をそのまま再現するには、リポジトリをクローンして uv run --group agent-recipes python -m examples.hero_swarm を実行してください(Linux で検証済み。「PROVEN: two DIFFERENT frameworks woke on ONE peer's failure」と出力されます)。高画質の MP4 は hero.mp4 にあります。メンテナーは docs/demo/.waitbus-demo/ から make hero でこの動画を再レンダリングします(開発専用。vhs、ttyd、tmux、JetBrains Mono が必要です)。
インストール不要ですぐにお試しいただけます:
uvx waitbus demoを実行すると、実際のローカルバスが起動し、イベントが届くと即座に戻ります。完全オフラインで動作します(約 8 秒)。
waitbus は、1 台のマシン上のツール同士が互いの状態を把握できるようにする、ワークステーション上でローカルに動作するハーネス間ステータスバスです。イベントの取り込み、ブロードキャスト、リプレイという 3 つの機能を提供します。
取り込み: ブロッキング型の wait/emit プリミティブにより、あらゆるエージェントやスクリプトが(Cursor、Claude Code、同じマシン上の任意のツールをまたいで)組み込みの 5 つのソース(GitHub Actions CI、pytest セッション、Docker コンテナのライフサイクル、ファイルシステムの変更、Prometheus Alertmanager)と、waitbus.sources.v1 エントリーポイントグループに登録された任意のプラグインソースからのイベントを待機または送信できます。
ブロードキャスト: イベントは到着した瞬間に SQLite に保存され、ブロードキャストデーモンが各レコードを、ローカルソケット経由で約 1 ミリ秒以内に接続中のすべてのコンシューマーへ配信します(実測値です。benchmarks/BENCHMARKING.md を参照)。エージェントは waitbus wait(--all-of/--first-of を使えば複数のソースを一度に対象にできます)で待機できるため、エージェント側のポーリングは不要で、関心のあるイベントが発生するまでは CPU を使いません。また、waitbus on <predicate> -- <command> を使うと、そのイベントが発生した瞬間にコマンドを実行できます(デーモンではなく CLI プロセス内で、シェルを介さず execve により実行します。イベント値は名前空間付きの WAITBUS_* 環境変数と $WAITBUS_EVENT_FILE として渡され、argv には渡されません。そのため、イベントの内容でフラグを注入したり、PATH を上書きしたりすることはできません)。マシン上のすべてのエージェントが同じバスを共有するため、同一マシン内の調整用バックプレーンとしても機能します。1 つのエージェントがイベントを送信すると、ほかのエージェントが起動します。
リプレイ: 耐久性のあるリプレイログ(since=)があるため、オフラインだったコンシューマーもイベントを見逃さずに追いつけます。また、waitbus events analyze でバスに保存された内容をクエリできます。これは、OS がすでに採用しているローカルのオプトイン型イベントブロードキャストモデル(D-Bus シグナル、inotify、journald)に、リプレイログと待機述語を追加したものです。(最初に接続されたソースが GitHub Actions だったため、例は CI から始まりますが、waitbus は CI 専用ではありません。)依存関係は軽量です。typer、msgspec、platformdirs、pydantic-settings、prometheus_client、stamina、および mcp SDK のみで、重い TUI や暗号化の依存関係はありません。デーモンのアイドル時の RSS は約 40 MB です(ベンチマーク用ホストでの実測値の p50 で、その大半は CPython インタープリターのベースラインです)。SQLite イベントストアと、長さプレフィックス方式のフレーミングを使う AF_UNIX SOCK_STREAM ブロードキャストバス上で動作します。Linux(systemd-user)と macOS(launchd)で動作します。
対象ユーザー
次のような方に向いています……
- 異種混在のエージェント群を運用している方(同じワークステーション上で Claude Code と Cursor と バックグラウンドスクリプトを併用し、それぞれの完了や失敗をほかのエージェントにも知らせたい方)。
- 複数のソースをまたいで待ちたい方。「テストが通り かつ ビルドが完了し かつ CI がグリーンになるまで待つ」を、スクリプト内で 1 つの述語として記述できます(
waitbus wait --all-of ...)。これを表現できるものはほかにありません。 - ローカルのさまざまな処理を、LLM トークンもポーリングも使わずに待つことを日常的に行いたく、そのためにデーモンを実行してもよい方。
- **自分のマシン上のデーモンが信頼できることを重視する方。**再現可能なビルド、オフライン、クラウド不使用、アカウント不要、テレメトリーなし。
次のような方には向いていません……
- 1 つの GitHub リポジトリの CI だけを待つ方。
gh run watchをお使いください。セットアップ不要で、その 1 つのジョブに限れば、デーモンを動かす理由になるほどの優位性はありません。 - ファイル変更への反応だけが必要な方。
inotifywait/entrをお使いください。生のファイルシステムのレイテンシーでは、はるかに高速で(自前のベンチマークでも確認済み)、デーモンも不要です。 - **クラウド、マシン間、またはチームでの調整を求める方。**ローカルコアの対象範囲外として、意図的に除外しています。
- エージェント間の宛先指定メッセージングを製品の中心として求める方(スレッド、受信トレイ、ルーティングなど)。ここでの主眼は、ソースから取り込んだイベントのブロードキャストです。
request()/respond()機能もありますが、その用途を中心とするなら、専用のメッセージキューのほうが適しています。
60 秒で試す
uvx waitbus demo # one command, no install needed
waitbus demo は一時的な状態ディレクトリを作成してブロードキャストデーモンを起動し、2 つのフェーズを実行します。**フェーズ 1、ここがポイントです:**エージェントが waitbus wait(実際のコマンドでも使われる同じイベント送出エンジン)で、ポーリングもアイドル時の CPU 使用もなしに待機します。GitHub の workflow_run イベントが到着すると、待機が終了し、デモはイベント発生から待機解除までの実測レイテンシーを表示します。**フェーズ 2、対応範囲の広さです:**同じプリミティブがすべてのソースのイベントを配信します。pytest_session、docker_container、fs_change イベントが、稼働中のサブスクライバーにブロードキャストされます。一時ディレクトリの外にあるマシン上のものには一切触れません。

録画済みの MP4 と GIF による解説は、docs/demo/.waitbus-demo/demo.mp4 と demo.gif にあります(テープスクリプトは demo.tape です)。このディレクトリで make demo を実行すれば、同じ内容を再現できます(VHS ≥ 0.10.0、ttyd、および ffmpeg が必要です)。Makefile は VHS のバージョン下限を適用し、テープの動作を知らないうちに変えてしまう可能性のある古いバイナリでのレンダリングを拒否します。
デモが送出する 4 つのイベントは、プロセス内で合成されたものです。実際の HTTP リスナーも、実際の pytest 実行も、実際の Docker デーモンも、実際の watchdog もありません。各イベントの送出前にバナーを表示してこのことを明示し、
waitbus statsの出力と同様にしています。実際の GitHub webhook 配信を waitbus に接続する方法は、以下のクイックスタートをご覧ください。
クイックスタート
約10秒で基本機能を確認できます。フォアグラウンドでデーモンを1つ起動し、イベントを1つ送るだけです。サービスとしてインストールする必要はありません。CLIをインストールして状態を初期化します。
uv tool install waitbus # or: pipx install waitbus
waitbus init # one-time setup: state dirs, SQLite schema, scaffolds
次に、2つのターミナルで、ブロッキングする wait がバスに emit が届いた瞬間に復帰する様子を確認します。
# Terminal A -- run the broadcast daemon in the foreground (Ctrl-C to stop):
waitbus broadcast serve
# Terminal B -- block on the next agent event, then emit one from the same shell:
waitbus wait --source agent --match 'fields.event_type="agent_message"' --timeout 30s &
sleep 1 # let the backgrounded wait attach to the bus before we emit (a
# long-lived subscriber would already be attached; this one-liner
# just compresses "wait, then something happens" into one shell)
waitbus emit \
--delivery-id demo-1 --source agent --event-type agent_message \
--owner local --repo local --received-at "$(date +%s)" \
--payload-json '{"hello":"world"}' --ingest-method manual
wait # the backgrounded `waitbus wait` prints "matched on source=agent" and exits 0
この往復処理、つまりポーリングなしで待機し、イベントを送信して、待機を解除することが、この基本機能のすべてです。以下では、実際のソースに接続する方法と、必要に応じてサービスマネージャーの下でデーモンを常時実行する方法を説明します。
フリートを常時実行する(任意)
waitbus install-credentials github-webhook-secret # optional: only for GitHub-CI waiting (enables the webhook listener)
waitbus install-systemd # Linux: copy + enable the 8 systemd-user units
waitbus install-launchd # macOS: copy + bootstrap the 4 LaunchAgent plists
waitbus read-events watch # live tail of incoming events
install-systemd は Linux 専用で、install-launchd は macOS 専用です。
各コマンドは別のプラットフォームでは実行を拒否し、適切なコマンドを案内します。
イベントが流れ始めたら、waitbus wait を使って、次に条件に一致するイベントが届くまで任意のスクリプトやエージェントを待機させられます。ソースやフィールドを問わず、終了コードで結果を返します。wait 側では常にセットアップ不要ですが、待機対象のイベントは何らかの仕組み(オプトインのエミッターまたはソースウォッチャー)から生成される必要があります。そのため、以下の各例では、復帰するために何がイベントを送信する必要があるかを記載しています。
# pytest: wait for any session to finish.
# wait is zero-setup; a pytest_session event needs the opt-in emitter --
# run your suite with: pytest -p waitbus.sources.pytest_emit --waitbus-emit
waitbus wait --source pytest --match 'fields.event_type="pytest_session"' --timeout 10m
# Docker: wait for a container to exit.
# wait is zero-setup; a docker_container event needs the docker watcher running --
# start it with: waitbus source docker (see `waitbus source docker --help`)
waitbus wait --source docker --match 'fields.event_type="docker_container"' --timeout 30s
# Filesystem: wait for a watched path to change.
# wait is zero-setup; an fs_change event needs the fs watcher running --
# start it with: waitbus source fs <dir> (see `waitbus source fs --help`)
waitbus wait --source fs --match 'fields.event_type="fs_change"' --timeout 5m
# GitHub CI: wait on a commit's terminal conclusion (needs webhook wiring -- see below)
waitbus wait --sha 7f3a1b2 --timeout 5m
ファイルが変更されたときにコマンドを再実行するために watchexec や entr を使ったことがあれば、waitbus wait も同じ考え方です。ただし、より広い範囲を対象にしています。ファイルの変更を待てるだけでなく、CI の実行、pytest セッション、コンテナの終了、別のエージェントのイベントも待機でき、その結果を終了コードで返します。さらに、その下で稼働するバスは、こうしたイベントをすべてマシン上の他のすべてのツールに配信します。
アーキテクチャ
docs/architecture.mmd から生成(PyPI などの Mermaid 非対応の表示環境でも図を表示できるよう、GitHub だけでなく静的画像を使用しています)。mmdc -i docs/architecture.mmd -o docs/architecture.png で再生成できます。
2種類の入力元が、同じストアにイベントを格納します。リモート Webhook(GitHub、Alertmanager)は HTTPS 経由で届き、waitbus listener serve を通ります。一方、プロセス内ソース(pytest、docker、fs、プラグイン、任意のエージェント)は、リスナーもネットワークホップも介さず、公開されている emit() API を呼び出して行を直接書き込みます。Webhook を受信できないリポジトリ(上流リポジトリ、フォーク)では、45秒間隔で ETag ポーリングによるフォールバックが実行されます。どの経路も同じ INSERT OR IGNORE を通じて書き込むため、再配信は冪等です。また、どの行もブロードキャストの呼び出しを発生させるため、どの入力経路から生成された場合でも、サブスクライバーは約1ミリ秒以内に起動します。
waitbus と MCP Tasks(task=True)、およびローカルのエージェント間バス(agent-message-queue、claude-code-inter-session)の関係については、docs/COMPETITIVE_LANDSCAPE.md を参照してください。
インストール
Python CLI ツールとして
uv tool install waitbus # or: pipx install waitbus
waitbus init # one-time setup: state dirs, SQLite schema, scaffold files
waitbus install-credentials github-webhook-secret # optional: HMAC for the GitHub webhook listener (opt-in)
waitbus install-credentials alertmanager-hmac # optional: alertmanager / watchdog HMAC
waitbus install-systemd # Linux: copy + enable the 8 systemd-user units
waitbus install-launchd # macOS: copy + bootstrap the 4 LaunchAgent plists
各コマンドはべき等です。install-credentials <name> を再実行すると、認証情報がローテーションされます(ローテーション後、GitHub webhook と Alertmanager を再設定し、systemctl --user restart waitbus-listener.service を実行してください)。
インストール後、PATH 上にコンソールスクリプト waitbus が配置されます。すべてのデーモンのエントリーポイントと管理コマンドはサブコマンドから実行できます。
| サブコマンド | 目的 |
|---|---|
waitbus init | 状態ディレクトリ、SQLite スキーマ、ひな形ファイルを初期化します |
waitbus install-systemd | Linux:systemd-user ユニットをコピーして有効化します |
waitbus install-launchd | macOS:LaunchAgent plist をコピーして登録します |
waitbus install-credentials | HMAC シークレットを 0600 のシークレットファイルに保存します(--file または stdin から読み込みます) |
waitbus doctor | インストールを検証します(パス、バイナリ、認証情報ストア、ユニット、/metrics) |
waitbus status | 運用ダッシュボード:DB の行数、デーモンの稼働状況 |
waitbus verify-plugin | .claude-plugin/plugin.json を検証します |
waitbus listener serve | HTTP webhook レシーバー(loopback :9000) |
waitbus broadcast serve | AF_UNIX ブロードキャストハブのデーモン |
waitbus etag-poll run | GitHub API ETag ポーリングワーカー |
waitbus mcp serve | ブロードキャストイベントを通知として再送する MCP サーバー(stdio) |
waitbus read-events watch | ブロードキャストバスを購読し、イベントをリアルタイムでストリーミングします |
waitbus read-events list | ローカルキャッシュから最近のイベントを表示します |
waitbus pr-monitor tick | ジョブイベントを PR ごとの状態に集約します |
waitbus watchdog-check run | 取り込み停止を検出します |
また、プラットフォームに応じて、Linux では ~/.config/systemd/user/ に 8 つの systemd-user ユニットがあります。
waitbus-listener.service waitbus-broadcast.socket
waitbus-broadcast.service waitbus-etag-poll.service
waitbus-etag-poll.timer waitbus-watchdog.service
waitbus-watchdog.timer [email protected]
…または、macOS では ~/Library/LaunchAgents/ に 4 つの LaunchAgent plist があります。
dev.waitbus.listener.plist dev.waitbus.broadcast.plist
dev.waitbus.etag-poll.plist dev.waitbus.watchdog.plist
macOS の plist には __BIN_DIR__/__LOG_DIR__/__RUNTIME_DIR__ のプレースホルダーが含まれており、waitbus install-launchd が書き込み前にオペレーターの実際のパスに置き換えます。エージェントは launchctl bootstrap gui/$UID <plist> で読み込まれます(これは非推奨の launchctl load -w に代わる最新の方法です)。
Python ライブラリとして
from waitbus import subscribe, wait_for, EventFrame
# Block until one matching event arrives (returns the frame, or None on timeout).
frame: EventFrame | None = wait_for('fields.event_type="pytest_session"',
source="pytest", timeout=600)
if frame is not None:
print(frame.event_type, frame.fields)
# Or stream every matching event as it lands.
for frame in subscribe(source="docker"):
print(frame.event_type, frame.fields)
エージェントは同じバス上で相互にメッセージを送ることもできます。一方がリクエストを送信して対応する返信を待ち、もう一方が受信ボックスから応答します。
from waitbus import request, respond, wait_for
# responder (agent_b), in its own process
msg = wait_for(to="agent_b", source="agent", timeout=5.0)
if msg is not None:
respond(msg, '{"answer": 42}') # sender defaults to msg's recipient
# requester (agent_a)
reply = request("agent_b", '{"ask": "meaning"}', sender="agent_a", timeout=5.0)
# reply is the answer EventFrame, or None on timeout.
リクエスト/返信の仕様、受信ボックスストリーム、同一 UID の信頼モデルについては、docs/AGENT_MESSAGING.md を参照してください。
安定した公開 API は emit、subscribe、asubscribe、wait_for、request、respond、EventFrame と、プラグインフックの register_source、register_condition、register_evaluator です(完全なシグネチャは docs/CONSUMER_API.md を参照してください)。イベントを生成するには、waitbus emit CLI が最も簡単です。emit() を使う Python 形式については examples/emitters/ を参照してください。先頭にアンダースコアが付くもの(waitbus._db、waitbus._paths など)はすべて非公開の内部実装であり、リリース間で変更される場合があります。
実行時依存関係(上記の軽量スタックと同じ必須依存関係一式):typer(統合 CLI)、msgspec(ワイヤーフレーミング)、platformdirs(状態およびランタイムパスの解決)、pydantic-settings(設定ローダー)、prometheus_client(メトリクス)、stamina(再試行ポリシー)、および mcp SDK(MCP サーバー)。コンシューマー向けの 2 つの追加機能(waitbus[analyze]、waitbus[fs])は duckdb/watchdog を遅延読み込みし、オプションパッケージはこれらのみです。その他の内部モジュールはすべて純粋な標準ライブラリです。インポート時にネットワーク通信はなく、C 拡張も使用しないため、Python 3.11 以降のあらゆる環境で安全にインポートできます。パッケージのルートロガーには NullHandler が設定されているため、ライブラリの利用者にログレコードが漏れることはありません。
MCP サーバーとして使用する場合(PyPI + uvx)
waitbus mcp serve は、仕様(https://modelcontextprotocol.io/specification)に準拠した JSON-RPC 2.0 over stdio の MCP サーバーです。クライアントで利用できる機能は、そのクライアントがどの MCP 機能を実装しているかによって異なります。実際の機能の違いは次のとおりです。
- プル:Tools に対応するすべての MCP クライアントで利用できます。 waitbus のツールを呼び出してステータスを確認したり、イベントをブロック待ちしたりできます。
tail_eventsは上限付きのロングポーリングなので、待機にもポーリングループは必要ありません。幅広いクライアントで利用できる方法です。 - プッシュ:リソースのサブスクリプションに対応するクライアントで利用できます。 waitbus は、
waitbus://repo/...をサブスクライブしているクライアントに、仕様標準のnotifications/resources/updatedを送信します。そのプッシュ通知をクライアントが(ツールの呼び出しだけでなく)表示するかどうかはクライアントによります。現在、多くのコーディングエージェント用 MCP クライアントはプル専用であり、公開されているクライアントの対応状況一覧では Tools / Resources / Prompts が記載されていますが、通知を表示するかどうかの項目はありません。 - インライン表示:Claude Code で利用できます。 waitbus は Anthropic 独自の
notifications/claude/channelも送信し、Claude Code はこれをインライン表示します。その他のクライアントは、JSON-RPC 2.0 に従って未知のメソッドを問題なく無視します。
動作確認済み: 実行可能なテストで、単に「仕様に準拠している」だけでなく、一連の処理をエンドツーエンドで検証しています。Claude Code(MCP の送信経路、tests/test_mcp_e2e.py)、公開 Python SDK(waitbus.wait_for / subscribe)経由の Pydantic AI および LangGraph エージェント(tests/test_agent_integration_*.py)、さらに各言語のスニペットと bash の waitbus wait ラッパーが対象です。その他の stdio-MCP クライアントも上記のプル方式を利用できますが、これは設定方法であり、エンドツーエンドでの動作を保証するものではありません。
コマンドは常に uvx --from waitbus waitbus mcp serve です。クライアントによって異なるのは、MCP 設定の保存場所のみです。保存場所や形式はクライアントのバージョンによって変わるため、以下の表は出発点として参照し、各クライアントの最新の MCP ドキュメントを確認してください。
{
"mcpServers": {
"waitbus": {
"command": "uvx",
"args": ["--from", "waitbus", "waitbus", "mcp", "serve"]
}
}
}
| クライアント | MCP 設定の場所(クライアントの最新ドキュメントで確認してください) |
|---|---|
| Claude Code | ~/.claude/.mcp.json(またはプロジェクトごとの ./.mcp.json) |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)または %APPDATA%\Claude\claude_desktop_config.json(Windows) |
| Cursor | ~/.cursor/mcp.json(またはプロジェクトごとの .cursor/mcp.json) |
| Cline (VS Code) | ~/.config/Cline/cline_mcp_settings.json(Linux)、またはワークスペースごとの .vscode/cline_mcp_settings.json |
| Codex CLI (OpenAI) | ~/.codex/config.toml([mcp_servers.waitbus] テーブル内。Codex は JSON ではなく TOML を使用します) |
| Gemini CLI (Google) | ~/.gemini/settings.json(mcpServers キー内) |
| Continue | ~/.continue/config.json(mcpServers キー内) |
Aider は意図的に含めていません。2026-05 時点で、Aider には ネイティブ MCP クライアントがありません(aider-AI/aider FR #4506 で上流の対応状況を追跡中です。唯一の MCP 経路は、別アプリの AiderDesk です)。Aider 系のエージェントや MCP 非対応エージェントから waitbus を利用するには、Python SDK(
waitbus.wait_for)またはwaitbus waitCLI を使ってください。
uv が PATH 上に必要です(curl -LsSf https://astral.sh/uv/install.sh | sh)。
プラットフォームのサポートを参照してください。
Claude Code プラグインとして使用する場合
マーケットプレイスまたは MCP レジストリへの登録が公開されるまでは、このリポジトリのローカルチェックアウトからプラグインを読み込みます。.claude-plugin/plugin.json のマニフェストはリポジトリルートの .mcp.json を参照するため、--plugin-dir にはサブディレクトリではなくチェックアウトのルートを指定する必要があります。
git clone https://github.com/astrogilda/waitbus
claude --plugin-dir ./waitbus --dangerously-load-development-channels
公開済みマーケットプレイス登録項目ではないローカルディレクトリからプラグインを読み込むには、--dangerously-load-development-channels が必要です(CONTRIBUTING.md に記載のものと同じ起動方法です)。マーケットプレイスの登録項目が MCP Registry に公開されたら(現在の状況は CHANGELOG.md を参照)、そちらからインストールしてください。どちらの方法でも、プラグインを有効にすると、すべての Claude Code セッションで /waitbus スラッシュコマンドと waitbus スキルを利用できます。
使用方法
イベントの読み取り
# Live tail — one line per event; monitoring-friendly cadence
waitbus read-events watch
# Query the last hour in JSON (pass extra flags after the sub-command)
waitbus read-events list --since 1h --json
# Roll job events into per-PR state (watch PRs 7 and 9)
waitbus pr-monitor tick --pr 7 --pr 9
主な機能
-
workflow_jobの失敗を1秒未満で検出します。 GitHub が Webhook を配信してから1秒未満(CI の失敗発生時点からではなく、Webhook 受信時点からの実時間)で、マトリックスの各セルの失敗を検出します。親のworkflow_run.completedが届くのを待つ必要はありません。他のマトリックスセルがまだ実行中でも、個々のジョブの失敗を即座に通知します。 -
冪等性を備えた SQLite イベントストアです。
event_id(取り込み時に割り当てる ULID)に対してINSERT OR IGNOREを実行します。Webhook の再配信や ETag ポーリングによる重複は自動的に破棄され、重複排除キューなしでデータベースの一貫性を維持します。 -
長さプレフィックス方式のフレーミングを備えた AF_UNIX
SOCK_STREAMブロードキャストバスです。 各ワイヤーフレームは、4バイトのビッグエンディアン長とそれに続く JSON ペイロードで構成されます。SOCK_SEQPACKETが利用できない Linux と macOS の両方で動作します。ソケットはノンブロッキングで、サブスクライバーごとに遅延カウンターを持ちます。LAG_LIMIT回連続して送信に失敗した遅いサブスクライバーは切断され、EOF をトリガーとするカーソルリセットによって再接続します。 -
HMAC-SHA256 による Webhook 署名検証です。
waitbus install-credentials github-webhook-secretを使ってシークレットを一度だけ設定すると、ユーザー状態ディレクトリの0600のsecrets.jsonに保存され、ユニットの起動時に読み込まれます。署名がない場合や無効な場合は、ペイロードを読み取る前に 401 で拒否します。 -
SIGTERM 時のドレインを保証します。 ブロードキャストデーモンは SIGTERM を受けると、新しいサブスクライバーの受け入れを停止し、接続中のサブスクライバーに送信中のすべてのフレームを送り切ってから、EOF で接続を閉じ、ソケットファイルを削除して終了コード 0 で終了します。
systemctl restart waitbus-broadcastでイベントが失われることはありません。 -
ETag ポーリングのフォールバックです。 45秒間隔のタイマーで
watched_repos.txtに記載されたリポジトリをポーリングし、If-None-Matchを使って GitHub API のレート制限を無駄に消費しないようにします。Webhook 駆動のリポジトリと併用できます。 -
Prometheus メトリクスエンドポイントです。
http://127.0.0.1:9000/metricsでは、取り込みイベント数と取り込みエラー数のカウンターを Prometheus テキスト形式で公開します。ウォッチドッグタイマーが取り込みの停止を検出し、記録します。
設定
設定ファイル(任意): ~/.config/waitbus/config.toml
[prometheus]
owner = "my-org"
repo = "my-repo"
環境変数による上書き:
| 変数 | 用途 |
|---|---|
WAITBUS_PROM_OWNER | Prometheus アラートラベルの owner を上書きします |
WAITBUS_PROM_REPO | Prometheus アラートラベルの repo を上書きします |
WAITBUS_STATE_DIR | 状態ディレクトリ(SQLite DB、scaffolds、cursors)を上書きします。デフォルトは platformdirs を使って解決されます。 |
WAITBUS_RUNTIME_DIR | 実行時ディレクトリ(broadcast および doorbell AF_UNIX ソケット)を上書きします。デフォルトは platformdirs を使って解決されます。 |
状態ディレクトリの解決
パスの解決は waitbus._paths にあり、設定チェーンのほかの部分と同じく、最初に見つかった値が優先されます。
WAITBUS_STATE_DIR/WAITBUS_RUNTIME_DIR環境変数(運用者が制御します)。- プラットフォームごとのデフォルト値として
platformdirs.PlatformDirs("waitbus")を使用します。- Linux: 状態データは
~/.local/state/waitbus/に保存されます(XDG_STATE_HOMEに従います)。ソケットは/run/user/$UID/waitbus/に保存されます(XDG_RUNTIME_DIRに従います)。 - macOS: 状態データは
~/Library/Application Support/waitbus/に保存されます。ソケットにはtempfile.gettempdir()から導出した安定したパスを使用します(platformdirs の macOSuser_runtime_dirは Apple によって削除される可能性のあるキャッシュであり、AF_UNIX ソケットには適していません)。
- Linux: 状態データは
同梱の systemd ユニットは StateDirectory=waitbus と
RuntimeDirectory=waitbus を使用するため、Linux では systemd がデーモンの起動前に、所有者を設定した 0700 のディレクトリを作成します。そのため、運用者が mkdir を実行する必要はありません。
シークレット(waitbus install-credentials <name> で登録):
| シークレット名 | 必須 | 用途 |
|---|---|---|
github-webhook-secret | Webhook リスナーを使用する場合のみ | GitHub Webhook 署名検証用の HMAC シークレット |
alertmanager-hmac | いいえ | Alertmanager / watchdog Webhook 検証用の HMAC シークレット |
ブロードキャストバス自体にシークレットは必要ありません。カーネルによる同一 UID のピア資格情報チェックで保護された AF_UNIX ソケットであるため、サブスクライバートークンはありません。シークレットは、ユーザーの状態ディレクトリ内の単一の 0600 モードの secrets.json(<state_dir>/secrets.json)に保存されます。install-credentials は --file または stdin から値を読み取り、原子的な置換によって追加します。値がコマンドラインに露出することはありません。保存時のファイル保護は、ホストのフルディスク暗号化(FileVault / LUKS)に委ねられます。SECURITY.md を参照してください。waitbus doctor は値を表示せずに各必須キーの有無を報告し、有効なユニットに必要なキーが不足している場合は 1 を返します。
セキュリティ
HMAC の脅威モデル、プラットフォームの前提、脆弱性の報告手順については、SECURITY.md を参照してください。
同一 UID の信頼モデル。 ブロードキャストバスにはプロセス間の機密性がありません。ユーザーとして実行されているプロセスは、バス上のすべてのイベントを読み取ることができ、任意の送信者名でイベントを送信できます。waitbus は単一ユーザーのワークステーション向けツールであり、実行中のプロセス間のセキュリティ境界ではありません。ピア認証にはカーネルが検証した UID(SO_PEERCRED)を使用するため、別のユーザーは接続できませんが、同じユーザー内の分離は設計上対象外です。
リリース成果物を検証するには(gh CLI、ネットワークアクセス、そしてアテステーション付きの公開済み GitHub リリースが必要です。そのため、これはクローン内でオフライン実行する検証手順ではありません):
gh attestation verify $(python -c "import waitbus; print(waitbus.__file__)") \
--repo astrogilda/waitbus
SLSA、PEP 740、SBOM のチェックを含む、完全な来歴検証手順については、SECURITY.md を参照してください。
サポート
バグ報告、機能リクエスト、質問については、SUPPORT.md を参照してください。セキュリティ、不正行為・行動規範、および一般的な問い合わせ窓口を記載し、単独メンテナーによるベストエフォートでの対応であることを説明しています。セキュリティ脆弱性は、公開 issue ではなく、SECURITY.md に記載された非公開の手順で報告してください。
運用
# Start the core daemons
systemctl --user start waitbus-listener.service
systemctl --user start waitbus-broadcast.socket
# Start the background timers
systemctl --user start waitbus-etag-poll.timer
systemctl --user start waitbus-watchdog.timer
# Health check — exits 1 on any missing required config or stopped unit.
# A non-zero exit right after install (before you start the daemons) is
# expected, not a failure: it just reports that the units are not up yet.
waitbus doctor
# Watch webhook deliveries arrive in real time
waitbus read-events watch
ログイン時にユニットが自動起動するように設定します。
systemctl --user enable waitbus-broadcast.socket \
waitbus-etag-poll.timer waitbus-watchdog.timer
# The webhook listener is opt-in; `install-credentials github-webhook-secret` enables it.
Webhook の HMAC シークレットをローテーションします。
# Pipe the new value in; install-credentials atomically replaces the staged secret.
openssl rand -hex 32 | waitbus install-credentials github-webhook-secret
# Then update the GitHub repository webhook secret and Alertmanager config.
systemctl --user restart waitbus-listener.service
ヘッドレスサーバー(SSH のみ/グラフィカルセッションなし)
グラフィカルなログインセッションのないヘッドレスマシンでは、インタラクティブなセッションが開いていない間も systemd-user インスタンスを継続して動作させるため、次の 2 つの追加設定が必要です。
-
ログアウト後もユーザーマネージャーを稼働させます。 次のコマンドを一度実行します。
loginctl enable-linger <username>これを設定しないと、最後のインタラクティブセッションが終了したときに、systemd ユーザーマネージャーとそのすべてのユニットが停止します。
-
キーリングのロック解除は不要です。 シークレットはユーザーの状態ディレクトリにある
0600のsecrets.jsonに保存され、通常のファイル読み込みで読み取られます。キーリングも、D-Bus セッションの要件も、pam_gnome_keyring.soへの依存もないため、完全なヘッドレスマシンでもデーモンスタックを変更せずに実行できます。
linger 設定が機能していることを確認します。 新しい SSH セッションを開き(先にユニットを手動で起動しないでください)、次を実行します。
systemctl --user is-active waitbus-listener
結果は active になるはずです。手動で systemctl --user start を実行しないとユニットがアクティブにならない場合、linger 設定は有効になっていません。
linger が有効なホストでの XDG_RUNTIME_DIR。 linger が有効な場合、systemd は XDG_RUNTIME_DIR=/run/user/$(id -u) を自動的に設定し、その下にブロードキャストソケットのパスを作成します。ユーザーが作業する必要はなく、どのセッションでも最初の systemctl --user 呼び出しからそのパスを利用できます。
リポジトリの接続
ローカルソースでは、リポジトリごとの接続設定は不要です。 pytest、Docker、ファイルシステムのイベントはマシン上で生成されるため、Webhook フォワーダーを設定する必要はありません。デーモンが起動し(上記のクイックスタート)、該当するイベント発生元(pytest のオプトインエミッター、または waitbus source docker/waitbus source fs のウォッチャー)がイベントを生成していれば、waitbus wait --source pytest|docker|fs にリポジトリごとの設定は一切必要ありません。以下の 2 つのサブセクションは、Webhook 経由で届く GitHub CI 専用です。そのため、フォワーダーが必要になります。
イベント駆動方式(自分が所有するリポジトリに推奨):
gh webhook forward \
--repo=<owner>/<repo> \
--events=workflow_run,workflow_job \
--url=http://127.0.0.1:9000/webhook \
--secret="<the same plaintext value you piped to install-credentials>"
gh webhook forward は GitHub 側に一時的な Webhook を作成し、ローカルのリスナーに配信をトンネルします。シークレットは、waitbus install-credentials github-webhook-secret で登録した平文と一致している必要があります。
systemd が管理するフォワーダー(同梱の [email protected] テンプレート)では、ユーザーが作業する必要はありません。ユニットは起動時に $STATE_DIRECTORY 経由で secrets.json から github-webhook-secret キーを読み取り、gh webhook forward --secret に渡します。
ETag ポーリング(読み取りはできるものの、Webhook を受信できないリポジトリ向け):
解決済みの状態ディレクトリにある watched_repos.txt に、owner/repo の行を追加します(パスは waitbus doctor に表示されます。Linux で WAITBUS_STATE_DIR による上書きがない場合は、~/.local/state/waitbus/watched_repos.txt です)。45 秒間隔のタイマーが自動的にリポジトリを検出します。
SSH のみを使用するマシンについては、loginctl enable-linger の設定要件を説明したヘッドレスサーバーを参照してください。
プラットフォームのサポート
| コンポーネント | Linux + systemd | macOS + launchd | 備考 |
|---|---|---|---|
| Python リスナー | 対応 | 対応 | ループバックにバインド、標準ライブラリのみ |
| SQLite イベントストア | 対応 | 対応 | 単一ファイルの DB、サーバー不要 |
| ブロードキャストデーモン | 対応 | 対応 | AF_UNIX SOCK_STREAM + 長さプレフィックス形式のフレーミング |
| ドアベルプリミティブ | os.eventfd | SOCK_STREAM ping | バインド箇所でインラインにディスパッチ |
| ピア認証情報による UID チェック | SO_PEERCRED | ctypes 経由の getpeereid() | LOCAL_PEERPID は意図的に使用しません(詳細は SECURITY.md を参照) |
| インストールエントリ | waitbus install-systemd | waitbus install-launchd | どちらも異なるプラットフォームでの実行を拒否します |
| プロセススーパーバイザー | systemd-user ユニット | launchd LaunchAgents | systemd ユニット 8 個、launchd plist 4 個。すべて waitbus 経由で制御します |
| MCP サーバー | 対応 | 対応 | stdio MCP。仕様に準拠するあらゆるクライアントで動作します |
| Claude Code プラグイン | 対応 | 対応 | プラグインマニフェストは .claude-plugin/ にあります |
どちらのプラットフォームでも、デーモンスタック全体が動作します。Linux ではソケットアクティベーションを使う systemd-user ユニットを使用し、macOS では手動でソケットをバインドする launchd LaunchAgents を使用します。ピア認証情報による UID チェック、ドアベルプリミティブ、インストールエントリポイントは、それぞれリーフ呼び出し箇所でインラインにディスパッチされます。この 3 つのリーフ箇所だけがプラットフォームごとに異なるコードであるため、IPCBackend のような抽象化レイヤーはありません。
詳細は SECURITY.md を参照してください。
ネイティブ Windows はサポートされていません。 waitbus の信頼モデルは、AF_UNIX ソケットと SO_PEERCRED による同一 UID のピアチェックを前提としており、Win32 にはこれに相当する仕組みがありません。Windows ユーザーは WSL2 上で waitbus を実行します。WSL2 は実際の Linux カーネルであるため、WSL2 ディストリビューション内での pip install waitbus(または uv tool install waitbus)は、ネイティブ Linux の場合とまったく同じように動作します。プラットフォームを選定した理由については、docs/ARCHITECTURE.md を参照してください。
デフォルトの外部通信はゼロ、テレメトリもありません。 ブロードキャストデーモン、すべてのサブスクライバー(waitbus wait、waitbus read-events、waitbus mcp serve)、および emit() の経路から、外部へのネットワーク呼び出しは行われません。外部への情報送信はありません。ネットワークに接続するのは、オプションの受信 GitHub webhook リスナー(ループバック 127.0.0.1:9000、HMAC 検証済み)と、認証情報の保存に使用するローカル OS キーリングへのアクセスのみです。外部への通信は、ETag ポーリングのフォールバックを明示的に有効にした場合に限り発生します(リストに記載したリポジトリについて GitHub API を呼び出します)。ネットワークの全体像については SECURITY.md を参照してください。
コントリビューション
サーフェスごとの開発ガイド、プラグインのローカル読み込み、バージョンの同期、リリース手順については、.github/CONTRIBUTING.md を参照してください。
ライセンス
waitbus は MIT License のもとで公開されています。全文は LICENSE を参照してください。
その他
- CHANGELOG.md:バージョン履歴と移行に関する注意事項
- SECURITY.md:HMAC の脅威モデル、プラットフォームの前提、報告手順
- .github/CONTRIBUTING.md:サーフェスごとの開発ガイド、プラグインのローカル読み込み
- docs/emitters/recipes.md:シェルおよび Docker のイベント発行レシピと、外部プロデューサー向け CloudEvents エンベロープのマッピング
- docs/emitters/claude-code-hook.md:Claude Code のセッションライフサイクルフックでバスイベントを発行する方法
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。
