Skip to content

Instantly share code, notes, and snippets.

@kuwa72
Last active August 12, 2026 05:48
Show Gist options
  • Select an option

  • Save kuwa72/f91563c47dd4bbe028db13b35d15efcb to your computer and use it in GitHub Desktop.

Select an option

Save kuwa72/f91563c47dd4bbe028db13b35d15efcb to your computer and use it in GitHub Desktop.
herdr (terminal multiplexer for AI agents) setup for Emacs users — ctrl+q prefix, no Alt bindings, blocked-agent jump (prefix+a), Claude Code tab-title sync hook

herdr セットアップ(Emacsユーザー向け)

herdr(AIコーディングエージェント用ターミナルマルチプレクサ)の個人設定一式。 Emacsキーバインド常用者向けに、prefixを ctrl+b から ctrl+q に変更し、Alt系バインドを排除した構成。

設計メモ

  • prefix = ctrl+q: Emacsの C-q(quoted-insert)はほぼ使わないため犠牲に。C-b/C-a/C-t/C-z などEmacs・シェルで実用のあるキーは回避
  • Alt系バインドなし: Alacrittyで alt_send_esc = true(Option = Meta)にしている前提のため、Alt直接バインドはEmacsと衝突する
  • 運用方針: ワークスペース=リポジトリ、タブ=1タスク1エージェント。状況把握は prefix+b のサイドバー
  • prompt_new_tab_name / prompt_new_workspace_name = true で作成時に必ず名前を付ける
  • 入力待ちだけを巡回する prefix+a: 多数のエージェントを並列で回すと「今どれが入力待ちか」を探すのが手間になる。標準の next_agent / previous_agent はサイドバー一覧を単純に上下移動するだけで ✔(idle/done)にも止まるため、agent_status = blocked のペインだけを拾うカスタムコマンド(focus-attention.sh)を割り当てている

キーバインド早見表

操作 キー
ペイン分割(右 / 下) prefix v / prefix -
ペイン移動 / 次ペイン / 直前ペイン prefix h/j/k/l / prefix o / prefix Tab
ペインを閉じる / ズーム / リサイズ prefix x / prefix z / prefix r
タブ新規 / 次・前 / 直接 / リネーム prefix t / prefix n・p / prefix 1..9 / prefix ,
WSピッカー / 上下移動 / 直接 / 新規 prefix w / prefix ↑↓ / prefix Shift+1..9 / prefix Shift+N
デタッチ / サイドバー / ヘルプ prefix d / prefix b / prefix ?
入力待ちエージェントへ移動(順 / 逆) prefix a / prefix Shift+A

セットアップ手順

1. herdr本体の設定

# herdr-config.toml を ~/.config/herdr/config.toml に配置(既存があればマージ)
herdr config check
herdr server reload-config   # サーバー稼働中ならこれで即反映

2. 公式エージェントスキル(Claude Code等がherdrを操作できるようになる)

mkdir -p ~/.claude/skills/herdr
curl -fsSL https://raw.githubusercontent.com/ogulcancelik/herdr/master/SKILL.md \
  -o ~/.claude/skills/herdr/SKILL.md

3. 公式Claude Code連携(herdrサーバー再起動後のセッション自動resume)

herdr integration install claude

4. タブ名自動同期フック(自作)

Claudeの応答終了ごとに、herdrのタブ名をClaudeのセッションタイトルへ同期する。 要 jq。手動リネーム(prefix+,)は次のStopで上書きされる点に注意。

mkdir -p ~/.claude/hooks
# herdr-tab-title.sh を ~/.claude/hooks/ に配置
chmod +x ~/.claude/hooks/herdr-tab-title.sh

~/.claude/settings.jsonhooks.Stop に追加(既存エントリとマージ):

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$HOME/.claude/hooks/herdr-tab-title.sh\"",
            "timeout": 10,
            "async": true
          }
        ]
      }
    ]
  }
}

5. 入力待ちエージェントへのジャンプ(自作)

prefix+a で「入力待ち(agent_status = blocked)のペイン」だけを巡回する。prefix+Shift+A は逆順。 該当ペインが無ければ何もしない。要 jq

mkdir -p ~/.config/herdr/scripts
# focus-attention.sh を ~/.config/herdr/scripts/ に配置
chmod +x ~/.config/herdr/scripts/focus-attention.sh

herdr-config.toml 内の [[keys.command]]command を自分の絶対パスに書き換える (/Users/<you>/... の部分)。command 文字列で ~ / $HOME が展開されるかは未確認のため絶対パス推奨。

agent_statusidle / working / blocked / done / unknown の5値(herdr agent wait --until の possible values で確認できる)。blocked が許可待ち・質問待ち。完了待ちの ✔ も拾いたい場合は command の末尾に引数で done を足す(例: focus-attention.sh blocked done)。

# 手動実行での動作確認
~/.config/herdr/scripts/focus-attention.sh          # 入力待ちがあればそこへフォーカス
herdr agent list | jq -r '.result.agents[] | "\(.pane_id) \(.agent_status)"'

戻し方

