【AI 開発】crit・hunk・herdr が良さげな話【CLI】

今回は AI 駆動開発で僕が使っているレビューツール crit と hunk の比較、そして tmux の代わりに気になっている herdr の話をします。AI エージェントと並走する開発スタイルだと、ツール選びも変わってきます。

こんにちは。ダタク @iQeeeda です。

AI エージェントと並走する開発スタイルになってから、ターミナルまわりのツールをガラッと見直しています。

結論: レビューは hunk、エージェント管理は herdr

先に結論です。

  • diff レビュー: hunk(crit から乗り換え)
  • 複数エージェントの管理: herdr(気になっていて、これから試す)

今回は、crit と hunk については使ってみた所感を、herdr については気になっている理由を紹介します。
それでは解説していきます。

AI 駆動開発では、人間の仕事はレビューになる

前提の話です。
いまの僕の開発は、AI エージェントがコードを書いて、僕がレビューするスタイルです。
いえ、レビューすら AI に任せることが多いです。

仮に駆け出しエンジニアを雇った場合の 1/20 以下の費用で、AI を雇える時代です。

コードを書く仕事は、どんどん AI に寄っていきます。
すると人間側のボトルネックは、diff を読んで判断することに移ります。

つまりレビュー体験の良し悪しが、そのまま開発速度に直結するようになりました。

crit とは

crit でできること

crit は、コードレビューツールです。

  • ローカルの diff に、インラインコメントを付けられる
  • レビュー結果をブラウザで確認できる
  • GitHub の PR に sync できる

参考) crit 公式サイト / GitHub

僕の使い方: ペルソナレビュー

僕は 3 つのペルソナで、AI にレビューさせています。

  • セキュリティ
  • パフォーマンス
  • 設計

この指摘を、crit のインラインコメントとして流し込みます。

ひとり開発でも多視点レビューが回せる。
AI 時代ならではです。

実際に使っている crit-personas skill の全文を貼っておきます。コピペ OK です。

---
name: crit-personas
description: 変更内容をセキュリティ・パフォーマンス・設計の3ペルソナで並行レビューし、候補を検証・整理した上でペルソナ名を author にして crit へコメント投稿、ローカルのレビュー URL を提示する(外部 crit.md への共有は禁止)。コードレビューを crit 上で多視点に行いたいときに使用。
argument-hint: "[crit に渡すレビュー対象(省略時は現在ブランチの変更)]"
---

# crit 3ペルソナレビュー

変更内容を **セキュリティ / パフォーマンス / 設計** の3つのペルソナで並行レビューし、候補を検証・整理した上でそれぞれの視点から `crit comment` でコメントを投稿する。全コメント投稿後、ローカルのレビュー URL を提示する。**外部 crit.md への `crit share` は禁止**(コードを外部に出さない)。

各ペルソナのコメントは `--author` で区別する:

| ペルソナ | author | 観点 |
|---|---|---|
| セキュリティレビュアー | `Security Reviewer` | 認証・認可・インジェクション・データ漏洩 |
| パフォーマンスレビュアー | `Performance Reviewer` | N+1 クエリ・キャッシュ・計算量 |
| 設計レビュアー | `Architecture Reviewer` | 責務分離・命名・拡張性 |

## 実行手順

### 1. レビュー対象を設定して crit daemon を起動

`$ARGUMENTS` を crit にそのまま渡す。引数があればそれが対象(ファイル / ディレクトリ / `--pr 42` / `--range base..head` など)、なければ現在ブランチの変更が対象になる。

```bash
crit $ARGUMENTS    # 引数なしなら `crit` だけ実行 → 現在ブランチの変更が対象
```

この最初の実行で対象が設定され daemon が起動する。続けて対象と差分を把握する:

```bash
crit status        # レビュー対象ファイル・差分・review ファイルパスを確認
```

対象ファイルの該当箇所は Read で実体を確認すること。**crit のコメント行番号はディスク上ファイルの 1-indexed 行**(diff 行番号ではない)なので、Read で正しい行を取る。

