06 - CLI 與自動化基礎
← 05-Agent偵測與狀態機制 | 00-Index | 下一篇 → 07-Agent-Skill讓AI自己操控Herdr
心智模型:三種基本元件
| 元件 | 職責 |
|---|---|
Layout(workspace / tab / pane 拓撲) | 建立與組織「終端機的位置」 |
| Pane | 控制一個原始終端:跑指令、送輸入、讀輸出、等輸出 |
| Agent | 用名字或 pane 控制一個被認出來的 coding agent,含 lifecycle 狀態 |
選錯元件是自動化最常見的錯誤。 判斷準則:
- 一般 shell、測試、server、CI watcher → pane 指令
- 需要 Herdr 理解「這是哪個 agent」「它現在什麼狀態」 → agent 指令
鐵則一:ID 從 JSON 讀,不要猜
建立類指令都會印 JSON。永遠從回應裡抓 ID。
created=$(herdr workspace create --cwd ~/Taiwan_IM_board --label board --no-focus)
ws=$(printf '%s\n' "$created" | jq -r '.result.workspace.workspace_id')
pane=$(printf '%s\n' "$created" | jq -r '.result.root_pane.pane_id')
split=$(herdr pane split "$pane" --direction right --no-focus)
worker=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')回應路徑速查:
| 指令 | 主要回傳路徑 |
|---|---|
workspace create | .result.workspace / .result.tab / .result.root_pane |
tab create | .result.tab / .result.root_pane |
pane split | .result.pane |
pane move | .result.move_result.pane.pane_id(舊值在 .previous_pane_id) |
agent start / agent prompt / agent wait | .result.agent |
pane wait-output | .result.pane_id / .result.matched_line / .result.read |
pane read / agent read(socket API) | .result.read.text |
鐵則二:明確指定目標
herdr pane split --current --direction right --cwd "$PWD" --no-focus # ✅
herdr pane split --direction right # ❌ 用 UI 目前 focus 的 pane省略目標時 Herdr 會用 UI 目前 focus 的 pane——那可能是使用者剛切過去的、或另一個 client 的。多 agent 環境下這一定會出事。
建立版面
# workspace(順便有 tab + root pane)
herdr workspace create --cwd ~/project --label api --no-focus
# tab
herdr tab create --workspace w1 --label validate --no-focus
# 分割 pane
herdr pane split --current --direction right --cwd "$PWD" --no-focus
herdr pane split w1:p2 --direction down --ratio 0.4 --no-focus分割方向的幾何規則:寬的往右切、窄或高的往下切,避免連續同方向切出無法使用的細長條。先看形狀:
herdr pane layout --pane "$HERDR_PANE_ID"在 pane 裡跑普通指令
herdr pane run w1:p3 "python3 tools/validate.py"
herdr pane send-text w1:p3 "some literal text" # 不送 Enter
herdr pane send-keys w1:p3 ctrl+c # 送按鍵pane run會把指令文字和 Enter 一起原子送出,而且尊重 pane 目前的 bracketed-paste 模式。跑指令一律用它。send-text+send-keys enter是低階做法,兩次操作分開,不保證原子性。
按鍵語法:普通字元 a、特殊鍵 enter tab esc backspace left right up down、和弦 ctrl+h alt+x shift+tab、功能鍵 f1、有名字的標點 minus plus backtick。escape 是 esc 的別名;舊式 C-c 也接受。
讀輸出
herdr pane read w1:p3 --source recent-unwrapped --lines 120
herdr agent read writer-a --source recent-unwrapped --lines 200
herdr pane read w1:p3 --source visible --ansi四種 source:
| Source | 意思 | 適合 |
|---|---|---|
visible | 目前渲染的畫面 | UI 回饋迴圈 |
recent | 近期輸出,含終端換行折行 | 一般 |
recent-unwrapped | 近期輸出,折行接回去 | log、transcript 首選 |
detection | agent 偵測用的底部純文字快照 | 除錯偵測 |
行為細節:
- 預設輸出 UTF-8 純文字、剝掉 ANSI escape。要保留顏色用
--format ansi或--ansi(detection永遠是純文字)。 recent系列:--lines N取「最後 N 個渲染終端列」;不給預設 80 列。visible和detection:不給--lines回傳整份快照;給了則保留最後 N 行。
⚠️ Alternate screen 的坑(Claude Code / OpenCode)
全螢幕型 agent(Claude Code、OpenCode)把 transcript 畫在終端的 alternate screen,不是 Herdr 的 host scrollback。
Herdr 有做了一件聰明事:對一個閒置、被認出來、而且停在 transcript 底部的 agent,recent / recent-unwrapped 且 --lines 超過可見畫面時,會自動用 agent 的滑鼠捲動介面去收集重疊的頁面,讀完再把 viewport 放回底部。
但這條路徑有條件:
- agent 正在
working/blocked/unknown時,明確指定--lines N的 alternate-screen 歷史讀取會回agent_not_idle。→ 等它 idle 再讀,或改用--source visible。 - 使用者手動捲動過、有 direct attach、或那個程式不回報滑鼠滾輪時,Herdr 不會動 viewport。
visible、detection、ANSI 讀取、輸出等待與訂閱一律是被動的,不會移動 viewport。
官方給的 fallback,也是實務上最好用的一招:
叫 agent 把完整回應寫成 Markdown 存到暫存目錄,只回傳檔案路徑,然後你直接讀那個檔案。
⚠️ 但這是 fallback,不要一開始就在 prompt 裡要求寫檔(會污染任務)。不過在詳解 / 筆記量產這種本來就要寫檔的任務裡,寫檔是任務本體,所以天然沒有這個問題——見 09-實戰-刷題網站Taiwan-IM-board。
等待
等普通指令的輸出
herdr pane wait-output w1:p3 --match "OK" --timeout 120000
herdr pane wait-output w1:p3 --regex "passed|failed" --timeout 120000- 它會立刻搜尋目前的快照,所以已經存在的輸出也會命中。
- 預設 source 名稱是
recent,比對時當成「最新 80 個渲染列的 unwrapped 近期輸出」;--lines可改。 --match是單行內的字面子字串;--regex是 Rust 正規表示式,一次比對一行。- 它完全不解讀 agent lifecycle。
等 agent 狀態
herdr agent wait writer-a --timeout 900000
herdr agent wait writer-a --until blocked --timeout 120000
herdr agent wait writer-a --until idle --until done --timeout 900000- 不給
--until時,預設接受idle/done/blocked。 agent wait是觀察目前狀態:如果現在就符合,立刻回傳。- 要接受
unknown必須明確寫--until unknown。
送 prompt 並等它
herdr agent prompt writer-a "把 §Diagnosis 依 2026 guideline 改寫" --wait --timeout 900000規則(這段一定要看懂,不然會誤判):
agent prompt把文字 + 編碼過的 Enter 原子送出,尊重終端目前的 bracketed-paste 模式。agent 正在工作時也可以送。--wait是立刻送出,然後:- 如果 agent 從非 working 狀態開始,Herdr 要求五秒內觀察到 lifecycle 變化。沒有的話回
agent_prompt_stalled,而不是無限等下去。(caller--timeout≤ 5 秒時走一般的timeout錯誤。) - 觀察到活動之後,才等你要的 settled 狀態。
- 如果 agent 從非 working 狀態開始,Herdr 要求五秒內觀察到 lifecycle 變化。沒有的話回
- ⚠️ 它追的是 lifecycle 狀態,不是「這一輪對話」。如果 agent 本來就在工作,目前那一輪結束就可能滿足這個 wait。
--until只有在同時有--wait時才允許。
🔑 實務結論:
agent prompt --wait回來 不等於「我要的任務做完了」。真正的驗收要靠:檢查它應該產生的檔案是否存在且正確,這比讀畫面可靠一百倍。
Timeout 與錯誤
pane wait-output、agent wait、agent prompt --wait不給--timeout就會無限等。- Timeout 或 server 錯誤 → JSON 印到 stderr,exit code 1。
- CLI 語法錯誤 → exit code 2。
啟動 agent
# 1. 先要有一個停在 shell prompt 的 pane
split=$(herdr pane split --current --direction right --cwd "$PWD" --no-focus)
p=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')
# 2. 才能啟動 agent
herdr agent start writer-a --kind codex --pane "$p"
# 3. 需要傳給 agent 本身的參數放在 -- 之後
herdr agent start reviewer --kind codex --pane "$p" -- --profile worker⚠️ 不要在編排腳本裡寫死模型名。 官方文件的範例寫的是
-m gpt-5.4,但該模型已於 2026-08-31 從 ChatGPT 登入的 Codex 退場。 讓~/.codex/config.toml的 profile 決定模型(見 Codex CLI 05),模型換代時腳本才不會跟著壞。
規則:
- 「可用的 shell pane」= 停在互動 shell prompt:shell 自己擁有前景,沒有前景指令、編輯器或 agent 在跑。
agent start只在 Herdr 偵測到預期的 agent 在同一個終端、而且準備好接受互動輸入之後才回傳。- 預設啟動 timeout 30000 ms;明確給的值必須 > 3000 且 ≤ 300000。
--kind選的是 Herdr 認定的標準執行檔;--之後的參數原封不動傳給它。- 手動啟動的 agent 也會被自動偵測,用 pane ID 定址;想要穩定的名字就
agent rename。
送按鍵給 agent 的互動 UI
herdr agent send-keys writer-a esc
herdr agent send-keys writer-a ctrl+c
herdr agent send-keys writer-a up enterHerdr 會先驗證所有按鍵,才寫出任何 byte。
pane 輸入 vs agent 輸入的差別:
- pane 輸入:不管目前誰佔用,直接對那個終端下手。
- agent 輸入:先解析出存活的 agent;如果那個 agent 已經不再控制該 pane,操作會被拒絕。
👉 編排時用 agent 輸入(比較安全);只有在你刻意要原始終端控制時才用 pane 輸入。
一段完整的最小編排範例
#!/usr/bin/env bash
set -euo pipefail
# 1. 開一個背景 pane
split=$(herdr pane split --current --direction right --cwd "$PWD" --no-focus)
p=$(printf '%s\n' "$split" | jq -r '.result.pane.pane_id')
# 2. 啟動 codex
herdr agent start reviewer --kind codex --pane "$p"
# 3. 丟任務並等它
herdr agent prompt reviewer \
"審查目前的 git diff,只回報可執行的問題。" \
--wait --timeout 600000
# 4. 讀結果
herdr agent read reviewer --source recent-unwrapped --lines 200等一個 agent 來問你問題、看一下、然後回它:
herdr agent wait reviewer --until blocked --timeout 120000
herdr agent read reviewer --source recent-unwrapped --lines 80
herdr agent send-keys reviewer esc跑一個普通 process 並等它的輸出(不當成 agent):
herdr pane run w1:p3 "npm run validate"
herdr pane wait-output w1:p3 --regex "通過|FAIL|Error" --timeout 300000
herdr pane read w1:p3 --source recent-unwrapped --lines 60其他常用指令
# 狀態
herdr status
herdr status server
herdr status client
# session
herdr session list --json
# git worktree(見第 09、10 章的隔離工作流)
herdr worktree list --cwd .
herdr worktree create --cwd . --branch feat/詳解-114 --no-focus
herdr worktree remove --workspace w2 --force
# 通知(可以在腳本結束時叫自己)
herdr notification show "詳解量產完成" --body "114 心臟 24 題已產出" --sound done
# API schema(要寫工具時)
herdr api schema --json --output herdr-api.schema.json🔗 相關筆記
- 05-Agent偵測與狀態機制 — 狀態的來源
- 07-Agent-Skill讓AI自己操控Herdr — 下一步:把這些指令交給 Claude 自己下
- 08-Claude當大腦-Codex當雙手 — 完整編排腳本
- 13-疑難排解與術語速查表 — 指令 cheat sheet
- Python 07 - 實戰自動化範例 — 刷題網站的 tools/ pipeline,正是被編排的對象
最後更新:2026-08-04
