Telegram + Hooks + Watchdog — 點樣 run 起
2026-04-23 — Steven 要 save 低,因為呢日一次過爆 3 個 bug:agent indicator 冇 show、mcp-watchdog 壞 4 日、修好後 spam 警告。借呢次做完整架構文檔。
Part 1 — 你 send TG 俾 CC 之後發生咩事
你 send msg
↓
UserPromptSubmit hook
↓
tg-thinking.sh → send「🤔 思考中...」→ 記低 msg_id
↓
Claude 開始用工具
↓
每個 tool call
↓
tg-tool-update.sh → edit 同一條 msg (加 #1 #2 #3... 計數 + tool icon)
↓
Claude 完成
↓
新 TG msg(final reply)→ 你手機 DING
設計哲學:
- 一條 msg 代表「Claude 思考中」—— edit 唔會 trigger 通知
- 新 msg 先有聲 —— 只有最終答案先 ping 你
檔案:
~/.claude/hooks/tg-thinking.sh~/.claude/hooks/tg-tool-update.sh- State:
/tmp/tg-thinking-${state_base}.json
Part 2 — Agent hook 點 work
正常流程(foreground)
Main Claude 派 subagent (例 Copy Agent)
↓
tg-agent-start.sh → 寫「/tmp/tg-agent/${state_base}-current.txt」= "Copy Agent"
↓
Subagent 跑 (可能幾分鐘)
↓
tg-agent-done.sh → 清走 current.txt
Background agent (2026-04-23 新加)
Main 派 subagent 用 run_in_background=true
↓
tg-agent-start.sh 寫「/tmp/tg-agent/${state_base}-bg-${tool_use_id}.txt」= "Research Agent"
↓
Main 唔等 subagent return,繼續做其他嘢
↓
tg-agent-done.sh 知道係 background → NOT clear state
↓
subagent 真正完成
↓
tg-subagent-stop.sh (SubagentStop hook) → 清 bg-*.txt
tg-tool-update.sh 每次 edit thinking msg 時讀 state files → 顯示:
🤔 思考中... #5
👤 Copy Agent (foreground)
🤖 BG: Research Agent, QA Agent (background,可以多於一個)
已知 bug(2026-04-23 未修)
Foreground agent 跑時,Main 會 block 住等 subagent return。呢段時間:
- 冇 tool call in Main → tg-tool-update.sh 唔 fire
- Subagent 內部 tool calls → 只 trigger subagent 自己嘅 hooks,唔影響 Main 嘅 thinking msg
- 結果:3 分鐘 Research Agent run 期間,TG msg 凍結冇更新
Steven 批咗修,未做。要做嘅:
- Step A:tg-agent-start.sh 自己主動 edit TG msg(唔淨係寫 state)
- Step B:背景 watcher 每 15 秒 update 一次 elapsed time
- Step C:改 hook 執行 order
Part 3 — 點解 TG 會死 + 保安巡查
TG 點會死
每個 CC session(cc / cc2 / cc3)背後有個 bun 程序,責任係 long-poll Telegram 嘅 getUpdates API,將 msg 送返去 Claude。
Bun 會靜靜死嘅原因:
- 網絡問題
- Plugin crash
- RAM 壓力令 MCP RPC pipe 凍結
- Telegram API 限流
結果:你 send msg → inbox 有但 bun 唔送 → 你冇回應,以為 Claude 死咗
保安 = mcp-watchdog(systemd timer,每 1 分鐘一次)
每 tick 對每個 session 做 4 個 check:
| Check | 睇咩 | Failure mode |
|---|---|---|
| 1 | bot.pid 檔案存在 + PID 仲 alive | PLUGIN_DEAD |
| 2 | Claude 主程序仲 alive | CLAUDE_DEAD |
| 3 | Inbox 冇塞住 | STUCK_INBOX |
| 4 | last_sid 檔案 mtime < threshold | MCP_STALE |
last_sid 係 bun 每次 getUpdates 成功都會覆寫一次嘅檔案(~30 秒一次)。如果 mtime 太舊但 bun 仲 alive → pipe 斷咗。
Alert 邏輯(2026-04-23 改良)
- Two-tick confirmation:第 1 個 bad tick 靜音(可能係瞬時),第 2 個 tick 同狀態先確認
- 每個狀態只報 1 次:用
/tmp/mcp-watchdog-alerted-${session}marker 防重複 - 狀態轉變或恢復 → 清 marker → 下次可以再 alert
- 恢復會 send「✅ [session] MCP 恢復」
Mode
- notify(當前):send 警告俾 Steven,要佢手動
bash ~/bin/start-tg.sh cc3 - restart(未 enable):watchdog 自動執行 start-tg.sh
設 WATCHDOG_ACTION=restart 就自動化。Steven 未開因為要先信 watchdog 唔會誤判。
Threshold
MCP_STALE_THRESHOLD=1800(30 分鐘)—— 2026-04-23 由 600s 拉到 1800s- 原因:idle session 唔應該觸發(你冇 send msg 就唔會有新 update,係合理嘅)
Part 4 — 2026-04-23 嗰日發生咩事(post-mortem)
時間線:
- Apr 19:home 目錄重組,mcp-watchdog.sh 由
/home/claude/搬去/home/claude/scripts/ - Apr 19-23:systemd unit ExecStart 路徑冇更新 → watchdog 每分鐘
203/EXEC失敗,冇警告 - Apr 23 11:30:RAM 91% 警告彈出(watchdog 壞咗冇清 zombie sessions)
- Apr 23 11:43:Claude 修返 systemd path
- Apr 23 11:44-12:22:watchdog 醒返,見 cc2/cc3 last_sid 35 分鐘唔更新 → 當壞咗 → 每分鐘 spam 警告
- Apr 23 12:25:Claude 加 dedup + 拉 threshold → spam 停
學到嘢:
- Home reorg 要 grep
/etc/systemd/搵用到嘅 script path - Oneshot systemd service fail 時好靜,需要 journalctl 定期 check
- Watchdog 設計要有 rate limit + 兩級確認,唔好每 tick 報一次
- Idle session 唔更新 last_sid 係 normal,threshold 10 min 太短
檔案位置 cheatsheet
| 類別 | 路徑 |
|---|---|
| Hook scripts | ~/.claude/hooks/tg-*.sh |
| Watchdog script | ~/scripts/mcp-watchdog.sh |
| Systemd unit | /etc/systemd/system/mcp-watchdog.{service,timer} |
| Hook config | ~/.claude/settings.json |
| Thinking state | /tmp/tg-thinking-*.json |
| Agent state | /tmp/tg-agent/*.txt |
| Watchdog state | /tmp/mcp-watchdog-state.json |
| Alert markers | /tmp/mcp-watchdog-alerted-* |
| Channel dirs | ~/.claude/channels/telegram{,-cc2,-cc3,-team-cc}/ |