> crit が見つからない場合は `brew install crit` を案内する。git リポジトリでないディレクトリでは引数なし `crit` は使えない(対象を引数で明示する)。

### 2. 3ペルソナを並行サブエージェントで分析(この段階では投稿しない)

1 メッセージで 3 つの Task を**並行起動**する。各エージェントには対象の差分・ファイルパスを渡し、**コメント候補を JSON 配列で返すだけ**にする(crit コマンドはサブエージェントに実行させない)。

各エージェントへのプロンプトに含める指示:
- 担当ペルソナと観点(上表)に絞ってレビューすること
- 行番号は **Read で確認したディスク上ファイルの 1-indexed 行**で返すこと
- 返却は次のスキーマの JSON 配列のみ(説明文を付けない):

```json
[
  {"file": "<相対パス>", "line": 42, "body": "<行への指摘>"},
  {"file": "<相対パス>", "line": "50-55", "body": "<範囲への指摘>"},
  {"scope": "review", "body": "<この観点の総評>"}
]
```

ペルソナごとの Task:
1. **Security Reviewer** — 認証・認可・インジェクション・データ漏洩の観点で指摘
2. **Performance Reviewer** — N+1 クエリ・キャッシュ・計算量の観点で指摘
3. **Architecture Reviewer** — 責務分離・命名・拡張性の観点で指摘

### 3. 候補を検証・整理する(投稿前の必須ステップ)

サブエージェントの候補を**そのまま投稿しない**。オーケストレーター(あなた)が curate する:

- **行番号を Read で実体確認**: ペルソナは存在しない行番号を返すことがある(例: 26 行しかないファイルに `line: 73`)。各候補の `file:line` を Read で開き、指摘内容と実際の行が一致するか確認し、ズレていれば正す。
- **事実誤り・矛盾を破棄**: コードを読んで誤りの候補(「○○が無い」と言うが実在する等)や、検証済みの事実・他ペルソナと矛盾する助言は捨てる(例: 既に正しくエスケープしている `{{ }}` に対し `{!! !!}` 化を勧める指摘)。
- **重複を統合**: 同じ箇所・同じ機序を指す候補は最も具体的な 1 件にまとめる。
- 精度優先。「投稿すれば人が実際にアクションする」候補だけを残す。

### 4. author を付与して一括投稿

3 ペルソナの(検証後の)配列の各エントリに、対応する `"author"` を付与してから 1 つの配列にマージする:

- Security Reviewer の全エントリ → `"author": "Security Reviewer"`
- Performance Reviewer の全エントリ → `"author": "Performance Reviewer"`
- Architecture Reviewer の全エントリ → `"author": "Architecture Reviewer"`

マージした配列を `crit comment --json` で一括投稿する(`--author` はエントリに author が無い場合のフォールバック):

```bash
echo '[
  {"file": "src/auth.go", "line": 42, "body": "...", "author": "Security Reviewer"},
  {"file": "src/repo.go", "line": "50-55", "body": "...", "author": "Performance Reviewer"},
  {"scope": "review", "body": "...", "author": "Architecture Reviewer"}
]' | crit comment --json --author 'Claude Code'
```

注意:
- JSON 各エントリの `author` でペルソナが区別される。1 回の `--json` 呼び出しで 3 ペルソナ分をまとめて投稿でき、daemon への書き込み競合も起きない。
- **JSON のクォート崩れに注意**: ヒアドキュメントで渡すときは**シングルクォート区切り(`<<'JSON'`)**を使い、`body` 内に**ダブルクォートを入れない**(JSON が壊れる。`id="x"` などはバッククォートや `id=x` で回避)。`?? ''` / `{{ }}` / `</textarea>` 等の特殊文字はシングルクォート区切りなら literal で安全に通る。
- 本文に長文・複数段落が含まれる場合は JSON をファイルに書き出して `crit comment --json --file <path> --author 'Claude Code'` を使う。ただし**plan モード中はファイルを書けない**ので、その場合はヒアドキュメント(`cat <<'JSON' | crit comment --json ...`)で stdin 投入する。
- 行コメントは `"file"` + `"line"`、観点全体の総評は `"scope": "review"`、ファイル全体への指摘は `"path"` のみ(`line` なし)。`line` は範囲を文字列 `"50-55"` でも渡せる。