herdr config reset-keys              # キーバインド初期化(config.tomlはバックアップされる)
herdr integration uninstall claude   # 公式連携の解除
#!/usr/bin/env bash
# 入力待ち(agent_status=blocked)のエージェントペインだけを巡回してフォーカスする。
#
# focus-attention.sh [--prev] [状態...]
#
# --prev 逆方向に巡回する
# 状態... 対象の agent_status(既定: blocked)。例: focus-attention.sh blocked done
#
# 該当ペインが無ければ何もしない(フォーカスは動かさない)。
set -euo pipefail
readonly HERDR_BIN="${HERDR_BIN:-$HOME/.local/bin/herdr}"
direction="next"
if [[ "${1:-}" == "--prev" ]]; then
direction="prev"
shift
fi
states=("$@")
if [[ ${#states[@]} -eq 0 ]]; then
states=("blocked")
fi
states_json=$(printf '%s\n' "${states[@]}" | jq -R . | jq -s .)
target=$("$HERDR_BIN" agent list | jq -r \
--argjson states "$states_json" \
--arg direction "$direction" '
[.result.agents[] | select(.agent_status as $s | $states | index($s))] as $queue
| ($queue | length) as $len
| if $len == 0 then
empty
else
([$queue[] | .focused] | index(true)) as $cur
| (if $cur == null then
(if $direction == "prev" then $len - 1 else 0 end)
elif $direction == "prev" then
($cur - 1 + $len) % $len
else
($cur + 1) % $len
end) as $next
| $queue[$next].pane_id
end
')
if [[ -z "$target" ]]; then
exit 0
fi
exec "$HERDR_BIN" agent focus "$target"
[ui]
agent_panel_sort = "priority"
prompt_new_tab_name = true # タブ作成時に名前を聞く(タブ=1タスク運用)
prompt_new_workspace_name = true # ワークスペース作成時も同様
[keys]
# プレフィクス: ctrl+q(Emacsの C-q = quoted-insert はほぼ使わないため犠牲にする)
# C-b/C-a/C-t/C-z などEmacs・シェルで実際に使うキーは避けている
prefix = "ctrl+q"
# --- ペイン ---
split_vertical = "prefix+v" # 右に分割(縦の境界線)
split_horizontal = "prefix+minus" # 下に分割(横の境界線)
close_pane = "prefix+x"
focus_pane_left = "prefix+h"
focus_pane_down = "prefix+j"
focus_pane_up = "prefix+k"
focus_pane_right = "prefix+l"
cycle_pane_next = "prefix+o" # Emacs C-x o の感覚で次ペインへ
cycle_pane_previous = "prefix+shift+o"
last_pane = "prefix+tab" # 直前ペインとトグル
zoom = "prefix+z"
resize_mode = "prefix+r"
edit_scrollback = "prefix+e"
# --- タブ ---
new_tab = "prefix+t"
close_tab = "prefix+shift+x"
next_tab = "prefix+n" # Emacs C-n/C-p の感覚
previous_tab = "prefix+p"
switch_tab = "prefix+1..9"
rename_tab = "prefix+comma" # tmux の prefix+, と同じ
# --- ワークスペース ---
workspace_picker = "prefix+w"
new_workspace = "prefix+shift+n"
close_workspace = "prefix+shift+d"
previous_workspace = "prefix+up" # サイドバーの並びと同じ上下移動
next_workspace = "prefix+down"
switch_workspace = "prefix+shift+1..9"
rename_workspace = "prefix+shift+w"
# --- セッション / UI ---
detach = "prefix+d" # tmux の prefix+d と同じ
settings = "prefix+s"
toggle_sidebar = "prefix+b"
reload_config = "prefix+shift+r"
help = "prefix+?"
# --- 使わないものは無効化 ---
open_notification_target = "" # o はペイン移動に譲る
new_worktree = ""
rename_pane = ""
# next_agent / previous_agent はサイドバー一覧を単純に上下移動するだけで、
# ✔(idle/done)のペインにも止まってしまうため使わない。
# 代わりに下のカスタムコマンドで blocked のみを巡回する。
# --- 入力待ちエージェントだけを巡回 ---
# agent_status = blocked(許可待ち・質問待ち)のペインのみを対象にフォーカス移動する。
# 該当なしなら何もしない。要 focus-attention.sh(同gist)+ jq。
# パスは絶対パスで書く(command 文字列での ~ / $HOME 展開は未確認)。
[[keys.command]]
key = "prefix+a"
type = "shell"
command = "/Users/<you>/.config/herdr/scripts/focus-attention.sh"
description = "入力待ちのエージェントへ移動"
[[keys.command]]
key = "prefix+shift+a"
type = "shell"
command = "/Users/<you>/.config/herdr/scripts/focus-attention.sh --prev"
description = "入力待ちのエージェントへ移動(逆順)"
#!/bin/bash
# Claude Code Stop hook: herdr のタブ名を Claude のセッションタイトルに同期する。
# herdr ペイン外では何もしない。手動リネームしたタブも次の Stop で上書きされる点に注意。
set -u
[ "${HERDR_ENV:-}" = 1 ] || exit 0
[ -n "${HERDR_TAB_ID:-}" ] || exit 0
command -v herdr >/dev/null 2>&1 || exit 0
title=$(herdr pane current --current 2>/dev/null | jq -r '.result.pane.terminal_title_stripped // empty')
# タイトルが未生成(汎用名やパス表示)のうちは触らない
case "$title" in
"" | "Claude Code" | "~"* | "/"*) exit 0 ;;
esac
herdr tab rename "$HERDR_TAB_ID" "$title" >/dev/null 2>&1 || true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment