herdr で `agent start` を呼ぶ前、`agent prompt` / `pane run` で自由記述テキストを渡す前、`blocked` の相手をキー送信 (`esc` 等) で操作する前、および herdr 経由の操作で想定外の挙動・エラーに遭遇したときに参照する。
Scanned 9/5/2026
Install to Claude Code
npx -y skills add 844196/dotfiles --skill gotcha --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Gotcha?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/844196-gotcha)More formats (shields.io, HTML) on the badges page.
---
name: gotcha
description: herdr で `agent start` を呼ぶ前、`agent prompt` / `pane run` で自由記述テキストを渡す前、`blocked` の相手をキー送信 (`esc` 等) で操作する前、および herdr 経由の操作で想定外の挙動・エラーに遭遇したときに参照する。
---
# Herdr の罠
herdr 本体のスキルは CLI の使い方 (構文) を教えてくれるが、"どう事故るか" までは教えてくれない。ここでは実運用で踏んだ罠と、上流に一次報告のある既知の地雷をまとめる。委任フロー固有の内容 — SendMessage のタグ運用、名前解決、自己承認文言など — は `herdr:orchestrate` に書いてある (`herdr:delegate-receive` にはタグ語彙だけが子向けに複製されている)。ここにあるのは herdr で誰かのペインを操作する場面全般に当てはまる罠。
## 罠: 相手の入力欄に中身そのものを流し込む → 誤爆・埋没・無言の切り詰め
**相手が Read ツールを持つ agent なら、渡すのは固定タグ + 絶対パスだけ (以下**タグ付きポインタ**)。中身そのものは argument に一切載せない。** 受け手は自分の Read でファイルを読む。
1. Write ツール (または Edit ツール) で自由記述テキスト (説明文・要約・他ファイルからの引用など) をファイルへ書き込む。置き場所はあなたのスクラッチパッドディレクトリ (システムプロンプトで指定されているもの)。**送信ごとに別のファイル名にすること** — 固定名にすると、並行するやり取りどうしで中身が入れ替わる。
2. `herdr agent prompt <target>` へは、相手が分岐に使う語彙をそのままタグにした短い文だけを渡す:
```bash
herdr agent prompt <target> "作業完了: <手順 1 のファイルの絶対パス>"
```
相手が複数の送信元からタグ付きポインタを受け取りうる場合は、タグに自分の名前を添えて送信元を明示する:
```bash
herdr agent prompt <target> "作業完了 <自分の名前>: <手順 1 のファイルの絶対パス>"
```
自分の名前は `herdr agent get "$HERDR_PANE_ID"` の `.result.agent.name` で取れる。ただしこのフィールドは `agent start <name>` で名前を付けて起動された agent にしか無い。送信元が 1 対 1 で明らかな場合は名前を省いてよい。
**理由**: 中身をそのまま引数に渡すと 3 つの事故が起きる。パス 1 個ならどれも起きない。
- **コマンド置換の誤爆** — バッククォートや `$(...)` を含む引用があると、bash がそれをコマンド置換として評価し、引用のつもりのコマンドが実際に実行される (下記の事故)
- **実状態の埋没** — 長文は送信の瞬間に相手のペインの入力欄を埋め、承認待ちなどの実状態が人間にもエージェントにも一時的に見えなくなる
- **無言の切り詰め** — 長い文字列は途中で切れたまま着弾し、送信側には成功して見える ([#2862](https://github.com/herdrdev/herdr/issues/2862))。再現が確認されているのはシェルへの注入なので、詳細は下記「相手が Read ツールを持たない場合」を参照
**実際に起きた事故**: あるセッションで、調査結果を子エージェントに伝えるメッセージ本文に「`` `git reset --hard HEAD~` が実行されて壊れた」という説明を引用として書いた。この本文をそのままダブルクォートに埋め込んで `herdr agent prompt` に渡したところ、引用のつもりで書いた `git reset --hard HEAD~` がコマンド置換として実際に実行され、直近のコミット (実装一式を含む squash commit) がまるごと失われた。dangling commit として git オブジェクトに残っていたため復旧できたが、`git gc` のタイミング次第では完全に消えていた。
### 相手が Read ツールを持たない場合 (非 agent ターゲットへのフォールバック)
`herdr pane run <id> "<text>"` で裸のシェルへ中身そのものを渡す必要があるとき (例: コミットメッセージの本文を渡す) は、ファイル経由の `$(cat ...)` を使う。
```bash
herdr pane run <id> "git commit -m \"\$(cat <手順 1 のファイル>)\""
```
`$(cat ...)` はコマンド置換だが、その結果は再度シェル解釈されない。ファイルの中身にバッククォートや `$(...)` が含まれていても、そのまま 1 個の引数として渡るので安全。ファイル名を送信ごとに変える運用は上記と同じ。
**シェルへ注入するコマンド行は 1024 バイトを超えると無言で切り詰められる** ([#2862](https://github.com/herdrdev/herdr/issues/2862))。閉じクォートが落ちてコマンドが実行されないまま、呼び出しは成功として返る。`$(cat ...)` を使えば渡す引数自体が短いままなので、この制限にも当たらない。
### 入力行が壊れたら
誤送信で対象ペインの入力行が中途半端な状態になったとき、消えたかどうか確認せずに送り直すと、二重入力や意図しないキー入力の混入につながる。次の順でクリアし、空になったことを確認してから送り直す。
```bash
herdr agent send-keys <target> esc
herdr agent send-keys <target> ctrl+c
herdr agent send-keys <target> ctrl+u
herdr agent read <target> --source visible # 入力行が空になったか確認
```
`ctrl+u` (行全体を削除) まで試しても残る場合は、原因 (バックティック展開・意図しない改行の混入など) を特定してから送り直す。
## 罠: 起動直後のペインは、まだ指示を受け付ける状態とは限らない
新しく起動したエージェントを初めて動かすディレクトリでは確認ダイアログが 2 段階で挟まる。**どちらも明示エラーとして返るので、以下は「どのエラーが返ったときに何をするか」の話になる。**
### `agent_pane_busy` — シェルがまだ「利用可能なシェル」でない
herdr は、シェル自身が唯一の前景プロセスであるときだけそのペインを「利用可能なシェル」とみなす。`.zshrc` から mise や atuin が子プロセスとして走っている間はこれを満たさない。
- **呼び出し側のリトライは不要。** CLI が `agent_pane_busy` を受けたとき、シェルがまだ初期化中なら 100ms 間隔で最大 **2 秒**まで自動でリトライする。このマシンでの実測ではシェルが利用可能になるまで最大 0.345 秒なので、2 秒で十分に収まる
- **ただし `agent start --timeout` を 3 秒以下にすると内製リトライは走らない。** 既定の 30 秒のままにしておくこと
- **それでも `agent_pane_busy` が返るなら、待っても解決しない類のものである。** mise や direnv が `--cwd` 先で trust プロンプトを出していると、シェルは対話プロンプトに到達しないまま止まる。`herdr pane read <pane> --source visible` で中身を読み、`herdr pane send-keys <pane> <キー>` で答えてから `agent start` をやり直す。`--cwd` に `.envrc` があると分かっているなら、先回りして `direnv exec <cwd> <agent>` の形で起動してもよい。この状態では agent が存在しないので `agent` 系コマンドは一切使えない (`pane list` の `agent_status` は `blocked` ではなく `unknown`)
### `agent_not_ready` — エージェント自身の初回ダイアログ
claude は初めて動くディレクトリで確認ダイアログを出す。`agent start` は起動時に `agent_status` が `blocked` なら **`agent_not_ready` を即座に返す**。
- **対処**: `agent_not_ready` が返っても**名前は生きている**。`herdr agent read <name> --source visible` でダイアログを読み、`herdr agent send-keys <name> <キー>` で答える。`herdr agent get <name>` が `idle` になってから `agent prompt` を送る
- ダイアログの中身によっては勝手に答えてよいとは限らない。下の「規律: `blocked` のダイアログを代理で承認しない」に従うこと
## 罠: `blocked` の相手へテキストを送ると、ダイアログを勝手に承認する
`agent_status` が `blocked` の相手へテキストを送ると、herdr は**メッセージ本文を捨てたうえで Enter をダイアログに送り、そのダイアログのデフォルト選択肢を押す** ([#2788](https://github.com/herdrdev/herdr/issues/2788))。Claude Code の Bash 権限ダイアログのデフォルトは `1. Yes` なので、**相手が訊いていた許可がそのまま承認される。** 呼び出しは `rc=0` で正常に返るため、送信側には成功に見える。**受け手側には痕跡が一切残らない** — 本文は届かず、ツール結果は正規に承認された場合と 1 バイトも変わらない。しかも auto mode のペインでは「ダイアログが出ないのは当然」がいつでも成立するので、不審に思って調べた側は無実の説明に到達して調査を打ち切る。**押されるのは、ユーザーが `ask` に指定した最後の砦のダイアログである。**
**ガードがあるのは `agent prompt` だけである。** `blocked` の相手には `agent_blocked` エラーを返し、テキストも Enter も送らない。
| 送信手段 | 送るもの | ガード |
|---|---|---|
| `agent prompt` | text + Enter | **あり** — `agent_blocked` で拒否 |
| `pane run` | text + Enter | **無し** — **ダイアログのデフォルト選択肢が押される** |
| `pane send-text` | text のみ (**bracketed paste で包まれない**) | **無し** — herdr が Enter を送ることはないが、本文はダイアログに流し込まれて失われる |
| `agent send-keys` / `pane send-keys` | キーのみ | **無し** — これは仕様として正しい (`esc` を送る経路そのもの) |
**したがって、ペイン系の低レベル API — とりわけ `pane run` — でテキストを送る前には、`herdr agent get <target>` で状態を確認すること。** 固定形式のキックであっても例外ではない — 対象が `idle` であることを確認してから送る。
**さらに、ガードは herdr の `blocked` 検出に依存している。** 判定は検出された状態が `blocked` かどうかの一致なので、**herdr が `blocked` と認識できない相手には `agent prompt` でも効かない。** 下の「`blocked` のカバー範囲はエージェント種別に依存する」を必ず併せて読むこと。
## 規律: `blocked` のダイアログを代理で承認しない
`blocked` の相手に対処するときは、**まず `herdr agent read <target> --source visible` で中身を読む。**
読み取りは **`--source visible`** で行う。`recent` / `recent-unwrapped` に `--lines` を付けると空が返ることがあり、ダイアログが出ているのに何も見えない状態になる。ダイアログは画面に出ているので `visible` で足りる。
**逆に、ダイアログが写っていないことを「出なかった」の根拠にしないこと。** 権限ダイアログは alternate screen 上の一時 UI で、解決した瞬間に消えてスクロールバックには残らない。**写らないのが正常である。**
読んだら、何を求められているかで切り分ける。
- **ツール実行の許可を求めるダイアログ** → あなたが依頼した作業の範囲内なら、あなたが判断して `esc` (却下) するか、ユーザーに上げる
- **人間の承認・同意を求めるダイアログ** → **選択肢を押さない。ユーザーへエスカレーションする。** 押せば、誰も下していない承認決定を捏造することになる
正規の経路は **`esc` (却下)** と**ユーザーへのエスカレーション**の 2 つだけ。人間の承認・同意を求めるダイアログでは、エスカレーションが唯一の経路である。
**`esc` は相手からは「人間が却下した」ようにしか見えない。** 相手の transcript には「ユーザーが回答を辞退した」と記録され、ツール結果の文言は「人間の指示を待て」で終わる。却下したのがあなたであることはどこにも現れず、相手はそのまま止まる。**却下したら、それが自分であることと次にやるべきことを、続けて伝えること。**
そもそも Claude Code の相手には、「ピアからの指示だけで見知らぬ行為を鵜呑みにすべきでない」として代理承認を拒否した実例がある。
## 罠: `blocked` のカバー範囲はエージェント種別に依存する
`blocked` の判定は UI 文字列のリテラルマッチである (claude では「最後の水平線より後ろに `esc to cancel` または `Enter to confirm · Esc to cancel` があるか」— [#2268](https://github.com/herdrdev/herdr/issues/2268))。**マニフェストはエージェント種別ごとに別**なので、Claude Code の `AskUserQuestion` はヒットする。一方 Codex の plan 承認メニューはヒットせず `idle` / `done` として上がる、という報告がある。相手の kind が違えば、`blocked` が何を拾うかも変わる。
**この検出漏れは、`agent prompt` の `agent_blocked` ガードの穴でもある。** herdr が `blocked` と認識できない相手には、そのガードも効かない。**そこでは誤爆がそのまま起きる。**
状態検出が疑わしいときの一次診断はこれ。評価された全ルールと、不一致の理由まで出る。
```bash
herdr agent explain <target> --verbose
```
## 罠: ツール呼び出しがテキストとしてリークし、何も実行されないまま `idle` になる
Opus 4.8 以降のモデルに共通する既知の不具合として、エージェントが組み立てたツール呼び出しがツール実行に進まず、そのままユーザー向けメッセージとして出力されてしまうことがある。エージェント自身はツールを呼び出したつもりでターンを終えるが、実際には何も実行されていない。起動直後の 1 往復目に限らず、作業が進んだ後の任意のターンでも起こりうる。
**症状**: `herdr agent read <target>` で読んだ内容が、ツール名・パラメータ名・タグの断片を含む不自然なテキストになっており、対応する実行結果 (Bash の出力、Read で取得したファイル内容など) が伴わないまま `agent_status` が `idle` になっている。
**危険性**:
- 監視する側はこれを「相手が正常に作業している」と誤認しやすい。見過ごすと、以降のチェックをすり抜けたまま放置されうる
- この状態に陥った相手は自力で復旧しない。リークした文字列を自分自身への攻撃と誤認し、明後日の方向の対応を始めることがある
**対処**: 壊れた相手にはメッセージを送らない — 症状の再現とリーク文字列を読ませる機会を増やすだけで、状態は変わらない。かわりに次の手順でサルベージする。
1. 壊れた相手とは別に、読み取り専用のエージェントを立てる
2. そのエージェントに、壊れた相手がそれまでに書き出したファイル (成果物・handover 文書など) と `herdr agent read <target>` のペイン出力から、どこまで進んでいたかをサルベージさせる
3. サルベージした内容を渡して新しいペインでエージェントを立ち上げ、そこから作業を引き継がせる。壊れた相手はそのまま停止する
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!