### 5. ローカル レビュー URL を提示する

- **レビュー依頼の前に必ずページ内容を最新化する(毎回・必須)**。plan セッションの表示内容(`~/.crit/plans/<slug>/current.md`)は ExitPlanMode 時のスナップショットで、その後のプランファイル修正は**自動反映されない**。コメント対応等でプランを修正したら、ユーザーにレビューを依頼する前に毎回:
  1. `diff <プランファイル> ~/.crit/plans/<slug>/current.md` で差分を確認する
  2. 差分があれば旧版を退避(`cp current.md vNNN.md.bak`)してから `cp <プランファイル> ~/.crit/plans/<slug>/current.md` で同期する(daemon はライブリロードなのでコピーだけで反映される)
  3. ユーザーには**「リロードしてください」**と添えて URL を提示する
  古い内容のままレビュー依頼するのは厳禁(ユーザーが古いプランをレビューしてしまう)。コードレビュー対象(ディスク上のファイル)は編集が直接反映されるためこの同期は不要だが、リロードの案内は同様に添える。
- **提示する前に必ず “いま生きているポート” を確認する**。手順 1 で daemon 起動メッセージ(`Started crit daemon at http://localhost:<port>`)が出ればその値を使う。出ない=**既存 daemon に接続した**場合は、`crit status` の `Daemon: running (PID …, port <port>)` 行から取得する。**過去メッセージに出たポートを記憶で使い回さない**(kill/再起動で番号が変わる)。確信が持てなければ `lsof -nP -iTCP -sTCP:LISTEN | grep crit` で実際に LISTEN しているポートを確認する。確定した `http://localhost:<port>` を**そのまま**提示して終える(ツール出力を掘り返させない)。
- **`crit share` は使わない(禁止)**。`crit share` は外部サービス(crit.md)へコード本体を *アップロード* し、外部に公開される(キャッシュ/インデックスされ得る)。本スキルでは外部共有しない。レビューはローカル URL で完結させる。

### 6. 後日ユーザーが「対応」「resolve」を求めたとき(重要)

投稿後、ユーザーが crit の Web UI 上でコメントに**返信**して指示を書くことがある。**resolve する前に必ず全コメントの返信を読み、ユーザー指示を先に反映する**。返信を読まずに一括 resolve するのは厳禁(=ユーザーの指示を握り潰す事故になる)。

- **返信の確認**: `crit comments --all --json` を読み、各コメントの `replies` を走査して author がユーザー(Claude 以外)の返信を拾う。返信の指示に従って**コードを対応してから** resolve する。
  - 例: 「対応しておいて」=実際に修正する(TODO 先送りにしない)。「TODO コメント付けておいて」=コメントのみ。指示が分かれるので1件ずつ読む。
- **resolve の手順**: `crit comment --json` で `{"reply_to": "<id>", "resolve": true, "author": "Claude Code", "body": "<対応内容>"}` を渡す(行コメントは `file` フィールドでファイル指定して曖昧さ回避)。`--resolve` はユーザーが明示依頼したときのみ。
- **CLI のハマりどころ(事故多発)**:
  - **`crit comment --help` を実行しない**。help が出ず `--help` を body と解釈して「--help」というコメントを投稿してしまう。使い方は `crit:crit-cli` スキル、または `crit --help`(トップレベル)で確認する。
  - 未知サブコマンド(例 `crit resolve`)は新ポートで daemon を起動しようとする。`resolve` 単体コマンドは無い。
  - **単一コメントを消す CLI は無い**(`crit comment --clear` は全削除)。誤爆コメント等を1件だけ消すには review.json(パスは `crit status` の `Review file`)を**バックアップの上で直接編集**して該当エントリを除去する。daemon はライブリロードするので、直接編集後に CLI mutation を挟まなければ反映される。
  - 未解決が0件のとき `crit comments --json` は `[]` ではなく `null` を返す。

