05 - Agent 偵測與狀態機制
← 04-日常操作-滑鼠與鍵盤 | 00-Index | 下一篇 → 06-CLI與自動化基礎
為什麼這章不能跳過
因為 多 agent 編排 的每一次「等 Codex 做完」都建立在狀態判斷上。如果你不知道 idle 是怎麼來的,你就會在腳本裡錯把「Herdr 不確定」當成「做完了」。
Herdr 怎麼知道 pane 裡跑的是什麼
兩階段:
- 先認 process:找出這個 pane 的前景 process 是什麼(Unix 用 foreground process group;Windows 掃 pane shell 的子代 process 樹)。
- 再判狀態:每個 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 走,不會被你的捲動干擾。
五種狀態的精確定義
| 狀態 | 精確意思 |
|---|---|
working | agent 正在跑 |
blocked | Herdr 認出了批准 / 提問 / 權限的 UI |
done | 底層 idle 狀態,背景工作完成但你還沒看過 |
idle | 準備好接收輸入,而且它的 tab 已經在 focus 的 Herdr UI 裡被看到過 |
unknown | 有 agent 在,但 Herdr 無法有信心地分類 |
done vs idle
底層是同一個狀態,差別只在「有沒有被看過」:
- 會標記為看過:focus 那個 tab、
pane focus、agent 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 wait 和 agent 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出來親自確認。
🔗 相關筆記
- 04-日常操作-滑鼠與鍵盤 — 上一步
- 06-CLI與自動化基礎 — 下一步:把狀態變成可等待的指令
- 08-Claude當大腦-Codex當雙手 — 這一章的知識在哪裡派上用場
- 13-疑難排解與術語速查表 — 狀態不對時的排查流程
最後更新:2026-08-04
