05 - Agent 偵測與狀態機制

04-日常操作-滑鼠與鍵盤 | 00-Index | 下一篇 → 06-CLI與自動化基礎


為什麼這章不能跳過

因為 多 agent 編排 的每一次「等 Codex 做完」都建立在狀態判斷上。如果你不知道 idle 是怎麼來的,你就會在腳本裡錯把「Herdr 不確定」當成「做完了」。


Herdr 怎麼知道 pane 裡跑的是什麼

兩階段:

  1. 先認 process:找出這個 pane 的前景 process 是什麼(Unix 用 foreground process group;Windows 掃 pane shell 的子代 process 樹)。
  2. 再判狀態:每個 pane 有一個 status authority(狀態權威)——不會有兩個來源同時說話。

兩種狀態權威

A. Lifecycle 權威(integration 說了算)

有完整 lifecycle hook 的 agent,只要 integration 裝好而且正在回報,hook 事件就是 idle/working/blocked 的權威,Herdr 不會再用畫面偵測當備援(避免兩個真相來源打架)。

適用:Pi、OMP、Kimi Code CLI、OpenCode、Kilo Code CLI、MastraCode

B. Screen manifest(畫面偵測)

沒有完整 lifecycle hook 的 agent,Herdr 讀 pane 緩衝區底部的即時畫面快照,用 TOML manifest 去比對,判斷 idle / working / blocked。有些 agent 還會提供終端標題和 OSC 進度序列當額外證據。

適用:Claude Code、Codex、Cursor、Copilot CLI、Devin、Droid、Grok、Amp、Kiro、Maki、Antigravity、Qoder、Hermes…

🔴 這對你最重要Claude Code 和 Codex 都屬於 B 類

herdr integration install claude / install codex 裝的是 session identity 型 integration ——它讓 Herdr 拿到原生 session id(server 重啟後可以 claude --resume <id> / codex resume <id> 續接對話),但狀態仍然是靠讀畫面判斷的

一個關鍵細節

畫面快照取自緩衝區底部的即時畫面,不是你捲動後看到的 viewport。所以你在 Herdr 裡往上捲歷史時,偵測仍然跟著底部的即時 agent UI 走,不會被你的捲動干擾。


五種狀態的精確定義

狀態精確意思
workingagent 正在跑
blockedHerdr 認出了批准 / 提問 / 權限的 UI
done底層 idle 狀態,背景工作完成但你還沒看過
idle準備好接收輸入,而且它的 tab 已經在 focus 的 Herdr UI 裡被看到過
unknown有 agent 在,但 Herdr 無法有信心地分類

done vs idle

底層是同一個狀態,差別只在「有沒有被看過」:

  • 會標記為看過:focus 那個 tab、pane focusagent focus
  • 不會標記為看過agent read / pane read(CLI 讀取)

💡 這個設計很貼心:你用腳本讀 agent 輸出不會把「done」這個提醒消掉,所以 sidebar 上的「有東西等你看」不會被自動化偷偷清掉。

blocked 是刻意嚴格的

對畫面偵測型 agent,Herdr 只有在畫面快照真的比對到已知的批准 / 提問 / 權限 UI 時才標 blocked。如果某個已知 agent 沒有任何 manifest 規則命中,Herdr 會退回 idle,並在 explain 輸出裡標記成 default_known_agent_idle_fallback

後果:agent 出現一個 Herdr 還沒學過的新提示畫面時,它可能顯示成 idle 而不是 blocked

好消息是這只影響顯示狀態和等待——這種情況不會讓 Herdr 送出輸入或做破壞性動作。

⚠️ unknown 不等於完成

官方明講:unknown 代表「有 agent 在但分不清楚」,不代表工作成功了。腳本裡如果需要區分這件事,就明確用 --until

herdr agent wait writer-a --until idle --until done --timeout 900000

agent waitagent prompt --wait 預設就接受 idle / done / blocked 三者;要接受 unknown 必須明確寫 --until unknown。)


狀態往上匯總(rollup)

Sidebar 會把狀態往上冒:

  • 一個 blocked 的 agent → 它的 pane、tab、workspace 全都看起來 blocked
  • 一個 working 的 agent → workspace 看起來活躍
  • 一個 done 的 agent → 一直顯示到你去看它為止

這就是 Herdr 的主要工作流:同時開好幾個 agent、讓它們平行跑,然後用 sidebar 判斷哪個專案需要決定、哪個還在跑、哪個可以收成了。