## トラブルシューティング

### A. 古いポート / 別対象の URL を提示してしまう

crit は**ライブリロード対応**(プラン/レビュー内容の変更はブラウザに即時反映される)。また `crit` は**既に起動済みの daemon があるとそこへ接続する**。だから本来、**daemon を 1 つ生かしたまま**にすれば、対象や内容が変わっても**ユーザーはタブを更新(or 自動リロード)するだけ**で最新化でき、新しい URL を出し直す必要はない。

問題が起きるのは **daemon を `kill` して再起動したとき**。crit の既定ポートは**ランダム**なので、再起動のたびにポート番号が変わり、開きっぱなしのタブが**死んだポート**を指してしまう(リロードしても接続拒否)。

- **原則 daemon を kill しない・新しいタブを開かない**。一度 crit を起動してユーザーがタブを開いたら、**同じセッションを使い回す**。`crit` を何度も起動し直してブラウザタブを増やさないこと(ライブリロードできるので不要)。対象を変えたいときは**同じ daemon に対して再実行**して retarget するが、その際は **`--no-open`**(ブラウザを自動で開かない)を付け、`crit <files...> --no-open` のようにする。retarget 後は `crit status` で **Review file が意図した対象**(コードレビューなら `~/.crit/reviews/<hash>/review.json`、plan なら `~/.crit/plans/<slug>/...`)になっているか確認し、ユーザーには**「(既存タブを)リロードしてください」**と伝える。
- **どうしても再起動が必要なら URL を固定する**: `CRIT_PORT=<port> crit ...` または `crit -p <port> ...` で**ポートを固定**すれば、再起動後も同じ URL のタブがリロードでつながる。片付けは `kill` ではなく **`crit stop --all`** を使う。
- **提示するポートは必ず実値で確認**: 起動メッセージか `crit status` の `Daemon: running (PID …, port <port>)` 行から取得し、過去メッセージの値を記憶で使い回さない。複数 daemon が疑わしいときだけ `ps aux | grep '[c]rit'` / `lsof -nP -iTCP -sTCP:LISTEN | grep crit` で確認する。

### B. plan モードで ExitPlanMode が通らない / Approve ボタンが出ない / internal error

crit は ExitPlanMode に**plan レビューのゲート hook**を挿す。未解決の plan コメントや**スタックした/壊れた plan セッション**があると、ゲートがブロックするだけでなく **internal error を返して承認 UI(Approve ボタン)自体が出ない**ことがある。

診断と対処:

1. `ls ~/.crit/plans/` で plan セッション一覧を見る。日付スラッグが複数あるなら、**今回のセッションのもの**(最新日付、`current.md`/`v001.md` が今の計画内容)を特定する。
2. 各 `<slug>/.crit/review.json` の未解決コメントを確認(`crit comments --plan <slug> --json`、または review.json を直接読む)。**`.crit/review.json` が存在しない** plan セッションがゲートの参照先だと hook が落ちて internal error になり得る。
3. 未解決コメントには `crit comment --plan <slug> --reply-to <id> --author 'Claude Code' '<対応方針>'` で**返信**する(`--resolve` は付けない=レビュアー判断)。
4. **返信だけではゲートは開かない**。最終的に**人間が crit UI で「Finish Review」/コメントを resolve すること**でゲートが解除される。`Approve ボタンが無い`と言われたら、同じ ExitPlanMode を機械的に再試行せず、上記の状態(どの slug の未解決コメントが残っているか)をユーザーに伝え、UI 側での解決(または明示的な続行指示)を仰ぐ。
5. それでも internal error が続く場合は、古い/壊れた plan セッションが原因のことが多い。ユーザーに状況を共有し、該当 plan の crit レビューを開き直してもらう(or 明示的に「このまま進めて」の指示をもらう)。勝手に plan セッションを削除しない。

