---
title: "05 - Agent 偵測與狀態機制"
type: note
specialty: Programming
tags: [herdr從0開始使用教學, 05-agent狀態, detection, integration]
created: 2026-08-04
updated: "2026"
modified: 2026-08-04
---

# 05 - Agent 偵測與狀態機制

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

---

## 為什麼這章不能跳過

因為 [[08-Claude當大腦-Codex當雙手|多 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 走**，不會被你的捲動干擾。

---

## 五種狀態的精確定義

| 狀態 | 精確意思 |
|---|---|
| `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`：

```bash
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」中較新的相容版本。

```bash
herdr server agent-manifests            # 看目前用的來源與版本
herdr server update-agent-manifests     # 立刻抓遠端更新並重載
herdr server reload-agent-manifests     # 手動改了本機覆寫後重載
```

想關掉背景遠端檢查：

```toml
[update]
manifest_check = false
```

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

---

## 除錯神器：`agent explain`

當某個 pane 狀態不對時：

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

輸出會告訴你：

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

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

```bash
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：

```bash
HERDR_AGENT=claude fence -- claude
```

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

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

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

```bash
HERDR_PROCESS_DETECTION=child-groups
```

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

---

## 自訂顯示（不搶語意狀態）

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

```bash
# 語意狀態（會影響 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*
