Community程式設計與開發github.com

ezolabs/ezo-watcher

在專案中設置、新增、檢查或修復監控、警報與正常運行檢查,驅動 `watcher` CLI 從頭到尾完成初始化、掃描、來源與頻道設定、驗證與託管。

ezo-watcher 是什麼?

EZO Watcher 是一個直接安裝在**使用者專案**內的警報牆與呼叫器(pager):設定即程式碼,放在 `.watcher/` 目錄中;單一本地 Node 程序,無需註冊帳號。此技能會帶領使用者完成完整的安裝與驗證過程,而非僅提供建議清單。其 CLI 是唯一真相來源,支援 `watcher` 命令列工具,涵蓋初始化(`watcher init`)、掃描(`watcher scan`)、新增來源與頻道、以及透過 `watcher doctor --live --prove` 進行端到端驗證。此技能亦支援無伺服器或無排程工作的專案,可新增主機監控(`watcher add host`),並在無任何運行時表面(runtime surface)時提供明確的 `NO_RUNTIME_SURFACE` 報告。支援 Cursor、Codex 與 Claude Code 等平台,透過 CLI 與專案互動,確保每個監控點都能真實觸發警報,而不是空跑綠燈。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ezolabs/ezo-watcher/tree/HEAD/skills/ezo-watcher

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

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。

  1. Init 初始化。 在專案根目錄執行 watcher init。這是冪等操作,不會有任何提示;會寫入 .watcher/config.json、.watcher/.env(權限 0600)、.watcher/data/,將後兩者加入 gitignore,從 7717 開始選擇一個可用埠號,並印出第一次 doctor 摘要。
  2. Scan 掃描。 watcher scan --json → {signals, suggestedCommands}。在一個小型手動標註的樣本上,其原型找到了 19 個 HTTP/TLS 點中的 15 個,但只找到了 10 個靜默點中的 2 個(請參閱 watcher skills discover):請將這些命令視為候選項目,然後按照下方的「靜默優先」方法,透過閱讀程式碼來處理。
  3. 根據排名選擇(下一節)。每個實際監控點一個來源;切勿為了看起來是綠燈而發明來源。
  4. 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> 則會移除一個。
  5. Doctor 循環。 watcher doctor --json;如果 ok:false,則透過其 next 修復第一個 fail,然後重新執行。如果 channel.missing 發出警告且使用者希望電話響鈴,則立即執行步驟 8 的頻道設定,然後再回來。退出碼 0 表示通過,1 表示失敗,64 表示使用方式錯誤。
  6. Run 執行。 watcher run --detach(或 watcher service install 以便在重開機後仍能存活)。然後執行 watcher doctor --live --json 來讀取正在運行的伺服器。
  7. 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)。不要將未經驗證的安裝視為完成。
  8. Page 呼叫。 新增一個頻道,然後執行 watcher test-alert;確認警報已送達重要的設備。缺少憑證是一個被命名的跳過項目,而不是通過。
  9. Host 託管(可選)。 階梯順序為:本地 → 服務 → Docker/VPS → Cloudflare Tunnel(預設選項,用於「用我的 Cloudflare 金鑰託管它」)→ Containers beta。請參閱 watcher skills hosting、watcher skills cloudflare。
  10. 為下次安裝此技能。 watcher skills install --target all --dir . 會將其寫入專案中。在 Claude Code 中,之後請執行 /reload-skills——在中途建立的頂層 skills 目錄,如果不重新載入就不會被偵測到。

後續日常操作——查看警報牆、確認、評論、靜默、擱置、重新檢查——請參閱 watcher skills operate。

當發生故障時

事件是一個帶有證據的主張,而不是一個通知。完整的循環請參閱 watcher skills fix:

  1. 使用 watcher status --brief 獲取一行摘要,或使用 watcher incidents --output json 獲取鍵值(MCP:watch_state,然後 list_incidents)。
  2. get_fix_context { key }(CLI:watcher incident <key> --fix-context):取得事件、來源和目標設定(憑證顯示為環境變數名稱)、規則的斷言以及失敗的那個、端點被找到的位置、上次正常與最後一次異常的觀測值、重新執行檢查的確切命令,以及 next(下一步)。
  3. 根據該命令重現問題。閾值不是原因。
  4. 修復原因,重新部署或重新啟動,使修復生效。
  5. verify_fix { key, by }(CLI:watcher recheck <key> --wait):它會重新檢查,等待來源給出新的答案,並在每個警報都解決時記錄確認——或者指出哪個斷言仍然失敗,以便可以修復。在重新檢查變為綠燈之前,切勿將事件標記為已解決;park 適用於已合併但尚未上線的修復,confirm_resolution 則適用於來源已自行關閉的事件。
  6. comment 說明你在過程中發現的內容。沉默的修復會讓下一個人無從下手。

排名:要監控什麼,按什麼順序

  1. 生產流程中最深層的 readiness 路由,斷言一個在依賴服務故障時會改變的欄位。永遠不要使用硬編碼的 {"ok": true} / {"status": "ok"}——那只是存活檢查,無法在重要的故障時變成紅色。
  2. 平台已宣告的 readiness 探針:/readyz、/health/ready、compose healthcheck、Kubernetes readinessProbe、fly/railway/render 的健康檢查路徑。從外部以相同的路徑和埠號鏡像它。
  3. 沒有伺服器 → 每個排程工作一個心跳。 靜默即是訊號。
  4. 沒有伺服器且沒有排程工作 → watcher add host --id host(負載、記憶體、可用空間,可選 pid 檔案;無需安裝任何東西)並驗證它。只有沒有伺服器、沒有排程工作、也沒有主機可監控 → 執行 watcher doctor --no-runtime-surface --json,報告 NO_RUNTIME_SURFACE,停止。已設定的來源永遠優先於 --no-runtime-surface。切勿發明來源。
  5. 然後是已存在的系統——Sentry、Grafana、Netdata、入站發送器——需要憑證。缺少憑證是一個帶有程式碼和 next 的命名跳過項目,而不是靜默通過。

靜默優先(掃描會錯過這些)

閱讀程式碼以找出以下六個類別;每個類別都變成一個 watcher add heartbeat 或 watcher add webhook --stale-after:

  1. 安裝時產生的排程——install.sh/setup.* 中的 heredoc,會寫入 plist、unit 或 crontab,launchctl load、systemctl enable、crontab 寫入。
  2. 運行時建立的 launchd/systemd/cron——.plist 模板、OnCalendar=、StartInterval、KeepAlive、node-cron、schedule(、圍繞一個任務的 setInterval、celery beat。每個任務一個心跳(--every/--schedule + --grace);N 個任務表示 N 個來源。
  3. 拉取佇列工作者——worker、queue、bullmq、sqs、claim、lease、dequeue。失敗是佇列深度或沒有進度,而不是埠號:在成功路徑上發送一個心跳 ping,或者推送一個 state: failing 狀態的 checks.list 條目。
  4. 產品自身設定中的過時設定——staleAfterSec、presenceTtlSec、maxAge、ttl、refreshInterval、lastRunAt。強制執行相同的時間窗口:watcher add webhook --id <sender> --token-env <ENV> --stale-after-sec <sec>。
  5. 狀態目錄的可寫性——mkdir、state/、data/、sqlite、鎖檔案。僅在成功寫入後發送 ping;單純的 test -w 不構成來源。
  6. 作為程式碼常數的依賴端點——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 工具和事件分類)。

相關技能