【惜しい点】ブラウザの sync が不安定

ただ、ブラウザでコメントやボタンが sync されないことがたまにあります。

※ ペルソナレビューを大量に流し込んでいるからかもしれません

レビュー中に「あれ、コメント反映されてない?」となると、地味に集中が切れるんですよね。

crit より hunk のほうが良さげ

hunk とは

そこで最近は hunk を使っています。
hunk は、TUI の diff レビューツールです。

参考) hunk 公式サイト / GitHub

hunk に乗り換えて感じたメリット

  • CLI ですべて完結する(ここが決定的)
  • インラインコメントも付けられる
  • ペルソナレビューの運用も、そのまま移行できた
  • ブラウザとの往復がなくなり、レビューの腰が軽くなった

hunk 版のペルソナレビュー skill はこちら。

---
name: hunk-personas
description: 変更内容をセキュリティ・パフォーマンス・設計の3ペルソナで並行レビューし、候補を検証・整理した上でペルソナ名を author にして live な Hunk セッションへインラインコメントを一括投稿する。Hunk(TUI)上で多視点コードレビューを行いたいときに使用。
argument-hint: "[hunk レビューコマンド(例: diff main...feature / show HEAD~1)。省略時は現セッションの表示内容が対象]"
---

# Hunk 3ペルソナレビュー

live な Hunk セッションの変更内容を **セキュリティ / パフォーマンス / 設計** の3つのペルソナで並行レビューし、候補を検証・整理した上でそれぞれの視点から `hunk session comment apply` でインラインコメントを一括投稿する。投稿後、ペルソナごとの総評をチャットで報告する。

Hunk は対話的な TUI。**`hunk diff` / `hunk show` 等の対話コマンドは絶対に自分で実行しない**(ユーザーの端末用)。操作は `hunk session *` CLI のみで行う。

各ペルソナのコメントは JSON の `author` フィールドで区別する:

| ペルソナ | author | 観点 |
|---|---|---|
| セキュリティレビュアー | `Security Reviewer` | 認証・認可・インジェクション・データ漏洩 |
| パフォーマンスレビュアー | `Performance Reviewer` | N+1 クエリ・キャッシュ・計算量 |
| 設計レビュアー | `Architecture Reviewer` | 責務分離・命名・拡張性 |

## 実行手順

### 1. live セッションを特定し、対象を設定する

```bash
hunk session list          # live セッションを確認
```

- セッションが無い("No active Hunk sessions")→ ユーザーに端末で Hunk を起動してもらう(例: 対象リポジトリで `hunk diff`)。Hunk が見えているのにこのエラーが出る場合は sandbox が localhost をブロックしている可能性があるので、権限昇格して再試行する。`hunk` コマンド自体が無ければ `brew install hunk` を案内する。
- 複数セッションが同一 repo にある("Multiple active sessions match")→ `<session-id>` を明示して選ぶ。以降のコマンドは `--repo <repoRoot>` か `<session-id>` でセッションを指定する。

`$ARGUMENTS` があればそれを Hunk レビューコマンド(`diff ...` / `show ...`)としてセッションに reload する。**`--` を必ず挟む**:

```bash
hunk session reload --repo . -- $ARGUMENTS   # 例: -- diff main...feature / -- show HEAD~1
```

引数が無ければ reload せず、**セッションが現在表示している内容**をそのまま対象にする。

続けて構造を把握する:

```bash
hunk session review --repo . --json                  # file/hunk 構造(まずはこれ)
hunk session review --repo . --include-patch --json  # 生 diff が本当に必要なファイルだけ
```

- 各ファイルの `hunks[].newRange` / `oldRange` は **1-based・両端含む**行範囲。ここが後の投稿可否を決める(範囲外の行にはコメントできない)。
- working-tree レビューなら new 側の行番号=ディスク上ファイルの 1-indexed 行。対象箇所の実体は Read で確認すること。

### 2. 3ペルソナを並行サブエージェントで分析(この段階では投稿しない)