偵測 manifest 與更新

  • Bundled manifest 內建在 Herdr binary 裡。
  • Herdr 也會去 herdr.dev 檢查遠端 manifest 更新,自動套用有效的 per-agent 規則更新,不需要重啟 Herdr
  • 本機覆寫放在 ~/.config/herdr/agent-detection/<agent>.toml本機覆寫永遠贏
  • 沒有本機覆寫時,Herdr 用「快取的遠端 manifest」與「binary 內建 manifest」中較新的相容版本。
herdr server agent-manifests            # 看目前用的來源與版本
herdr server update-agent-manifests     # 立刻抓遠端更新並重載
herdr server reload-agent-manifests     # 手動改了本機覆寫後重載

想關掉背景遠端檢查:

[update]
manifest_check = false

遠端 manifest 只能修補 Herdr 已經認得的 agent 的偵測規則。要加一個全新的 agent,仍然要更新 Herdr binary。


除錯神器:agent explain

當某個 pane 狀態不對時:

herdr agent explain w1:p2
herdr agent explain w1:p2 --verbose
herdr agent explain w1:p2 --json

輸出會告訴你:

  • 這是哪個 agent、最終判定的狀態
  • 有沒有因為完整 lifecycle 權威而跳過畫面偵測
  • manifest 來源與版本、快取的遠端版本、本機覆寫有沒有蓋掉別的
  • 命中的是哪一條規則、以及它的區域證據
  • 沒有規則命中時的 idle fallback 理由

想離線分析一份存檔畫面:

herdr agent read w1:p2 --source detection --format text > screen.txt
herdr agent explain --file screen.txt --agent codex --json

⚠️ agent explain 的即時模式是由正在跑的 server 評估的,所以升級 Herdr 之後要重啟或 handoff 到新 server,即時 explain 才會反映新版行為。


常見的偵測陷阱

1. tmux 套在 Herdr 裡面

Herdr 可以跑在 tmux 外層環境裡。但 agent 偵測不會去看在 Herdr pane 裡面啟動的 tmux session。如果你的 shell framework 會自動進 tmux,Herdr 就只會看到 tmux 這個 process,看不到後面的 agent。

👉 在 Herdr pane 裡不要自動進 tmux。

2. Sandbox / VM wrapper 遮住真正的 agent

在 Linux 和 macOS 上,一個 host 看得到的 wrapper 可能把真的 agent process 藏起來。用 HERDR_AGENT=<agent> 告訴 Herdr 該用哪份 manifest:

HERDR_AGENT=claude fence -- claude

這個提示只作用在那個前景 process 上。不要全域 export,除非你真的希望所有繼承到的前景 process 都被當成那個 agent。

3. 受限的 Linux runtime 看不到前景 process group

某些受限環境不提供終端前景 process group。可以讓 server 改用子 process group 推論:

HERDR_PROCESS_DETECTION=child-groups

⚠️ 這是 opt-in 的 best effort:比較新的背景 job 可能被誤認成前景 job。這個變數是 server 讀的,需要重啟 server,而且要設在遠端 server 環境而不是連上去的 client。


自訂顯示(不搶語意狀態)

有時你想在 sidebar 顯示「這個 agent 在做什麼」,但不想把 lifecycle 權威搶走。答案是 metadata

# 語意狀態(會影響 wait / 通知 / rollup)
herdr pane report-agent w1:p1 --source custom:indexer --agent docs-bot --state working
 
# 純顯示(不影響任何邏輯)
herdr pane report-metadata w1:p1 \
  --source user:codex-title \
  --agent codex \
  --title "114年心臟 001-012 詳解" \
  --display-agent "Codex: 心臟" \
  --token summary="詳解量產" \
  --ttl-ms 3600000
  • --state 影響 wait、通知、rollup。
  • --title / --display-agent / --state-label / --token 只影響外觀
  • 跟 Herdr 官方 integration 並存的自訂 hook,應該用 metadata 而不是 report-agent,才不會把 integration 的權威搶走。

💡 這在量產詳解時超實用:讓每個 Codex pane 的 sidebar 直接顯示「它負責哪一批題號」,你掃一眼就知道誰做完了。用法見 09-實戰-刷題網站Taiwan-IM-board


一句話總結

Claude 和 Codex 的狀態是 Herdr 讀畫面猜的,不是 agent 主動回報的。 所以:wait 用來省事,但關鍵結果一定要 read 出來親自確認。


🔗 相關筆記


最後更新:2026-08-04