EZO Watcherは、ユーザーのプロジェクトにインストールされるアラートウォール兼ページャーです。設定はコードとして.watcher/に保存され、ローカルのNodeプロセス1つで動作し、アカウントは不要です。あなたの仕事は、インストール全体を実際に動作する形で完了させることです — 単なる提案リストではありません。
CLIが唯一の情報源です。以下の各トピックはCLIから出力されます:watcher skills <topic>(トピック:install、discover、sources、channels、hosting、cloudflare、netdata、operate、fix、telemetry)、またはこのファイルと同じディレクトリにあるreferences/<topic>.mdを参照してください。すべてのコマンドはwatcher <verb>の形式で実行し、単独の単語(doctorはホストエージェント自身の/doctorと衝突します)では実行しないでください。
CLIのインストール
CI=1 npm_config_yes=true npm i -g ezo-watcher
watcher --version
グローバルインストールしない場合:npx -y ezo-watcher <verb> で同じCLIを実行できます。チェックアウトからの場合:npm ci && npm run build && npm link。
Node 24以上が必要です。GitHubからの最新メインビルドを含む詳細は:watcher skills install。
ループ
.watcher/が既に存在する場合、まずwatcher doctor --jsonとwatcher scan --jsonを実行し、ランキングで不足しているものだけを追加します。動作しているインストールを再初期化しないでください。
- 初期化。 プロジェクトルートで
watcher initを実行します。冪等で、プロンプトは表示されません。.watcher/config.json、.watcher/.env(0600)、.watcher/data/を作成し、最後の2つをgitignoreに追加し、7717から空いているポートを選び、最初のdoctorサマリーを表示します。 - スキャン。
watcher scan --json→{signals, suggestedCommands}。小さな手動ラベル付きサンプルでは、プロトタイプが19個のHTTP/TLSポイントのうち15個を発見しましたが、10個のサイレンスポイントのうち2個しか発見しませんでした(watcher skills discover):そのコマンドを候補として扱い、コードを読みながら以下のサイレンス優先パスを実行します。 - ランキングに従って選択(次のセクション)。実際のポイントにつき1つのソース。グリーンに見せるためにソースをでっち上げないこと。
- 追加。 選択した各ソースに対して:
watcher add <kind> --id <id> … --found-at <file:line> --read "<何を証明するか>"。--found-at/--readは出典情報で、これらがないとwatcher doctorが警告を出します。--dry-runでプレビューできます。次に1つのチャネル:watcher add channel <type> --id <id> …(watcher skills channelsを参照)。認証情報がない場合 — ヘッドレスボックス、ベンダーアカウントなし、ページャーを選択していないユーザー — 認証情報不要のフォールバックを追加します。watcher add channel file --id local:これは通知ごとに1行のJSONを.watcher/data/に書き込み、実際にテスト可能なチャネルであり、スタブではありません。watcher add … --replaceは既存のIDを書き換え、watcher rm <id>は削除します。 - doctorループ。
watcher doctor --json。ok:falseの場合、最初のfailをそのnextで修正し、再実行します。channel.missingの警告が出てユーザーが電話を鳴らしたい場合は、今すぐステップ8のチャネルを追加して戻ってきます。終了コード0は成功、1は失敗、64は使用方法の誤りです。 - 実行。
watcher run --detach(または再起動後も持続するwatcher service install)。その後watcher doctor --live --jsonで実行中のサーバーを読み取ります。 - 証明。
watcher doctor --live --prove --jsonを{"ok": true, "live": true}が返るまで実行します。--proveは各ソースの読み取り値を閾値を超えて移動させ、ルールが実際に反転しない限り失敗します(source.assertion-not-red;空疎なhttp-probeアサーションはsource.assertion-vacuousで失敗します):http-probeの応答は変更され、ハートビートは見逃し実行とその猶予期間後に評価され、ホスト読み取りはディスク/メモリ/負荷の閾値を超えて移動し、tcp接続は失敗し、有効期限はpageDays内に収まります。送信元が報告するアラートの種類(grafana、vmalert、sentry、netdata、feed、webhook)は名前付きのsource.prove-unsupportedスキップとなり、決して失敗にはなりません。プロジェクトにサーバーもスケジュールジョブもない場合、watcher add host --id host— マシン自体を、何もインストールせずローカルで読み取る — を追加して証明します。サーバーがなく、スケジュールジョブもなく、監視するホストもないプロジェクトのみ、watcher doctor --no-runtime-surface --jsonを実行 →{"ok": true, "live": false, "reason": "no-runtime-surface"}と平易に報告します。設定されたソースは常に--no-runtime-surfaceより優先されます(その場合、レポートはdoctor.no-runtime-surface-ignored警告を出します)。証明されていないインストールを完了と呼んではいけません。 - ページング。 1つのチャネルを追加し、
watcher test-alertを実行します。重要なデバイスに届いたことを確認します。認証情報の欠落は名前付きスキップとなり、決して成功にはなりません。 - ホスティング(オプション)。 段階はローカル → サービス → Docker/VPS → Cloudflare Tunnel(「Cloudflareキーでホストする」場合のデフォルト) → Containersベータです。
watcher skills hosting、watcher skills cloudflare。 - 次回のためにスキルをインストール。
watcher skills install --target all --dir .でプロジェクトに書き込みます。Claude Codeではその後**/reload-skills**を実行してください — セッション中に作成されたトップレベルのスキルディレクトリは、そうしないと認識されません。
2日目 — ウォールの読み取り、確認、コメント、サイレンス、保留、再チェック — はwatcher skills operateです。
何かが壊れたとき
インシデントは証拠を伴う主張であり、単なる通知ではありません。完全なループはwatcher skills fixです:
watcher status --briefで1行表示、またはwatcher incidents --output jsonでキーを表示(MCP:watch_state、次にlist_incidents)。get_fix_context { key }(CLI:watcher incident <key> --fix-context):インシデント、ソースとターゲットの設定(認証情報は環境変数名として)、ルールのアサートと失敗したもの、エンドポイントが見つかった場所、最後の正常と最後の異常の観測値、チェックを再実行する正確なコマンド、そしてnext。- そのコマンドから再現します。閾値は原因ではありません。
- 原因を修正し、修正が反映されるように再デプロイまたは再起動します。
verify_fix { key, by }(CLI:watcher recheck <key> --wait):再チェックし、ソースの新しい応答を待ち、すべてのアラートが解決されたときに確認を記録します — または、どのアサーションがまだ失敗しているかを示し、修正を修復できるようにします。再チェックがグリーンになる前にインシデントを解決済みとマークしないでください。parkは修正がマージされたがまだライブではない場合、confirm_resolutionはソースが既に閉じた場合に使用します。- 途中で見つけたことを
commentします。黙って修正すると、次に来る人に何も残りません。
ランキング:何を監視するか、優先順位順
- 本番プロセスの最も深い readiness ルート。依存関係がダウンしたときに変化するフィールドをアサートします。ハードコードされた
{"ok": true}/{"status": "ok"}は決して使用しないでください — それは生存性であり、重要な障害ではレッドになり得ません。 - プラットフォームが既に宣言している readiness プローブ:
/readyz、/health/ready、composeのhealthcheck、KubernetesのreadinessProbe、fly/railway/renderのヘルスパス。同じパスとポートで外部からミラーリングします。 - サーバーがない → スケジュールジョブごとに1つのハートビート。 沈黙がシグナルです。
- サーバーがなく、スケジュールジョブもない →
watcher add host --id host(負荷、メモリ、空き容量、オプションでpidファイル。何もインストールしません)を追加して証明します。サーバーがなく、スケジュールジョブもなく、監視するホストもない場合のみ →watcher doctor --no-runtime-surface --json、NO_RUNTIME_SURFACEを報告して停止します。設定されたソースは常に--no-runtime-surfaceより優先されます。決してソースをでっち上げないでください。 - 次に、既存のシステム — Sentry、Grafana、Netdata、インバウンド送信者 — 認証情報にバインドされたもの。認証情報の欠落はコードと
nextを持つ名前付きスキップであり、黙って成功ではありません。
最初に沈黙(スキャンが見逃すもの)
以下の6つのクラスについてコードを読みます。それぞれがwatcher add heartbeatまたはwatcher add webhook --stale-afterになります:
- インストール時に生成されるスケジュール —
install.sh/setup.*内のheredocでplist、unit、crontabを書き込むもの、launchctl load、systemctl enable、crontabの書き込み。 - ランタイムに作成されるlaunchd/systemd/cron —
.plistテンプレート、OnCalendar=、StartInterval、KeepAlive、node-cron、schedule(、ジョブをラップするsetInterval、celery beat。ジョブごとに1つのハートビート(--every/--schedule+--grace)。NジョブはNソースを意味します。 - プルキューワーカー —
worker、queue、bullmq、sqs、claim、lease、dequeue。障害はキュー深度または進行の欠如であり、ポートではありません。成功パスでハートビートをpingするか、state: failingのエントリを持つchecks.listをプッシュします。 - プロダクト自身の設定における古さ —
staleAfterSec、presenceTtlSec、maxAge、ttl、refreshInterval、lastRunAt。同じウィンドウを適用します:watcher add webhook --id <sender> --token-env <ENV> --stale-after-sec <sec>。 - 状態ディレクトリの書き込み可能性 —
mkdir、state/、data/、sqlite、ロックファイル。成功した書き込みの後にのみpingします。単なるtest -wはソースではありません。 - コード定数として保持される依存関係エンドポイント —
process.env.X ?? "https://…"、ホスト:ポートリテラル、gRPC/ClickHouse/LLMベース。watcher add http-probe(HTTPS GET)またはwatcher add tcp-probe --host --port、--found-atは定数。
pingはジョブの成功パスに配置します — POST /ingest/heartbeat/<id>、失敗した実行には/fail、特定の終了コードには/<exit-code>。watcher add heartbeatは、名前付き変数にまだ値がない場合にトークンを.watcher/.env(0600)に作成するか、渡した--secret-valueを書き込み、正確な行を出力します(以下の$NIGHTLY_TOKENは--id nightlyに対して選ばれた名前です。渡した--token-envは代わりに出力される変数です):
set -a; . .watcher/.env
curl -fsS -m 10 "${WATCHER_URL:-http://127.0.0.1:7717}/ingest/heartbeat/<id>?token=$NIGHTLY_TOKEN" # 成功した実行の後
curl -fsS -m 10 "${WATCHER_URL:-http://127.0.0.1:7717}/ingest/heartbeat/<id>/fail?token=$NIGHTLY_TOKEN" # 失敗した実行の後
curl -fsS -m 10 "${WATCHER_URL:-http://127.0.0.1:7717}/ingest/heartbeat/<id>/<exit-code>?token=$NIGHTLY_TOKEN" # ジョブの終了コード付き
1つのジョブではないコレクターは、代わりに完全なリストをプッシュします:POST /ingest/<source> with {"checks":{"list":[{"id":"…","service":"…","state":"ok","lastRunAt":"…"}]}} — 完全な形状と状態はwatcher skills sourcesにあります。
ヘルスルートがリテラルのみを返す場合、より深いものを見つけるか、追加します:GET /readyz → 依存関係が応答する場合は200 {"db":{"ok":true}}、応答しない場合は503 {"db":{"ok":false}}。ユーザーのプロジェクトの編集は許可されています — あなたはファイルを書き込むエージェントです。そして、変化するフィールドをアサートし、決して{"ok":true}をアサートしないでください。
ルール
- Watcher自身の
/healthzにソースを向けないでください —source.self-probeが拒否します。 - ソースは反転できる何かをアサートしなければなりません。 単なる200は生存性のみです(
source.bare-200)。watcher doctor --live --proveがゲートであり、--found-atは警告です(source.untraced)。 - シークレットは設定内では環境変数名、値は
.watcher/.env内のみです。 スキャン中に.envの値を読み取らず、.watcher/.envや.watcher/data/をコミットしないでください。 - 1つの動作するチャネルは、5つの設定されたチャネルに勝ります。
watcher test-alertで証明してください。認証情報がまったくない場合?watcher add channel file --id localを追加してそれを証明します:そのファイルは実際のチャネルであり、認証情報の欠落は名前付きスキップであり、成功ではありません。 - 証明したことを報告してください — 追加されたソース、コマンド出力、そしてすべての名前付きスキップ。エージェントが段階を完了できない場合(認証情報なし、ゾーンなし)、それを1行で理由とともに述べてください。
詳細は、ステップが必要な場合:watcher skills discover(完全なシグナルカタログとサイレンスチェックリスト)、watcher skills sources(すべての種類、フラグ、例)、watcher skills channels、watcher skills hosting、watcher skills cloudflare、watcher skills netdata、watcher skills operate(MCPツールとインシデントトリアージ)。