1 メッセージで 3 つの Task を**並行起動**する。各エージェントには対象の差分・ファイルパス・hunk 範囲を渡し、**コメント候補を JSON 配列で返すだけ**にする(hunk コマンドはサブエージェントに実行させない)。

各エージェントへのプロンプトに含める指示:
- 担当ペルソナと観点(上表)に絞ってレビューすること
- 行番号は **Read で確認したディスク上ファイルの 1-indexed 行**(new 側)で返すこと。削除行への指摘だけ `"side": "old"` を付けて old 側の行番号で返す
- `summary` は 1 文の短い指摘、`rationale` は必要なときだけ詳細(省略可)
- 返却は次のスキーマの JSON 配列のみ(説明文を付けない):

```json
[
  {"file": "<相対パス>", "line": 42, "summary": "<短い指摘>", "rationale": "<詳細(任意)>"},
  {"file": "<相対パス>", "line": 88, "side": "old", "summary": "<削除行への指摘>"},
  {"overall": "<この観点の総評>"}
]
```

ペルソナごとの Task:
1. **Security Reviewer** — 認証・認可・インジェクション・データ漏洩の観点で指摘
2. **Performance Reviewer** — N+1 クエリ・キャッシュ・計算量の観点で指摘
3. **Architecture Reviewer** — 責務分離・命名・拡張性の観点で指摘

> crit と違い hunk には review 全体へのスコープコメントが無い。`overall`(総評)は投稿せず、手順 5 でチャット報告に使う。行範囲コメント(`"50-55"`)も無いので、範囲への指摘は最も代表的な 1 行を選ばせる。

### 3. 候補を検証・整理する(投稿前の必須ステップ)

サブエージェントの候補を**そのまま投稿しない**。オーケストレーター(あなた)が curate する:

- **行番号を Read で実体確認**: ペルソナは存在しない行番号を返すことがある。各候補の `file:line` を Read で開き、指摘内容と実際の行が一致するか確認し、ズレていれば正す。
- **hunk 範囲内かを必ず確認**: 手順 1 の `review --json` の `newRange` / `oldRange` に**入っていない行は投稿できない**。しかも `comment apply` のバッチは**アトミック**——1 件でも範囲外だと `No new diff hunk in <file> covers line <n>` で**全件却下**される。範囲外の候補は範囲内の代表行に付け替えるか破棄する。
- **事実誤り・矛盾を破棄**: コードを読んで誤りの候補(「○○が無い」と言うが実在する等)や、検証済みの事実・他ペルソナと矛盾する助言は捨てる。
- **重複を統合**: 同じ箇所・同じ機序を指す候補は最も具体的な 1 件にまとめる。
- 精度優先。「投稿すれば人が実際にアクションする」候補だけを残す。

### 4. author を付与して一括投稿

検証後の候補を hunk の `comment apply` ペイロードに変換する。各エントリに対応するペルソナの `author` を付与し、`line`/`side` を `newLine` または `oldLine` に写す:

```bash
cat <<'JSON' | hunk session comment apply --repo . --stdin --focus --json
{
  "comments": [
    {"filePath": "src/auth.go", "newLine": 42, "summary": "...", "rationale": "...", "author": "Security Reviewer"},
    {"filePath": "src/repo.go", "newLine": 55, "summary": "...", "author": "Performance Reviewer"},
    {"filePath": "src/old.go", "oldLine": 30, "summary": "...", "author": "Architecture Reviewer"}
  ]
}
JSON
```

注意:
- 各エントリは `filePath` + `summary` + `newLine`/`oldLine` の**どちらか片方**が必須。`rationale` は任意(TUI では summary と空行区切りで連結表示される)。
- 3 ペルソナ分を **1 回の `--stdin` バッチ**で投稿する。バッチは全件検証後に反映されるので、成功すれば取りこぼしは無い。
- **JSON のクォート崩れに注意**: ヒアドキュメントは**シングルクォート区切り(`<<'JSON'`)**を使い、`summary`/`rationale` 内に**ダブルクォートを入れない**(JSON が壊れる。`id="x"` などはバッククォートや `id=x` で回避)。
- `--focus` でユーザーの TUI 表示が先頭コメントへジャンプする。結果 JSON の `applied[].commentId` は後で個別削除に使うので控えておく。

