EZO Watcher 是一個警報牆和呼叫器,直接安裝在使用者的專案中:設定即程式碼,放在 .watcher/ 目錄,一個本地 Node 程序,無需帳號。你的工作是完成整個安裝並驗證——而不是提供一串建議清單。
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 安裝 latest-main):請執行 watcher skills install。
循環流程
如果 .watcher/ 已存在,請先執行 watcher doctor --json 和 watcher scan --json,然後只根據排名結果新增缺少的部分;不要對已正常運作的安裝重新執行 init。
- Init 初始化。 在專案根目錄執行
watcher init。這是冪等操作,不會有任何提示;會寫入.watcher/config.json、.watcher/.env(權限 0600)、.watcher/data/,將後兩者加入 gitignore,從 7717 開始選擇一個可用埠號,並印出第一次 doctor 摘要。 - Scan 掃描。
watcher scan --json→{signals, suggestedCommands}。在一個小型手動標註的樣本上,其原型找到了 19 個 HTTP/TLS 點中的 15 個,但只找到了 10 個靜默點中的 2 個(請參閱watcher skills discover):請將這些命令視為候選項目,然後按照下方的「靜默優先」方法,透過閱讀程式碼來處理。 - 根據排名選擇(下一節)。每個實際監控點一個來源;切勿為了看起來是綠燈而發明來源。
- Add 新增。 對於每個選定的來源:
watcher add <kind> --id <id> … --found-at <file:line> --read "<what it proves>"。--found-at/--read是來源證明,watcher doctor在缺少它們時會發出警告。使用--dry-run可以預覽。然後新增一個頻道:watcher add channel <type> --id <id> …(請參閱watcher skills channels)。如果沒有任何憑證可用——例如無頭伺服器、沒有供應商帳號、使用者尚未選擇呼叫器——請新增無憑證的備用方案:watcher add channel file --id local:它會將每次通知寫成一行 JSON,存放在.watcher/data/下,這是一個真實、可測試的頻道,不是空殼。watcher add … --replace會重寫現有的 id;watcher rm <id>則會移除一個。 - Doctor 循環。
watcher doctor --json;如果ok:false,則透過其next修復第一個fail,然後重新執行。如果channel.missing發出警告且使用者希望電話響鈴,則立即執行步驟 8 的頻道設定,然後再回來。退出碼 0 表示通過,1 表示失敗,64 表示使用方式錯誤。 - Run 執行。
watcher run --detach(或watcher service install以便在重開機後仍能存活)。然後執行watcher doctor --live --json來讀取正在運行的伺服器。 - Prove 驗證。 執行
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)。不要將未經驗證的安裝視為完成。 - Page 呼叫。 新增一個頻道,然後執行
watcher test-alert;確認警報已送達重要的設備。缺少憑證是一個被命名的跳過項目,而不是通過。 - Host 託管(可選)。 階梯順序為:本地 → 服務 → Docker/VPS → Cloudflare Tunnel(預設選項,用於「用我的 Cloudflare 金鑰託管它」)→ Containers beta。請參閱
watcher skills hosting、watcher skills cloudflare。 - 為下次安裝此技能。
watcher skills install --target all --dir .會將其寫入專案中。在 Claude Code 中,之後請執行/reload-skills——在中途建立的頂層 skills 目錄,如果不重新載入就不會被偵測到。
後續日常操作——查看警報牆、確認、評論、靜默、擱置、重新檢查——請參閱 watcher skills operate。
當發生故障時
事件是一個帶有證據的主張,而不是一個通知。完整的循環請參閱 watcher skills fix:
- 使用
watcher status --brief獲取一行摘要,或使用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、composehealthcheck、KubernetesreadinessProbe、fly/railway/render 的健康檢查路徑。從外部以相同的路徑和埠號鏡像它。 - 沒有伺服器 → 每個排程工作一個心跳。 靜默即是訊號。
- 沒有伺服器且沒有排程工作 →
watcher add host --id host(負載、記憶體、可用空間,可選 pid 檔案;無需安裝任何東西)並驗證它。只有沒有伺服器、沒有排程工作、也沒有主機可監控 → 執行watcher doctor --no-runtime-surface --json,報告NO_RUNTIME_SURFACE,停止。已設定的來源永遠優先於--no-runtime-surface。切勿發明來源。 - 然後是已存在的系統——Sentry、Grafana、Netdata、入站發送器——需要憑證。缺少憑證是一個帶有程式碼和
next的命名跳過項目,而不是靜默通過。
靜默優先(掃描會錯過這些)
閱讀程式碼以找出以下六個類別;每個類別都變成一個 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。每個任務一個心跳(--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://…"、host:port 字面值、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" # 帶任務的退出碼
如果不是單一任務的收集器,則改為推送整個清單:POST /ingest/<source>,帶有 {"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/。 - 一個運作正常的頻道勝過五個設定好的頻道。 使用
watcher test-alert驗證它。完全沒有憑證?使用watcher add channel file --id local並驗證它:檔案是一個真實的頻道,缺少憑證是一個被命名的跳過項目,而不是通過。 - 報告你驗證了什麼——新增的來源、命令輸出,以及每個被命名的跳過項目。如果代理程式無法完成某個步驟(缺少憑證、沒有區域),請用一行話說明是哪個步驟以及原因。
更多細節,當某個步驟需要時:watcher skills discover(完整訊號目錄和靜默檢查清單)、watcher skills sources(每種來源的類型、標誌和範例)、watcher skills channels、watcher skills hosting、watcher skills cloudflare、watcher skills netdata、watcher skills operate(MCP 工具和事件分類)。