### 5. 結果を報告する

- ユーザーには Hunk の TUI 上でコメントが見える状態になっていることを伝える(`--focus` 済み。以降のコメント間移動は TUI 操作、または `hunk session navigate --repo . --next-comment` で誘導できる)。
- 各ペルソナの `overall`(総評)と投稿件数・破棄件数をチャットでまとめて報告する。crit のような Web URL は無い——**報告先はチャットと TUI 内コメント**。

### 6. 後日ユーザーが「対応」「削除」を求めたとき

- **ユーザーの手書きノートを先に読む**: ユーザーが TUI 上でインラインノートを残していることがある。`hunk session comment list --repo . --type user --json` で拾い、指示に従って**コードを対応してから**整理する。返信・resolve 機構は無いので、対応済みコメントの整理は削除で行う。
- **個別削除の罠(事故多発)**: `comment rm` は `--repo` 指定でも**引数 1 個だと `[sessionId]` に食われて** `missing required argument 'commentId'` になる。**sessionId と commentId を両方**渡す:

  ```bash
  hunk session comment rm <sessionId> <commentId>
  ```

  sessionId は `hunk session list`、commentId は投稿時の `applied[].commentId` か `comment list --json` の `noteId`。
- `comment clear --yes` は**全削除**(`--file` で絞れる)。ユーザーが明示依頼したときのみ使う。

## トラブルシューティング

- **"No visible diff file matches ..."** — そのファイルは現在ロード中のレビューに無い。`review --json` で対象を確認し、必要なら `reload` する。
- **"No new diff hunk in \<file\> covers line \<n\>"** — 行が hunk 範囲外(バッチ全体が却下されている)。手順 3 の範囲チェックに戻る。
- **"No active Hunk sessions"** — Hunk が起動していれば sandbox の localhost ブロックを疑い権限昇格して再試行。起動していなければユーザーに起動を依頼する。
- **"Multiple active sessions match"** — `<session-id>` を明示する。
- **"Pass the replacement Hunk command after `--`"** — `reload` の入れ子コマンド前の `--` が抜けている。
- **untracked ファイルが混ざる** — `hunk diff` は既定で untracked を含む。tracked のみにするなら `hunk session reload --repo . -- diff --exclude-untracked`。

diff ビューアとしても優秀

レビュー用途に限らず、diff をちゃんと見たい人には hunk がいい気がします。
git diff を目 grep するのに限界を感じている人は、一度触ってみてほしいです。

tmux が AI エージェント時代に厳しくなった

tmux は長年の相棒だった

ここからは、ターミナル自体の話です。
僕はブログで解説記事を書くくらいには、tmux を使い込んできました。

AI エージェントのステータスが見えない

でも AI エージェントを複数走らせるようになって、問題にぶつかりました。
tmux や zellij では、各エージェントのステータスが掴めないのです。

複数のエージェントを走らせていると、知りたいのはこれです。

  • どれが working か
  • どれが blocked か
  • どれが idle か

これが一目で見えないと厳しい。
ペインを巡回して目視確認するのは、さすがに 2026 年のやり方ではないなと。

herdr が気になっている

herdr とは

そこで気になっているのが herdr です。

  • キャッチコピーは "one terminal. whole herd."
  • エージェントの working / blocked / idle が見える
  • cmux みたいな UI のまま実現できるらしい

参考) herdr 公式サイト / GitHub

これかもしれない。

ターミナルエミュレータも見直し中

herdr に乗り換えるなら、ターミナル自体もまた Ghostty に戻そうかなと考え中です。

AI エージェント時代のツールは、移り変わりが激しい。
半年後には全部入れ替わってる気もします。

また知見が溜まったら書きます。

関連記事

まだコメントはありません