[{"data":1,"prerenderedAt":537},["ShallowReactive",2],{"post-index":3,"post-ghostty-herdr-dev-env":453},{"posts":4,"categories":402,"tags":411},[5,17,35,43,60,74,87,105,122,144,156,167,179,193,208,223,239,250,264,275,285,296,308,319,331,343,356,367,377,387],{"slug":6,"title":7,"description":8,"publishedAt":9,"updatedAt":9,"category":10,"tags":13,"thumbnail":16},"ai-cognitive-debt-approval"," 認知負債は「承認」で生まれる ── コーディングエージェント時代の意図負債と、個人・チームの向き合い方","コーディングエージェントに実装を任せると、コードは速く書けるのに人の理解が追いつかない。認知負債・意図負債・理解負債の違いを「下り」と「上り」で整理し、負債が生まれる承認の瞬間と、個人とチームでできる対策、まだ答えのない問いを、自分の体験から考える。","2026-11-03T17:12:07.686Z",{"name":11,"slug":12},"AI","ai",[14],{"name":15,"slug":15},"organization",null,{"slug":18,"title":19,"description":20,"publishedAt":21,"updatedAt":21,"category":22,"tags":23,"thumbnail":16},"design-harness-personal-product","デザインハーネスを個人開発で組んだ — AI が作る画面のずれを止めるまで","デザイナーのいない個人開発で、AI が作る画面のずれを止めるまでの記録。Codex の Product Design で画像の案を出して画面を作り直し、デザインファイルとコードの食い違いを正本の分担で片付け、lint・見た目の比較・AI の評価役からなるデザインハーネスで外れたら止める仕組みを組んだ。","2026-11-03T15:39:02.665Z",{"name":11,"slug":12},[24,27,30,32],{"name":25,"slug":26},"claude code","claude-code",{"name":28,"slug":29},"design system","design-system",{"name":31,"slug":31},"codex",{"name":33,"slug":34},"design harnes","design-harnes",{"slug":36,"title":37,"description":38,"publishedAt":39,"updatedAt":39,"category":40,"tags":41,"thumbnail":16},"claude-code-mods-intro","Claude Codeの「Claude Mods」とは？ 入れてみた3つのmodと、安全に入れる手順","Claude Codeの新機能Claude Mods（v2.1.287〜）を紹介する。hooks・skills・MCPとの違い、入れてみたmod 3つ（prompt-rail・md-prompt・qa-guide）の使い方、claude plugin validateで中身を確かめて入れる手順をまとめた。","2026-11-03T15:30:44.678Z",{"name":11,"slug":12},[42],{"name":25,"slug":26},{"slug":44,"title":45,"description":46,"publishedAt":47,"updatedAt":47,"category":48,"tags":51,"thumbnail":16},"worktree-shared-reverse-proxy","AI 時代の並列開発の環境構築 — git worktree ごとにアプリを同時に動かす","git worktree の並列開発で、各 worktree のフロントとバックを同時に動かす Docker Compose 構成を紹介する。ポートはずらさず共有のリバースプロキシでホスト名に振り分け、DB は 1 つを共有ネットワークに置いて全 worktree から参照する。","2026-11-03T15:24:32.067Z",{"name":49,"slug":50},"Dev Env","dev-env",[52,54,57],{"name":53,"slug":53},"git",{"name":55,"slug":56},"Docker","docker",{"name":58,"slug":59},"開発環境","development-environment",{"slug":61,"title":62,"description":63,"publishedAt":64,"updatedAt":64,"category":65,"tags":66,"thumbnail":16},"ghostty-herdr-dev-env","Ghostty + herdr で組む開発環境（2026年9月版） — AI エージェントを並べてターミナルで開発する","WezTerm + tmux + 自作ツールから Ghostty + herdr に移した私の開発環境を紹介する。Claude Code・Codex・takt を並べて動かす 1 タスクの流れ、ターミナル内ブラウザで画面の要素を AI に渡す方法、Neovim・lazygit・hunk・Nix まで層ごとにまとめた。","2026-11-03T15:14:47.700Z",{"name":49,"slug":50},[67,68,70,72],{"name":58,"slug":59},{"name":69,"slug":69},"herdr",{"name":71,"slug":71},"ghostty",{"name":73,"slug":73},"terminal",{"slug":75,"title":76,"description":77,"publishedAt":78,"updatedAt":78,"category":79,"tags":80,"thumbnail":16},"dotfiles-operation-and-nix","設定ファイルを端末に置いたままにしない — dotfiles 運用のすすめと、その先の Nix","設定ファイルを Git リポジトリで管理する dotfiles 運用の始め方と、その先で効いてくる Nix の話。何を入れて何を入れないか、配線の 3 手法の比較、運用して見えてくる穴、3 端末を 1 つの設定で回すところまでを実例で書く。","2026-11-03T15:04:48.084Z",{"name":49,"slug":50},[81,82,85],{"name":58,"slug":59},{"name":83,"slug":84},"Nix","nix",{"name":86,"slug":86},"dotfiles",{"slug":88,"title":89,"description":90,"publishedAt":91,"updatedAt":91,"category":92,"tags":93,"thumbnail":102},"opencode-go-plan-evaluation","OpenCode Go プランを評価する — 月$10 で LLM オーケストレーションの中間層は作れるか","OpenCode が提供する月額固定の Go プラン（初月$5、翌月以降$10\u002F月）を、料金体系・想定ユースケース・3層 LLM 構成における中間モデル層としての適合性まで含めて評価する。","2026-05-07T12:12:31.936Z",{"name":11,"slug":12},[94,97,100],{"name":95,"slug":96},"Harness Engineering","harness-engineering",{"name":98,"slug":99},"LLM","llm",{"name":101,"slug":101},"opencode",{"url":103,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F6Nh8tVuSCuHunaVeqyegdU\u002F0fee3536b9ee406b986430ebc1b8ebfd\u002FOpenCode_Go_%C3%A3__%C3%A3__%C3%A3__%C3%A3__%C3%A3__%C3%A8__%C3%A4__%C3%A3__%C3%A3__.png","",{"slug":106,"title":107,"description":108,"publishedAt":109,"updatedAt":109,"category":110,"tags":111,"thumbnail":120},"prompt-context-harness-engineering","ハーネスエンジニアリングとは何か：プロンプト→コンテキスト→ハーネスへ至るAIエージェント設計の変遷","「ハーネスエンジニアリング」とは何か。プロンプトエンジニアリング、コンテキストエンジニアリングから続く3段階の変遷を、論文引用（Lost in the Middle \u002F SWE-bench）とClaude Codeの実装例（フック・ルール・Skill）で階層構造として整理する。","2026-04-07T13:04:49.564Z",{"name":11,"slug":12},[112,115,116,119],{"name":113,"slug":114},"Prompt Engineering","prompt-engineering",{"name":95,"slug":96},{"name":117,"slug":118},"Context Engineering","context-engineering",{"name":98,"slug":99},{"url":121,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F74HnVGS2R8wphJ1nGHgLfb\u002Fb87d3d6e35ccc518e04d9959c7637a88\u002Fã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã_ªã__ã__ã__ã__ã__ä__ã__ï__ã__ã__ã__ã__ã__ã__ã__â__ã__ã__ã__ã__ã__ã__â__ã__ã__ã__ã__ã__è__ã__A.png",{"slug":123,"title":124,"description":125,"publishedAt":126,"updatedAt":126,"category":127,"tags":130,"thumbnail":142},"authjs-v5-jwt-dual-timeout-bff-django","Auth.js v5 でJWT二重タイムアウトを実装する：BFF + Django連携の設計パターン","Auth.js v5のjwt callbackで8時間の絶対有効期限と30分のアイドルタイムアウトを両立する実装方法を解説。Next.js MiddlewareによるBFF API保護とDjango REST Frameworkとの Token Exchange パターンも紹介する。","2026-04-06T12:45:28.328Z",{"name":128,"slug":129},"Programming","programming",[131,134,136,139],{"name":132,"slug":133},"auth.js","auth-js",{"name":135,"slug":135},"jwt",{"name":137,"slug":138},"Django REST Framework","django-rest-framework",{"name":140,"slug":141},"Next.js","next-js",{"url":143,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002FpqkFfHKpf2UqoNrB6KrKS\u002F672a78076f28d88b31509c230f9c3f64\u002FAuth.js_v5_ã__ã__JWTäº_é__ã__ã__ã__ã__ã__ã__ã__å__è__ã__ã__ï__BFF___Djangoé__æ_ºã__è__è__ã__ã__ã__ã__ã__.png",{"slug":145,"title":146,"description":147,"publishedAt":148,"updatedAt":148,"category":149,"tags":150,"thumbnail":154},"claude-code-spec-to-growing-claudemd","仕様書を「渡す」からCLAUDE.mdを「育てる」へ — Claude Codeの使い方が変わった話","Claude Codeに仕様書を丸ごと渡す運用から、CLAUDE.mdを継続的に育てる運用へ。「間違えたら追加」ルールの実践例と、20行→146行+31スキルに育てた記録。","2026-04-02T14:58:11.375Z",{"name":11,"slug":12},[151,152,153],{"name":25,"slug":26},{"name":113,"slug":114},{"name":117,"slug":118},{"url":155,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002FqybhQ2TQSYQhIvDhWxqvs\u002F9f8b888e11a76223c8a1b1da42df5ce1\u002Fä__æ__æ__ã__ã__æ__ã__ã__ã__ã__CLAUDE.mdã__ã__è__ã__ã__ã__ã___â___Claude_Codeã__ä__ã__æ__ã__ã__å__ã__ã__ã__è__.png",{"slug":157,"title":158,"description":159,"publishedAt":160,"updatedAt":160,"category":161,"tags":162,"thumbnail":165},"claude-code-harness-engineering","Claude Codeを覚醒させる「ハーネスエンジニアリング」 CLAUDE.md・Hooks・Rules設定の徹底解説","プロンプトを書く時代から、AIが最高に働く環境を設計する時代へ。Claude CodeのCLAUDE.md、Hooks、Rules、Settings、Agent Routingを体系的に解説し、自作のオーケストレーションシステム「ai-orchestra」による統合管理の実践例を紹介する。","2026-03-22T08:59:48.575Z",{"name":11,"slug":12},[163,164],{"name":25,"slug":26},{"name":95,"slug":96},{"url":166,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F3liirUgzBlFBuAMoytyN5E\u002F66ba6b07385791bcaae4ddf404f06ce1\u002FClaude_Codeã__è__é__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã_ªã__ã__ã__ã___CLAUDE.mdã__Hooksã__Rulesè__å__ã__å__åº_è__èª_.png",{"slug":168,"title":169,"description":170,"publishedAt":171,"updatedAt":172,"category":173,"tags":174,"thumbnail":177},"claude-code-dev-toolchain","Claude Code開発を支える私のツールチェイン — ターミナルからAIデザインまで","Claude Code CLIを中心とした開発環境を紹介する。WezTerm + Tmuxのターミナル構成、GTRやBatonによる並列開発、ステータスライン・通知フックのカスタマイズ、MCP\u002Fプラグイン活用、Aqua VoiceやPencilとの連携まで、実際に使っているツールチェインの全体像をまとめた。","2026-03-21T19:30:43.616Z","2026-11-03T15:18:14.982Z",{"name":49,"slug":50},[175,176],{"name":25,"slug":26},{"name":58,"slug":59},{"url":178,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F4wFUBAqC9yuIgeo3xWVHJM\u002F8843248b854fee93872b5ac519d16bc2\u002FClaude_Codeé__ç_ºã__æ__ã__ã__ç__ã__ã__ã__ã__ã__ã__ã__ã___â___ã__ã__ã__ã__ã__ã__ã__AIã__ã__ã_µã__ã__ã__ã__ã__ã__.png",{"slug":180,"title":181,"description":182,"publishedAt":183,"updatedAt":184,"category":185,"tags":186,"thumbnail":191},"lazygit-commit-message-auto-generate","【コピペで導入】lazygit × Claude Code でコミットメッセージ自動生成","lazygit の customCommands と Claude Code の --print モードを組み合わせ、Ctrl+G 一発で Conventional Commits 形式のコミットメッセージを自動生成する方法を解説。コピペ可能な完成形設定と、4段階の試行錯誤で得たハマりポイントを共有します。","2026-03-15T04:36:20.532Z","2026-11-03T15:18:53.496Z",{"name":49,"slug":50},[187,188,189],{"name":53,"slug":53},{"name":25,"slug":26},{"name":190,"slug":190},"lazygit",{"url":192,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F62ov1mzeLUjRm6cbzQ7R92\u002F3bc21a7fe7ec517ad3258b6264d4097e\u002Fã__ã__ã__ã__ã__ã__ã__ã__å__å__ã__lazygit_Ã__Claude_Code_ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__ã__è_ªå__ç__æ__.png",{"slug":194,"title":195,"description":196,"publishedAt":197,"updatedAt":198,"category":199,"tags":200,"thumbnail":206},"git-worktree-runner-guide","git-worktree-runner で worktree 管理が劇的にラクになった話","git-worktree-runner（GTR）は git worktree の操作を 1 コマンドに集約する CLI ラッパーです。Taskfile.yaml での運用から GTR に移行した体験を元に、インストール・設定・AI 並列開発での活用法を解説します。","2026-03-09T15:32:31.316Z","2026-11-03T15:18:33.924Z",{"name":49,"slug":50},[201,202,204],{"name":53,"slug":53},{"name":203,"slug":203},"git-worktree",{"name":205,"slug":205},"git-worktree-runner",{"url":207,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F7BRBfHFocF2ABOeOQmtIic\u002Fa63ce99493098bc42123e4315f43d768\u002Fgit-worktree-runner_ã__ã___worktree_ç__ç__ã__ã__å__ç__ã__ã__ã__ã__ã_ªã__ã__è__.png",{"slug":209,"title":210,"description":211,"publishedAt":212,"updatedAt":212,"category":213,"tags":214,"thumbnail":221},"rag-basic-knowledge","RAG入門 — 検索拡張生成の基礎知識を実験結果とともに学ぶ","RAG（検索拡張生成）の仕組みをVectorDB・Embedding・チャンク分割の3要素に分解して解説。Embeddingモデル変更で正答率0\u002F5→4\u002F5に改善した検証データも公開。","2026-03-01T11:29:25.841Z",{"name":11,"slug":12},[215,218,219],{"name":216,"slug":217},"RAG","rag",{"name":98,"slug":99},{"name":220,"slug":220},"ollama",{"url":222,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F1enfpUixTuvis0oX9x5Cfa\u002F934aed76ac994412ceb37dfdf5dc6f6c\u002FRAGå__é___â___æ__ç__æ__å_µç__æ__ã__å_ºç__ç__è__ã__å__é__çµ_æ__ã__ã__ã__ã__å__ã_µã__.png",{"slug":224,"title":225,"description":226,"publishedAt":227,"updatedAt":228,"category":229,"tags":230,"thumbnail":237},"engineer-ai-daily-workflow","1人のエンジニアがAIを日常にどう組み込んでいるか — 契約サービスから活用フローまで全公開","Claude Code、ChatGPT、Gemini、Aqua Voice、Adobe Fireflyの5サービスを使い分けるエンジニアが、開発・情報収集・ブレスト・音声入力・振り返りまで、AIを日常に組み込んだリアルな活用フローを全公開します。","2026-02-18T14:13:58.531Z","2026-02-18T14:14:12.514Z",{"name":11,"slug":12},[231,232,234],{"name":98,"slug":99},{"name":233,"slug":233},"openclaw",{"name":235,"slug":236},"マルチエージェント","multi-agent",{"url":238,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F5gBC06O8WX2GX8wmoOXQfy\u002F27a11e0f280f642a781e462dead9d3ae\u002F1äººã__ã__ã__ã__ã__ã__ã__ã__ã__AIã__æ__å__ã__ã__ã__ã__çµ_ã__è__ã__ã__ã__ã__ã__ã___â___å__ç__ã_µã__ã__ã__ã__ã__ã__æ__ç__ã__ã_.png",{"slug":240,"title":241,"description":242,"publishedAt":243,"updatedAt":243,"category":244,"tags":245,"thumbnail":248},"ai-orchestra-design-and-practice","Claude Codeマルチエージェント実践｜AI Orchestraで超えた2つの壁","Claude Code単体運用で生じるコンテキスト溢れ・役割混乱の課題を、25種の専門エージェントとClaude×Codex×Geminiのマルチモデル連携で解決するオーケストレーションシステム「AI Orchestra」。その設計思想、Hookによる自動ルーティング、並列レビューなどの実装を具体的に紹介します。","2026-02-08T08:01:16.212Z",{"name":11,"slug":12},[246,247],{"name":235,"slug":236},{"name":98,"slug":99},{"url":249,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F6j2KWOOo7wJfUobTCg3o2w\u002F126c8d413cd9a56e64fba107544ec4e1\u002FClaude_Codeã__ã__ã__ã__ã__ã__ã__ã__ã__ã__å__è_µï__AI_Orchestraã__ã__è__ã__ã__2ã__ã__å__.png",{"slug":251,"title":252,"description":253,"publishedAt":254,"updatedAt":255,"category":256,"tags":257,"thumbnail":262},"ai-benchmark-guide","AIベンチマーク読み方ガイド｜SWE-bench・GPQA・ARC-AGIの意味と活用法","SWE-bench、GPQA Diamond、ARC-AGI、Terminal-Benchなど主要AIベンチマークの読み方を解説。2026年2月最新のモデルスコア比較と、コーディングエージェントへのタスク振り分けに活かす実践的な指針を紹介します。","2026-02-07T16:10:19.131Z","2026-02-07T16:11:56.095Z",{"name":11,"slug":12},[258,259],{"name":98,"slug":99},{"name":260,"slug":261},"Benchmark","benchmark",{"url":263,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F3QlfPsXmLogdj9o4mdgFYQ\u002F73a69ca272ac4e4fdcf977f322c0218a\u002FAIã__ã__ã__ã__ã__ã__ã__èª_ã__æ__ã__ã__ã__ã__ã__ï__SWE-benchã__GPQAã__ARC-AGIã__æ__å__ã__æ__ç__æ__.png",{"slug":265,"title":266,"description":267,"publishedAt":268,"updatedAt":268,"category":269,"tags":270,"thumbnail":273},"multi-agent-building-guide","マルチエージェント構築入門｜構成の全体像と3つの実装アプローチ","マルチエージェントの構築方法を解説。オーケストレーター・サブエージェント・ツール連携の3要素から、自作・フレームワーク・既存ツール活用の選択肢まで。Claude Codeでの実装例付き。","2026-02-05T12:52:58.095Z",{"name":11,"slug":12},[271,272],{"name":98,"slug":99},{"name":235,"slug":236},{"url":274,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F68XZFvLA17pegNy0lHCrYN\u002Ff90202a483bf087f4fa4cbb80dae934e\u002Fã__ã__ã__ã__ã__ã__ã__ã__ã__ã__æ__ç__å__é__ï__æ__æ__ã__å__ä__å__ã__3ã__ã__å__è__ã__ã__ã__ã__ã__ã__.png",{"slug":276,"title":277,"description":278,"publishedAt":279,"updatedAt":279,"category":280,"tags":281,"thumbnail":283},"openclaw-security-and-features","OpenClaw徹底解説 ── セルフホスト型AIアシスタントの可能性とセキュリティリスク","「AIが自分の代わりにメッセージを返信してくれたら…」そんな願いを叶えるツールが、いま爆発的な人気を集めています。その名も「OpenClaw」。わずか2ヶ月でGitHub Stars 10万を突破し、週間200万人が訪れるほどの注目を浴びています。  しかし、その急成長の裏には商標問題、詐欺騒動、そして深刻なセキュリティ脆弱性の発覚と、波乱万丈なドラマがありました。","2026-02-03T15:20:26.415Z",{"name":11,"slug":12},[282],{"name":233,"slug":233},{"url":284,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F7aKouVOZSGnzVUGgLQfa22\u002F5688eb515dc5f0b2c301b9b8c267ec20\u002F00036.png",{"slug":286,"title":287,"description":104,"publishedAt":288,"updatedAt":289,"category":290,"tags":291,"thumbnail":294},"custom-instructions","ChatGPTやClaudeがもっと賢くなる！カスタム指示の書き方と実例集","2026-01-30T17:42:57.415Z","2026-02-03T15:03:06.461Z",{"name":11,"slug":12},[292,293],{"name":98,"slug":99},{"name":113,"slug":114},{"url":295,"description":287},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F4EojonTOebJGeiaXf98ol0\u002F9e391fc8bd6e548f8c96136c805b49d7\u002FChatGPTã__Claudeã__ã__ã__ã__ã__è__ã__ã_ªã__ï__ã__ã__ã__ã__æ__ç_ºã__æ__ã__æ__ã__å__ä__é__.png",{"slug":297,"title":298,"description":299,"publishedAt":300,"updatedAt":301,"category":302,"tags":303,"thumbnail":306},"ollama-local-llm-setup","ローカルLLMはまず小さめモデルから：Ollamaで始める導入〜疎通確認","acでOllamaを使い、ローカルLLMを最短で起動→1回応答まで確認する手順を解説。モデル選定の考え方、遅い\u002Fメモリ\u002Fディスクの切り分け、API疎通(curl)もまとめます。","2026-01-18T06:40:49.270Z","2026-01-21T13:05:14.924Z",{"name":11,"slug":12},[304,305],{"name":220,"slug":220},{"name":98,"slug":99},{"url":307,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F1NQmtspOD1S6LEb4SrCYIQ\u002F49c213de131a9a4ea139c32e805f3b01\u002Fã__ã__ã__ã__LLMã__ã__ã__ã__å__ã__ã__ã__ã__ã__ã__ã__ã__ï__Ollamaã__ã__å__ã__ã__å__å__ã__ç__é__ç_ºèª_.png",{"slug":309,"title":310,"description":104,"publishedAt":311,"updatedAt":312,"category":313,"tags":314,"thumbnail":317},"llm-leaderboard-score-guide","LLMリーダーボードの読み方：スコア指針とベンチマーク確認手順","2026-01-10T08:57:26.636Z","2026-01-18T06:55:58.990Z",{"name":11,"slug":12},[315,316],{"name":260,"slug":261},{"name":98,"slug":99},{"url":318,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F8u7GQ3mAlcvIHOc5bFJc6\u002Fa953bf74c33117efa393eaf8541f515a\u002FLLMã_ªã__ã__ã__ã__ã__ã__ã__ã__ã__ã__èª_ã__æ__.png",{"slug":320,"title":321,"description":104,"publishedAt":322,"updatedAt":322,"category":323,"tags":324,"thumbnail":329},"vite_docker_esbuild-error","Vite + Docker + ESBuild Errorの解決","2021-11-12T03:53:22.965Z",{"name":128,"slug":129},[325,326],{"name":55,"slug":56},{"name":327,"slug":328},"Vite","vite",{"url":330,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F5gqsl4ZChCI3uaSXQA86du\u002F3c94f9928ffaaab2d8911d32e742de1e\u002Fprogramming.jpg",{"slug":332,"title":333,"description":104,"publishedAt":334,"updatedAt":335,"category":336,"tags":337,"thumbnail":341},"nuxt-router-scroll-control","Nuxt.jsのページ遷移時のスクロール制御したい","2021-10-28T14:31:11.276Z","2021-10-28T14:35:33.155Z",{"name":128,"slug":129},[338],{"name":339,"slug":340},"Nuxt.js","nuxt-js",{"url":342,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F6dqpNPZsBJJ7x9XJj1Ld1z\u002Fcd1bb9323a8ffb0657ad79525403e1ff\u002Fnuxt.jpg",{"slug":344,"title":345,"description":104,"publishedAt":346,"updatedAt":347,"category":348,"tags":349,"thumbnail":354},"react-drf-img_uploader-backend","React × DRFで画像アップロード機能作成 (バックエンド実装編)","2021-10-26T02:56:58.215Z","2021-10-27T11:37:43.829Z",{"name":128,"slug":129},[350,353],{"name":351,"slug":352},"React","react",{"name":137,"slug":138},{"url":355,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F4jbVtK0nXsMKZplpBAwhri\u002Fb0ccef5153d92a7947eb0c682008255c\u002Fdjango-rest-framework.jpg",{"slug":357,"title":358,"description":104,"publishedAt":359,"updatedAt":360,"category":361,"tags":362,"thumbnail":365},"react-drf-img_uploader-frontend","React × DRFで画像アップロード機能作成 (フロント実装編)","2021-10-26T02:39:01.629Z","2021-10-27T11:37:24.670Z",{"name":128,"slug":129},[363,364],{"name":351,"slug":352},{"name":137,"slug":138},{"url":366,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F3uFOs5NyHOvRqYgE1lQ3p6\u002Fd79c8fabb7d4151c5773ffe1cdd2bce3\u002Freact.jpg",{"slug":368,"title":369,"description":104,"publishedAt":370,"updatedAt":371,"category":372,"tags":373,"thumbnail":376},"react-drf-img_uploader-environment","React × DRFで画像アップロード機能作成 (環境構築編)","2021-10-26T02:00:01.702Z","2021-10-27T11:47:28.398Z",{"name":128,"slug":129},[374,375],{"name":351,"slug":352},{"name":137,"slug":138},{"url":330,"description":104},{"slug":378,"title":379,"description":104,"publishedAt":380,"updatedAt":381,"category":382,"tags":383,"thumbnail":385},"docker-install-procedure","各OS毎のDockerインストール手順","2021-10-26T01:43:54.692Z","2022-02-07T14:32:07.791Z",{"name":128,"slug":129},[384],{"name":55,"slug":56},{"url":386,"description":104},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F3aVlE8NIfX12QvTafaC8xE\u002Fd00bf480e212538e1816fc10d2e7b77d\u002Fdocker.jpg",{"slug":388,"title":389,"description":104,"publishedAt":390,"updatedAt":391,"category":392,"tags":395,"thumbnail":399},"notion-clear-trash","Notionのゴミ箱を一括削除する","2021-09-12T13:04:59.853Z","2021-10-21T14:29:03.528Z",{"name":393,"slug":394},"Lifestyle","lifestyle",[396],{"name":397,"slug":398},"Notion","notion",{"url":400,"description":401},"https:\u002F\u002Fimages.ctfassets.net\u002Fd3b1looh8iwg\u002F5binM4YxsZdSXX9SKkGyNP\u002Fcf39353211db8b3e0c4ac18e03b55527\u002Fnotion.jpg","Notion記事用のサムネイル",[403,405,407,409],{"name":49,"slug":50,"count":404},6,{"name":11,"slug":12,"count":406},16,{"name":128,"slug":129,"count":408},7,{"name":393,"slug":394,"count":410},1,[412,414,415,417,418,420,421,422,423,424,425,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450],{"name":98,"slug":99,"count":413},10,{"name":25,"slug":26,"count":404},{"name":137,"slug":138,"count":416},4,{"name":58,"slug":59,"count":416},{"name":55,"slug":56,"count":419},3,{"name":53,"slug":53,"count":419},{"name":95,"slug":96,"count":419},{"name":113,"slug":114,"count":419},{"name":351,"slug":352,"count":419},{"name":235,"slug":236,"count":419},{"name":260,"slug":261,"count":426},2,{"name":117,"slug":118,"count":426},{"name":220,"slug":220,"count":426},{"name":233,"slug":233,"count":426},{"name":132,"slug":133,"count":410},{"name":31,"slug":31,"count":410},{"name":33,"slug":34,"count":410},{"name":28,"slug":29,"count":410},{"name":86,"slug":86,"count":410},{"name":71,"slug":71,"count":410},{"name":203,"slug":203,"count":410},{"name":205,"slug":205,"count":410},{"name":69,"slug":69,"count":410},{"name":135,"slug":135,"count":410},{"name":190,"slug":190,"count":410},{"name":140,"slug":141,"count":410},{"name":83,"slug":84,"count":410},{"name":397,"slug":398,"count":410},{"name":339,"slug":340,"count":410},{"name":101,"slug":101,"count":410},{"name":15,"slug":15,"count":410},{"name":216,"slug":217,"count":410},{"name":73,"slug":73,"count":410},{"name":327,"slug":328,"count":410},{"name":451,"slug":451,"count":452},"takt",0,{"slug":61,"title":62,"description":63,"publishedAt":64,"updatedAt":64,"category":454,"tags":455,"thumbnail":16,"html":460,"headings":461,"readingMinutes":505,"older":506,"newer":512,"related":518},{"name":49,"slug":50},[456,457,458,459],{"name":58,"slug":59},{"name":69,"slug":69},{"name":71,"slug":71},{"name":73,"slug":73},"\u003Ch1 id=\"ghostty-+-herdr-で組む開発環境（2026年9月版）\" tabindex=\"-1\">Ghostty + herdr で組む開発環境（2026年9月版）\u003C\u002Fh1>\n\u003Cp>半年前、\u003Ca href=\"\u002Fblog\u002Fclaude-code-dev-toolchain\">Claude Code 開発を支える私のツールチェイン\u003C\u002Fa> という記事で WezTerm + tmux + 自作ツール Baton の構成を紹介した。あれから中身がだいぶ入れ替わったので、現時点の開発環境をまとめ直す。\u003C\u002Fp>\n\u003Cp>入れ替えたのはターミナルエミュレーター・マルチプレクサ・AI セッション管理の 3 つで、エディタやバージョン管理まわりはほぼそのままだ。この記事ではまず「今どういう構成で、どう開発しているか」を書き、そのあとに「なぜこの形になったか」を短く添える。想定している読者は、ターミナル中心で開発したい人と、Claude Code を複数並べて動かしている人だ。\u003C\u002Fp>\n\u003Ch2 id=\"結論から\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">01\u003C\u002Fspan>結論から\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>常用の構成は \u003Cstrong>Ghostty（ターミナルエミュレーター）+ herdr（ターミナルマルチプレクサ）\u003C\u002Fstrong> にした。WezTerm + tmux + Baton は捨てずに、戻るための退路として残している\u003C\u002Fli>\n\u003Cli>herdr を選んだ決め手は、tmux 時代にできなかった「Neovim での画像表示」と「ターミナル内ブラウザで画面の要素を選んで AI に渡すこと」ができるようになったことだ。承認待ちの検知や使い心地は、Baton とほとんど変わらない\u003C\u002Fli>\n\u003Cli>Ghostty に移ったのは、そのターミナル内ブラウザが WezTerm では重くて使い物にならず、Ghostty では普通に動いたから\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>全体の構成を 1 枚にするとこうなる。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002Fc1f421414ce9-20260924.png\" alt=\"開発環境のレイヤー構成図。下から基盤（Nix、dotfiles）、OS 操作（AeroSpace、Alfred、Karabiner、Loupedeck）、ターミナルエミュレーター（Ghostty）、マルチプレクサ（herdr とプラグイン）が積み重なり、最上段に AI エージェント（Claude Code、Codex、takt、OpenCode、Antigravity）と開発ツール（Neovim、lazygit、hunk、gtr、terminal-browser）が並ぶ\" loading=\"lazy\">\u003C\u002Fp>\n\u003Ch2 id=\"半年前から変わったところ\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">02\u003C\u002Fspan>半年前から変わったところ\u003C\u002Fh2>\n\u003Cp>変わったのは下の 3 層だけで、そのほかは据え置きだ。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002Fabfa8a9d41bf-20260924.png\" alt=\"2026年3月と9月の構成比較図。ターミナルエミュレーターが WezTerm から Ghostty に、マルチプレクサが tmux から herdr に、AI セッション管理が自作の Baton から herdr のサイドバーに変わった。Neovim、lazygit、gtr、Nix、Alfred は変わっていない\" loading=\"lazy\">\u003C\u002Fp>\n\u003Cdiv class=\"tbl\" tabindex=\"0\" role=\"region\" aria-label=\"Table\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>層\u003C\u002Fth>\n\u003Cth>2026年3月\u003C\u002Fth>\n\u003Cth>2026年9月\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>ターミナルエミュレーター\u003C\u002Ftd>\n\u003Ctd>WezTerm\u003C\u002Ftd>\n\u003Ctd>Ghostty（WezTerm は退路として残す）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>マルチプレクサ\u003C\u002Ftd>\n\u003Ctd>tmux\u003C\u002Ftd>\n\u003Ctd>herdr\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>AI セッション管理\u003C\u002Ftd>\n\u003Ctd>Baton（自作の Go 製 TUI）\u003C\u002Ftd>\n\u003Ctd>herdr のサイドバー + 自作スクリプト（Baton は休止）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>ブラウザ連携\u003C\u002Ftd>\n\u003Ctd>なし\u003C\u002Ftd>\n\u003Ctd>terminal-browser（ターミナル内の Chromium）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Neovim の画像表示\u003C\u002Ftd>\n\u003Ctd>tmux の中では実用にならない\u003C\u002Ftd>\n\u003Ctd>使える\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>エディタ \u002F Git \u002F worktree\u003C\u002Ftd>\n\u003Ctd>Neovim \u002F lazygit \u002F gtr\u003C\u002Ftd>\n\u003Ctd>変わらず（hunk を試用中）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>環境管理\u003C\u002Ftd>\n\u003Ctd>dotfiles\u003C\u002Ftd>\n\u003Ctd>dotfiles + Nix（nix-darwin + home-manager）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Nix 化は 8 月の話で、経緯は \u003Ca href=\"\u002Fblog\u002Fdotfiles-operation-and-nix\">dotfiles 運用のすすめと、その先の Nix\u003C\u002Fa> に書いた。この記事の範囲は 9 月の入れ替えである。\u003C\u002Fp>\n\u003Ch2 id=\"ghostty-+-herdr-でどう開発しているか-—-1-タスクの流れ\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">03\u003C\u002Fspan>Ghostty + herdr でどう開発しているか — 1 タスクの流れ\u003C\u002Fh2>\n\u003Cp>道具の一覧より先に、1 つのタスクをどう進めているかを書く。私の場合、常時 10 本前後のエージェントを並べて動かしている。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002F4efad4a78f60-20260924.png\" alt=\"1 タスクの開発フロー図。1 プロジェクトを開く、2 worktree を切る、3 分割してエージェントを起動、4 状態を見て承認、5 ブラウザで確認して要素を渡す（Web 開発のときのみ）、6 差分を読む、7 コミット。4 から 6 は繰り返す\" loading=\"lazy\">\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>プロジェクトを開く。\u003C\u002Fstrong> Ghostty を起動すると自動で herdr にアタッチし、前回の作業がそのまま残っている。新しく始めるときは \u003Ccode>prefix+f\u003C\u002Fcode> で ghq 管理下のリポジトリを fzf で選び、herdr のワークスペースとして開く。Alfred から開くこともある\u003C\u002Fli>\n\u003Cli>\u003Cstrong>worktree を切る。\u003C\u002Fstrong> 並列で進めるタスクごとに \u003Ccode>wt\u003C\u002Fcode>（gtr のラッパー）で worktree を作り、同じピッカーから開く\u003C\u002Fli>\n\u003Cli>\u003Cstrong>分割してエージェントを起動する。\u003C\u002Fstrong> \u003Ccode>prefix+2\u003C\u002Fcode> 〜 \u003Ccode>prefix+8\u003C\u002Fcode> で N 分割し、\u003Ccode>prefix+0\u003C\u002Fcode> でペイン数に応じて Neovim・Claude Code・Codex を起動する。全ペインで Claude Code を一斉に立ち上げたいときは、Loupedeck（物理ボタンの左手デバイス）の 1 ボタンで済ませる\u003C\u002Fli>\n\u003Cli>\u003Cstrong>状態を見て承認する。\u003C\u002Fstrong> 各ペインが working \u002F blocked \u002F idle のどれかを、herdr がサイドバーに出す。承認待ちが出たら \u003Ccode>prefix+b\u003C\u002Fcode> の承認コンソールで \u003Ccode>a\u003C\u002Fcode>（承認）か \u003Ccode>d\u003C\u002Fcode>（拒否）を押すか、通知をクリックしてそのペインへ飛ぶ\u003C\u002Fli>\n\u003Cli>\u003Cstrong>（Web アプリのとき）ブラウザで確認して、要素ごと直させる。\u003C\u002Fstrong> \u003Ccode>tb\u003C\u002Fcode> で localhost を隣のペインに開き、気になる要素を \u003Ccode>Ctrl+G\u003C\u002Fcode> で選ぶ。選んだ要素の情報がエージェントの入力欄に入るので、そのあとに「ここの余白を詰めて」と書いて送る\u003C\u002Fli>\n\u003Cli>\u003Cstrong>差分を読む。\u003C\u002Fstrong> エージェントが書いた変更は hunk でまとめて読む。気になるところは Neovim で開いて直接確認する\u003C\u002Fli>\n\u003Cli>\u003Cstrong>コミットする。\u003C\u002Fstrong> 基本はエージェントに commit スキルを実行させ、変更内容からコミットを作らせる。手で直したファイルは \u003Ccode>prefix+g\u003C\u002Fcode> で開く lazygit でステージし、\u003Ccode>Ctrl+G\u003C\u002Fcode> で Antigravity にコミットメッセージを作らせてそのままコミットする\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002F122881ea4d52-20260924.png\" alt=\"herdr の画面。左のサイドバーにワークスペースと、blocked・done・working・idle の状態付きのエージェント一覧が並ぶ。右側は 4 分割で、Claude Code、Codex、Antigravity、OpenCode が動いており、Antigravity のペインはコマンド実行の承認待ちになっている\" loading=\"lazy\">\u003C\u002Fp>\n\u003Cp>4〜6 を何周も回すのが日常だ。5 は Web アプリを作っているときだけの手順で、それ以外の開発ではターミナル内ブラウザは使わない。\u003C\u002Fp>\n\u003Cp>Web アプリの開発でいちばん変わったのは、その 5 である。以前は、ブラウザ（Dia）用に自作した拡張で要素の情報を拾い、ターミナルに戻って AI に渡していた。今はブラウザを切り替えず、\u003Ccode>Ctrl+G\u003C\u002Fcode> で要素を指すだけで済む。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002F93a89ae187f0-20260924.png\" alt=\"terminal-browser で Ghostty の公式ドキュメントを開き、Ctrl+G の要素ピッカーで見出しの div を選んでいるところ。選択中の要素が枠で囲まれ、要素名のラベルが出ている\" loading=\"lazy\">\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002F7915fe1021f8-20260924.png\" alt=\"要素を選んだ直後の画面。左のペインの Claude Code の入力欄に、選んだ div の HTML の抜粋と CSS セレクタが 1 行で入っている\" loading=\"lazy\">\u003C\u002Fp>\n\u003Cp>※ 開発中のプロダクトは見せられないので、画面はサンプルとして Ghostty の公式ドキュメントを開いている。普段は localhost で動かしている手元のアプリに対して同じ操作をする。\u003C\u002Fp>\n\u003Ch2 id=\"レイヤー別のツール紹介\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">04\u003C\u002Fspan>レイヤー別のツール紹介\u003C\u002Fh2>\n\u003Cp>ここからは図 1 の層ごとに、使っているものを紹介する。\u003C\u002Fp>\n\u003Ch3 id=\"ターミナルエミュレーター:-ghostty\" tabindex=\"-1\">ターミナルエミュレーター: Ghostty\u003C\u002Fh3>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fghostty.org\" target=\"_blank\" rel=\"noopener noreferrer\">Ghostty\u003C\u002Fa> は Zig 製の、GPU で描画するターミナルエミュレーターだ。公式ドキュメントに「Zero Configuration Philosophy」という節があり、設定なしでもほとんどの人がそのまま使えることを目標にしている（\u003Ca href=\"https:\u002F\u002Fghostty.org\u002Fdocs\u002Fconfig\" target=\"_blank\" rel=\"noopener noreferrer\">Ghostty Configuration\u003C\u002Fa>）。\u003C\u002Fp>\n\u003Cp>私の設定は本体 55 行と herdr 用のキー設定 51 行で、合わせて 106 行だ。WezTerm のときは Lua で 7 ファイル 388 行あった。ただ、減った分の大半は Ghostty の手柄ではない。タブや分割の管理を herdr に移したので、ターミナルエミュレーター側の仕事がそもそも減った。\u003C\u002Fp>\n\u003Cp>Ghostty 側でやっていることは、ほぼ 1 つしかない。Cmd 系のキーを「herdr の prefix + キー」のバイト列に変換して送ることだ。Ghostty には Lua のようなスクリプトがないので、\u003Ccode>text:\u003C\u002Fcode> アクションでバイト列を直接書く。\u003C\u002Fp>\n\u003Cfigure class=\"code\" data-lang=\"ini\">\u003Cdiv class=\"code-bar\">\u003Cspan class=\"lang\">INI\u003C\u002Fspan>\u003Cspan>13 LINES\u003C\u002Fspan>\u003Cbutton class=\"copy\" type=\"button\" data-cursor=\"COPY\">COPY\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki site-code\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode class=\"language-ini\">\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># config\u002Fghostty\u002Fherdr.conf（抜粋）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># Cmd 系のキーを「herdr の prefix（Ctrl+Q = \\x11）+ キー」のバイト列で送る\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># Cmd+D でペインを縦に分割、Cmd+T で新規タブ、Cmd+W でペインを閉じる\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">keybind\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> cmd+\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">d=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">text:\\x11v\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">keybind\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> cmd+\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">t=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">text:\\x11c\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">keybind\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> cmd+\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">w=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">text:\\x11x\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># Cmd+1..9 を herdr のタブ切替（Alt+1..9）に回す。\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># Ghostty 既定の super+digit_N=goto_tab が先にマッチするので、先に外しておく\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">keybind\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> cmd+\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">digit_1=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">unbind\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># Alt+1 は ESC 前置ではなく CSI u 形式で送る（herdr が kitty keyboard protocol を使うため）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">keybind\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> =\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> cmd+\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">1=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">text:\\x1b[49\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-comment)\">;3u\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Ffigure>\n\u003Cp>ハマったのは Cmd+数字だ。\u003Ccode>cmd+1\u003C\u002Fcode> を上書きしても、Ghostty 既定の物理キー指定（\u003Ccode>super+digit_1\u003C\u002Fcode>）が先にマッチしてしまう。\u003Ccode>cmd+digit_N=unbind\u003C\u002Fcode> で既定を外してから割り当てる必要があった。Alt の送り方も、よく見る ESC 前置（\u003Ccode>\\x1b1\u003C\u002Fcode>）ではなく CSI u 形式（\u003Ccode>\\x1b[49;3u\u003C\u002Fcode>）にしている。herdr が外側のターミナルエミュレーターに kitty keyboard protocol を要求するためだ。\u003C\u002Fp>\n\u003Cp>見た目では、WezTerm で使っていた背景画像を引き継いだ。Ghostty には背景画像の明るさを下げる設定がないので、画像そのものを事前に暗く加工して敷いている。\u003C\u002Fp>\n\u003Ch3 id=\"マルチプレクサ:-herdr\" tabindex=\"-1\">マルチプレクサ: herdr\u003C\u002Fh3>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fherdrdev\u002Fherdr\" target=\"_blank\" rel=\"noopener noreferrer\">herdr\u003C\u002Fa> は AI エージェントを動かす前提で作られたターミナルマルチプレクサで、Rust 製の単一バイナリだ。tmux と同じ層にあり、tmux の代わりに使う。\u003C\u002Fp>\n\u003Cp>tmux から移って違いを感じたのは次の点である。\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>各ペインのエージェントの状態が見える。\u003C\u002Fstrong> Claude Code や Codex を自動で検出し、working \u002F blocked \u002F idle をサイドバーに出す\u003C\u002Fli>\n\u003Cli>\u003Cstrong>マウスも普通に使える。\u003C\u002Fstrong> README に「keyboard and mouse, both first-class」とあり、prefix キーとクリック・ドラッグのどちらでも操作できる\u003C\u002Fli>\n\u003Cli>\u003Cstrong>エージェントから操作できる。\u003C\u002Fstrong> CLI とソケット API があり、ペインの分割やキー送信をスクリプトから叩ける\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>キーバインドは tmux 時代のものをそのまま移植した。prefix も tmux と同じ \u003Ccode>Ctrl+Q\u003C\u002Fcode> にしている（herdr 既定の \u003Ccode>Ctrl+B\u003C\u002Fcode> は、Karabiner で左矢印に変換しているので届かない）。\u003C\u002Fp>\n\u003Cfigure class=\"code\" data-lang=\"toml\">\u003Cdiv class=\"code-bar\">\u003Cspan class=\"lang\">TOML\u003C\u002Fspan>\u003Cspan>12 LINES\u003C\u002Fspan>\u003Cbutton class=\"copy\" type=\"button\" data-cursor=\"COPY\">COPY\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki site-code\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode class=\"language-text\">\u003Cspan class=\"line\">\u003Cspan># config\u002Fherdr\u002Fconfig.toml（抜粋）\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[keys]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan># prefix は tmux 時代と同じ Ctrl+Q\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>prefix = \"ctrl+q\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan># lazygit をポップアップで開く\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>[[keys.command]]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>key = \"prefix+g\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>type = \"popup\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>command = \"zsh -ic 'lazygit'\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>width = \"80%\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan>height = \"80%\"\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Ffigure>\n\u003Cp>herdr 単体で足りない部分は、自作スクリプト 10 本で埋めた。主なものは、承認待ちのエージェントを一覧して \u003Ccode>a\u003C\u002Fcode> \u002F \u003Ccode>d\u003C\u002Fcode> で承認・拒否できる承認コンソール（Baton の TUI の代わり）、ghq のリポジトリピッカー、N 分割、ペイン数に応じたプロセスの一括起動である。スクリプトはすべて dotfiles の \u003Ccode>config\u002Fherdr\u002Fbin\u002F\u003C\u002Fcode> に置いている。\u003C\u002Fp>\n\u003Cp>プラグインはタブ名を自動で付ける \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fqu8n\u002Fherdr-automatic-rename\" target=\"_blank\" rel=\"noopener noreferrer\">herdr-automatic-rename\u003C\u002Fa> と、OS の通知バナーをクリックすると該当ペインへ飛べる \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdot\u002Fherdr-terminal-notifier\" target=\"_blank\" rel=\"noopener noreferrer\">herdr-terminal-notifier\u003C\u002Fa> の 2 つを入れている。プラグインは \u003Ccode>herdr plugin install\u003C\u002Fcode> で入れる仕組みなのでリポジトリで管理しにくい。そこで、使うプラグインと commit SHA を書いたリストを dotfiles に置き、Nix の switch のたびにそのリストへ揃えるようにした。導入前にはスクリプトと同梱アプリの中身を確認し、commit を固定している。\u003C\u002Fp>\n\u003Cp>細かいところでは、サイドバーのエージェント名を Claude はオレンジ、Codex は青緑というように色分けした。10 本並ぶと、色がないとどれが何か分からない。\u003C\u002Fp>\n\u003Ch3 id=\"ai-エージェント:-claude-code-\u002F-codex-\u002F-takt-\u002F-opencode-\u002F-antigravity\" tabindex=\"-1\">AI エージェント: Claude Code \u002F Codex \u002F takt \u002F OpenCode \u002F Antigravity\u003C\u002Fh3>\n\u003Cp>エージェントは Claude Code と Codex を主に使い、手順が決まった作業は nrslib さんの \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fnrslib\u002Ftakt\" target=\"_blank\" rel=\"noopener noreferrer\">takt\u003C\u002Fa> に流している。takt はステップごとにプロバイダを割り当てられるので、実装とテストは Codex、計画とレビューは Claude Code、AI 特有のアンチパターン検出だけは OpenCode、という分担にしている。\u003C\u002Fp>\n\u003Cp>承認まわりは半年で様子が変わった。Baton を作った当初は、Claude Code にも Codex にも、承認を自動で判定する仕組みがなかった。すべてを許可するモード（\u003Ccode>--dangerously-skip-permissions\u003C\u002Fcode>）で起動すれば承認は出なくなるが、それは怖い。そこで Baton に「safe auto mode」を実装した。決まったルールで \u003Ccode>rm\u003C\u002Fcode> や本番操作のような危険な操作を弾き、判断に迷うものだけ別の LLM に審査させる仕組みだ。その後 Claude Code に auto mode が入り、Claude Code にはあるのに Codex にはない時期も Baton で補っていた。今は Codex にも承認リクエストを自動でレビューする設定があり、どちらも組み込みの機能で足りるようになった。\u003C\u002Fp>\n\u003Cp>このほかに OpenCode と Antigravity（\u003Ccode>agy\u003C\u002Fcode>）も入れている。OpenCode は takt のレビュー工程の一部を担当し、Antigravity は調べものの委譲と、後述する lazygit のコミットメッセージ生成に使っている。herdr はどちらも検出してサイドバーに出すので、Claude Code や Codex と同じ一覧で状態を追える。\u003C\u002Fp>\n\u003Ch3 id=\"開発ツール\" tabindex=\"-1\">開発ツール\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>Neovim。\u003C\u002Fstrong> 全部入りのディストリビューションは使わず、プラグインマネージャーの lazy.nvim で 1 つずつ足してきた。今は 29 ファイルで、選んだ理由は ADR としてリポジトリに残している。herdr に移って、\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ffolke\u002Fsnacks.nvim\" target=\"_blank\" rel=\"noopener noreferrer\">snacks.nvim\u003C\u002Fa> の画像表示が使えるようになった。Ghostty では Markdown の画像リンクのすぐ下に画像が埋め込まれるので、記事を書きながら図の見た目を確かめられる。WezTerm のときは埋め込みに対応しておらず、カーソルを乗せたときのフロート表示までだった。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002Fa41711668afb-20260924.png\" alt=\"Neovim でこの記事の Markdown を開いたところ。画像リンクの行のすぐ下に、1 タスクの流れの図がバッファ内に埋め込まれて表示されている\" loading=\"lazy\">\u003C\u002Fp>\n\u003Cp>実は 9\u002F15 に一度、この画像表示を諦めている。tmux の中では画像の残像や位置ずれが出たので、画像表示を切り、パスをコピーして Alfred で開く運用にしていた。herdr に移ってから有効に戻したところ、残像も位置ずれも出なかった。一度諦めた機能だったので、これはかなり嬉しかった。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>lazygit。\u003C\u002Fstrong> 手で直したファイルをコミットするときに使う。herdr の \u003Ccode>prefix+g\u003C\u002Fcode> でポップアップとして開くので、作業中のペインを崩さない。ステージしてから \u003Ccode>Ctrl+G\u003C\u002Fcode> を押すと、Antigravity が差分から Conventional Commits 形式のメッセージを作り、そのままコミットする（lazygit の customCommands に登録している）。エージェントが書いた変更は、エージェント自身に commit スキルを実行させてコミットすることが多い。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>hunk。\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fhunk.dev\u002F\" target=\"_blank\" rel=\"noopener noreferrer\">hunk\u003C\u002Fa> は、エージェントが書いた変更をまとめて読むための diff ビューアで、「review-first」をうたっている。今回の移行と同じタイミングで試し始めた。1 行ずつステージするなら lazygit、エージェントが複数ファイルにまたがって書いた変更の全体を読むなら hunk、という分担を考えている。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>gtr。\u003C\u002Fstrong> Git worktree の作成と削除をまとめるツールで、\u003Ccode>wt\u003C\u002Fcode> というラッパーでブランチ名も自動で付けている。worktree を作ったあとにポートの割り当てや依存のインストールを流す処理も、gtr の hook に書いてある。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>terminal-browser。\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fzenbu-labs\u002Fterminal-browser\" target=\"_blank\" rel=\"noopener noreferrer\">terminal-browser\u003C\u002Fa> は、Electron で本物の Chromium を動かし、その画面を Kitty graphics protocol でペインに描くブラウザである。localhost で動かしている手元のプロダクトも、普通の Web サイトも、実ブラウザと同じ見た目で表示される。起動は短いシェル関数にしている。\u003C\u002Fp>\n\u003Cfigure class=\"code\" data-lang=\"zsh\">\u003Cdiv class=\"code-bar\">\u003Cspan class=\"lang\">ZSH\u003C\u002Fspan>\u003Cspan>9 LINES\u003C\u002Fspan>\u003Cbutton class=\"copy\" type=\"button\" data-cursor=\"COPY\">COPY\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cpre class=\"shiki site-code\" style=\"background-color:var(--shiki-background);color:var(--shiki-foreground)\" tabindex=\"0\">\u003Ccode class=\"language-zsh\">\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># tb          → localhost:3000 を右に分割して開く\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># tb 5173     → localhost:5173\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-comment)\"># tb ... down → 2 つ目の引数で分割方向\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">tb\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">()\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  local\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> target\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"${1\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">localhost\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">3000}\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-keyword)\">  local\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> dir\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"${2\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">:-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">right}\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">  [[ \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"$target\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> ==\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\"> &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\">-\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">>\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> ]] \u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-punctuation)\">&#x26;&#x26;\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-foreground)\"> target\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-keyword)\">=\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\">\"localhost:$target\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-token-function)\">  terminal-browser\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> open\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$target\"\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string)\"> --split\u003C\u002Fspan>\u003Cspan style=\"color:var(--shiki-token-string-expression)\"> \"$dir\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:var(--shiki-foreground)\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Ffigure>\n\u003Cp>要素を選んで AI に渡す \u003Ccode>Ctrl+G\u003C\u002Fcode> は terminal-browser の組み込み機能だ。要素ピッカー（react-grab）が起動し、選んだ要素の HTML の抜粋が、同じタブにあるエージェントの入力欄に \u003Ccode>&gt; ...\u003C\u002Fcode> の 1 行で入る。React の開発ビルドなら、コンポーネント名とソースの位置も付く。Enter は押されないので、続けて指示を書いてから送る。逆に AI 側からは \u003Ccode>terminal-browser action\u003C\u002Fcode> で、開いているタブのスクリーンショット・DOM の取得・クリックなどができる。\u003C\u002Fp>\n\u003Ch3 id=\"os-操作:-aerospace-\u002F-alfred-\u002F-karabiner-\u002F-loupedeck\" tabindex=\"-1\">OS 操作: AeroSpace \u002F Alfred \u002F Karabiner \u002F Loupedeck\u003C\u002Fh3>\n\u003Cp>ターミナルの外側は、キーボードから手を離さずに済むことを基準に選んでいる。\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>AeroSpace\u003C\u002Fstrong>: タイル型のウィンドウマネージャー。Ghostty は決まったワークスペースに固定で置いている\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Alfred\u003C\u002Fstrong>: ランチャー。リポジトリを herdr のワークスペースとして Ghostty で開くワークフローや、Taskfile のタスクを実行するワークフローを自作している\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Karabiner-Elements\u003C\u002Fstrong>: キーの変換\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Loupedeck\u003C\u002Fstrong>: 物理ボタンの左手デバイス。全ペインで Claude Code を起動する、全ペインで \u003Ccode>\u002Fclear\u003C\u002Fcode> を実行する、といった一括操作を割り当てている\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"基盤:-nix-+-dotfiles\" tabindex=\"-1\">基盤: Nix + dotfiles\u003C\u002Fh3>\n\u003Cp>ここまでのツールは、すべて dotfiles リポジトリで管理し、nix-darwin + home-manager で配っている。herdr・Ghostty・terminal-browser も Homebrew の宣言に入れてある。宣言にないパッケージは switch のたびに消える設定（\u003Ccode>cleanup = &quot;zap&quot;\u003C\u002Fcode>）にしているので、試しに入れたツールを片付け忘れることがない。\u003C\u002Fp>\n\u003Cp>設定を変えるときは、判断の理由を ADR としてリポジトリに残すようにしている。今回の移行でも、試用の開始から採用の確定、ターミナル内ブラウザの経路の選択まで、2 本の ADR を書いた。この記事の数字や経緯も、ほぼその ADR から拾っている。\u003C\u002Fp>\n\u003Ch2 id=\"なぜこの構成になったか\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">05\u003C\u002Fspan>なぜこの構成になったか\u003C\u002Fh2>\n\u003Cp>ここからは移行の経緯を短く書く。流れを図にするとこうなる。\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"https:\u002F\u002Fstatic.zenn.studio\u002Fuser-upload\u002Fe1d36804def6-20260924.png\" alt=\"構成が決まるまでの判断フロー。Orca の「要素を選んで AI に渡す」機能が欲しい、しかし Orca は GUI 前提なので見送り、ターミナルの中で実現したい、herdr を試す、Neovim の画像表示とターミナル内ブラウザが動く、Chawan は SVG アイコンが描けず見送り、terminal-browser は WezTerm では重い、Ghostty なら軽く動く、Ghostty + herdr に決定\" loading=\"lazy\">\u003C\u002Fp>\n\u003Ch3 id=\"きっかけは-orca-の「要素を選んで-ai-に渡す」機能\" tabindex=\"-1\">きっかけは Orca の「要素を選んで AI に渡す」機能\u003C\u002Fh3>\n\u003Cp>9 月の頭、AI エージェント向けの統合開発環境として話題になっていた \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fstablyai\u002Forca\" target=\"_blank\" rel=\"noopener noreferrer\">Orca\u003C\u002Fa> を検討した。いちばん惹かれたのは、内蔵ブラウザで画面の要素を選び、コメントを付けてそのまま AI に渡せる機能だった。\u003C\u002Fp>\n\u003Cp>ただ、Orca 自体は私の使い方に合わなかった。GUI 前提のツールで、私の環境は逆に GUI を減らしてターミナルに寄せる方向に進んでいる。Orca の売りである worktree 管理は gtr で、GitHub 連携は \u003Ccode>gh\u003C\u002Fcode> で足りていたし、複数エージェントの管理は当時 Baton で賄えていた。\u003C\u002Fp>\n\u003Cp>それでも「要素を選んで AI に渡す」だけは欲しかった。同じことをターミナルの中でできないか。そう考えたのが、今回の入れ替えの出発点である。\u003C\u002Fp>\n\u003Ch3 id=\"herdr:-画像とブラウザが動いたのが決め手\" tabindex=\"-1\">herdr: 画像とブラウザが動いたのが決め手\u003C\u002Fh3>\n\u003Cp>herdr は、実は 9 月の頭に一度見送っている。当時は承認待ちの検知精度をいちばん重く見ていて、その観点では Baton と herdr に差がなかった。どちらも画面の文字を読んで判定する方式である。一方で移行の手間は重かった。あとで数えたところ、tmux のキーバインドが 89 個、自作スクリプトが 26 本、Baton の Go コードが 7,639 行あった。差がないなら移る理由はない、と判断した。\u003C\u002Fp>\n\u003Cp>考えが変わったのは、開発環境全体を見直したときだ。Claude Code や Codex に自動承認の仕組みが組み込まれて、Baton の safe auto mode の出番が減っていた。自作ツールを直し続ける手間と、コミュニティが活発な herdr に乗る場合を比べると、後者のほうが先がある。そこで、机上で比べるのをやめて実際に使ってみることにした。\u003C\u002Fp>\n\u003Cp>使ってみた結果、エージェント管理の使い心地は正直ほとんど変わらなかった。変わったのは別のところだ。tmux は Kitty graphics protocol に対応していない。そのため、ターミナルに画像を描く系統の機能が tmux の中では思うように動かなかった。herdr ではこれが動き、Neovim の画像表示とターミナル内ブラウザの両方が使えるようになった。takt を動かすと画面がちらつく問題も、tmux では設定で抑え込んでいたが、herdr では最初から出なかった。\u003C\u002Fp>\n\u003Cp>決め手はここだった。やりたいことがあって、それを叶えてくれたのが herdr だった。tmux のままでも解決する道はあったのかもしれない。ただ、流行っているエージェント管理ツールを試したら、副産物として長く諦めていたことが解決した。それなら herdr でいい、となった。\u003C\u002Fp>\n\u003Cp>移るときは、いきなり切り替えずに試用から始めた。最初は \u003Ccode>~\u002F.config\u002Fuse-herdr\u003C\u002Fcode> というファイルがあるかないかで、WezTerm が tmux と herdr のどちらを起動するかを切り替える形にした。戻すときは \u003Ccode>rm\u003C\u002Fcode> 1 回で済む。この状態で tmux + Baton と使い比べてから、採用を決めた。今も WezTerm を起動すれば tmux + Baton の環境に戻れるようにしてある。\u003C\u002Fp>\n\u003Cp>Baton でやっていたことは、次のように置き換えた。\u003C\u002Fp>\n\u003Cdiv class=\"tbl\" tabindex=\"0\" role=\"region\" aria-label=\"Table\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Baton \u002F tmux でやっていたこと\u003C\u002Fth>\n\u003Cth>herdr での置き換え\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>セッション一覧と状態表示\u003C\u002Ftd>\n\u003Ctd>サイドバーの working \u002F blocked \u002F idle 表示\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>TUI から承認・拒否\u003C\u002Ftd>\n\u003Ctd>自作の承認コンソール（\u003Ccode>prefix+b\u003C\u002Fcode> → \u003Ccode>a\u003C\u002Fcode> \u002F \u003Ccode>d\u003C\u002Fcode>）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>承認待ちのペインへジャンプ\u003C\u002Ftd>\n\u003Ctd>通知のクリック、または承認待ち優先の並び + \u003Ccode>prefix+alt+1\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>ghq のプロジェクトピッカー\u003C\u002Ftd>\n\u003Ctd>自作の \u003Ccode>herdr-sessionizer\u003C\u002Fcode>（\u003Ccode>prefix+f\u003C\u002Fcode>）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>N 分割・ペインの初期化\u003C\u002Ftd>\n\u003Ctd>自作の \u003Ccode>herdr-split-layout\u003C\u002Fcode> \u002F \u003Ccode>herdr-init-panes\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>tmux のキーバインド\u003C\u002Ftd>\n\u003Ctd>同じ prefix（\u003Ccode>Ctrl+Q\u003C\u002Fcode>）で移植\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>safe auto mode\u003C\u002Ftd>\n\u003Ctd>\u003Cstrong>置き換えなし\u003C\u002Fstrong>（各エージェントの自動承認に任せる）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>takt のセッション検知\u003C\u002Ftd>\n\u003Ctd>\u003Cstrong>置き換えなし\u003C\u002Fstrong>（Claude Code として一覧に出るので実害は小さい）\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Ch3 id=\"ghostty:-ターミナル内ブラウザが-wezterm-では重すぎた\" tabindex=\"-1\">Ghostty: ターミナル内ブラウザが WezTerm では重すぎた\u003C\u002Fh3>\n\u003Cp>herdr に移って最初に試したターミナル内ブラウザは Chawan だった。独自エンジンで軽く、Wikipedia のような文書中心のページは問題なく読める。ところが私のプロダクト（Next.js）を開くと、アイコンがすべて \u003Ccode>[img]\u003C\u002Fcode> という文字に置き換わった。アイコンが HTML に直接埋め込まれた \u003Ccode>&lt;svg&gt;\u003C\u002Fcode> で、Chawan はこれを描けない。モダンな Web アプリの確認には使えないので、入れて 10 分足らずで外した。\u003C\u002Fp>\n\u003Cp>次に試したのが terminal-browser だ。こちらは中身が本物の Chromium なので、表示は実ブラウザと変わらない。ただ、WezTerm + herdr の組み合わせでは、スクロールするだけで WezTerm が CPU を 1 コア以上使い続け、操作がまともに追いつかなかった。同じことを Ghostty + herdr で試すと、CPU 使用率は十数%に収まった。普通のブラウザと同じ感覚でスクロールでき、一気に快適になった。\u003C\u002Fp>\n\u003Cp>原因は、terminal-browser が画面を転送する経路にあった。terminal-browser は herdr を通してターミナルエミュレーターへ画像を直接流す専用の経路（ストリーム）を開くが、WezTerm ではこれが約 3 秒で閉じてしまい、流量制限のない予備の経路に落ちていた。なぜ閉じるのかまでは突き止めていない。\u003C\u002Fp>\n\u003Cp>もう 1 つ、Ghostty にしてよかったことがある。iPhone（Moshi）から herdr のセッションにアタッチしたあと PC に戻ると、WezTerm ではペインが実色で塗りつぶされ、背景画像が隠れてしまう現象があった。Ghostty にしてからは、今のところこれが起きていない。こちらも原因は切り分けていない。\u003C\u002Fp>\n\u003Cp>ついでに書くと、起動直後のメモリは WezTerm の約 316MB に対して Ghostty は約 213MB だった。ただ、普段のテキスト表示の速さはほぼ変わらない。Ghostty に移って得たのは、ターミナル内ブラウザが使えるようになったことだ。\u003C\u002Fp>\n\u003Ch2 id=\"失ったもの・割り切ったこと\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">06\u003C\u002Fspan>失ったもの・割り切ったこと\u003C\u002Fh2>\n\u003Cp>使い心地はほぼ変わらないと書いたが、herdr に移って失ったものもある。いちばん大きいのは見た目の自由度だ。tmux では好きに組めたステータス表示が、herdr では決まった枠の中でしかいじれない。サイドバーの列を揃える設定も、モード別に色を変える設定もない。\u003C\u002Fp>\n\u003Cp>ほかにも、次のような制約を抱えたまま使っている。\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>ペインを ID で直接フォーカスできない。\u003C\u002Fstrong> tmux 時代のペイン番号ジャンプは再現できなかった\u003C\u002Fli>\n\u003Cli>\u003Cstrong>ターミナル内のリンクをクリックで開けない。\u003C\u002Fstrong> herdr がマウスを捕まえているためで、マウス捕捉を切るとサイドバーのクリックやドラッグでのコピーも失う\u003C\u002Fli>\n\u003Cli>\u003Cstrong>safe auto mode と takt の検知がない。\u003C\u002Fstrong> どちらも Baton にしかない機能だった\u003C\u002Fli>\n\u003Cli>\u003Cstrong>terminal-browser は herdr のクライアントが 1 つのときしか軽く動かない。\u003C\u002Fstrong> iPhone から同じセッションに繋ぐと、Ghostty でも重い経路に落ちる。開き直すまで戻らない\u003C\u002Fli>\n\u003Cli>\u003Cstrong>通知が二重に出る。\u003C\u002Fstrong> Claude Code \u002F Codex の hook の通知と herdr の通知が重なっている。まだ直していない\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Ghostty のメモリは観測中。\u003C\u002Fstrong> Claude Code 由来のメモリリークの報告があったため、移行後 1 週間は 10 分おきに記録している。今のところ 200MB 前後で推移していて、増え続ける様子はない\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Baton は休止にした。WezTerm を起動すると従来どおり tmux + Baton で立ち上がるようにしてあり、いつでも戻れる。takt のセッション検知のように Baton にしかない機能もあるので、戻る可能性はゼロではない。ただ、takt のセッションも herdr のエージェント一覧には Claude Code として出てくるので、今のところ困っていない。たぶん戻らないと思う。\u003C\u002Fp>\n\u003Ch2 id=\"ターミナル中心の環境を作る人へ\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">07\u003C\u002Fspan>ターミナル中心の環境を作る人へ\u003C\u002Fh2>\n\u003Cp>前提として、開発の軸をターミナルに置くところから始めてほしい。そのうえで大事だと思うのは、一度に全部を入れないことだ。\u003C\u002Fp>\n\u003Cp>私は Neovim を組み始めたとき、プラグインを次々に入れていた。Neovim には LazyVim のような全部入りのディストリビューションと、lazy.nvim のようなプラグインマネージャーで 1 つずつ足していくやり方がある（名前が似ていてややこしい）。全部入りで始めると、自分の環境に何の機能が入っているのかを把握しきれなくなる。私は 1 つずつ入れて使い心地を確かめ、目的を 1 つずつ潰していくやり方のほうが合っていた。\u003C\u002Fp>\n\u003Cp>設定が面倒な人には、Ghostty と herdr から始めるのがいいと思う。Ghostty は設定なしでまともに動くことを設計思想にしている。herdr も、tmux の取っつきにくさを減らす方向で作られている。キーボードとマウスの両方を正式な操作方法として扱っているので、prefix キーを覚える前からクリックとドラッグで分割や移動ができる。\u003C\u002Fp>\n\u003Cp>そこから先は、使いながら育てればいい。やりたいことが出てきたとき、他の人の環境紹介を読んで「この機能いいな」と思ったときに、その考え方を 1 つずつ取り込む。私の今の構成も、Orca の機能に惹かれたところから始まっている。\u003C\u002Fp>\n\u003Ch2 id=\"まとめ\" tabindex=\"-1\">\u003Cspan class=\"h-no\" aria-hidden=\"true\">08\u003C\u002Fspan>まとめ\u003C\u002Fh2>\n\u003Cp>半年前の記事と比べると、入れ替えたのはターミナルエミュレーター・マルチプレクサ・セッション管理の 3 つだけだ。エージェントを並べて承認を回す、という開発のやり方もほとんど変わっていない。\u003C\u002Fp>\n\u003Cp>それでも、tmux 時代に諦めていたことが 2 つ戻ってきた。Neovim で画像を見ることと、ブラウザで要素を指して AI に直させることだ。環境を入れ替える理由として、私にはこれで十分だった。\u003C\u002Fp>\n\u003Cp>使い込むうちに、また不満や入れ替えたいものが出てくると思う。そのときはまた ADR に書き足していく。\u003C\u002Fp>\n",[462,464,466,469,471,474,477,480,482,485,488,490,493,496,499,501,503],{"level":426,"id":463,"text":463},"結論から",{"level":426,"id":465,"text":465},"半年前から変わったところ",{"level":426,"id":467,"text":468},"ghostty-+-herdr-でどう開発しているか-—-1-タスクの流れ","Ghostty + herdr でどう開発しているか — 1 タスクの流れ",{"level":426,"id":470,"text":470},"レイヤー別のツール紹介",{"level":419,"id":472,"text":473},"ターミナルエミュレーター:-ghostty","ターミナルエミュレーター: Ghostty",{"level":419,"id":475,"text":476},"マルチプレクサ:-herdr","マルチプレクサ: herdr",{"level":419,"id":478,"text":479},"ai-エージェント:-claude-code-\u002F-codex-\u002F-takt-\u002F-opencode-\u002F-antigravity","AI エージェント: Claude Code \u002F Codex \u002F takt \u002F OpenCode \u002F Antigravity",{"level":419,"id":481,"text":481},"開発ツール",{"level":419,"id":483,"text":484},"os-操作:-aerospace-\u002F-alfred-\u002F-karabiner-\u002F-loupedeck","OS 操作: AeroSpace \u002F Alfred \u002F Karabiner \u002F Loupedeck",{"level":419,"id":486,"text":487},"基盤:-nix-+-dotfiles","基盤: Nix + dotfiles",{"level":426,"id":489,"text":489},"なぜこの構成になったか",{"level":419,"id":491,"text":492},"きっかけは-orca-の「要素を選んで-ai-に渡す」機能","きっかけは Orca の「要素を選んで AI に渡す」機能",{"level":419,"id":494,"text":495},"herdr:-画像とブラウザが動いたのが決め手","herdr: 画像とブラウザが動いたのが決め手",{"level":419,"id":497,"text":498},"ghostty:-ターミナル内ブラウザが-wezterm-では重すぎた","Ghostty: ターミナル内ブラウザが WezTerm では重すぎた",{"level":426,"id":500,"text":500},"失ったもの・割り切ったこと",{"level":426,"id":502,"text":502},"ターミナル中心の環境を作る人へ",{"level":426,"id":504,"text":504},"まとめ",27,{"slug":75,"title":76,"description":77,"publishedAt":78,"updatedAt":78,"category":507,"tags":508,"thumbnail":16},{"name":49,"slug":50},[509,510,511],{"name":58,"slug":59},{"name":83,"slug":84},{"name":86,"slug":86},{"slug":44,"title":45,"description":46,"publishedAt":47,"updatedAt":47,"category":513,"tags":514,"thumbnail":16},{"name":49,"slug":50},[515,516,517],{"name":53,"slug":53},{"name":55,"slug":56},{"name":58,"slug":59},[519,525,531],{"slug":44,"title":45,"description":46,"publishedAt":47,"updatedAt":47,"category":520,"tags":521,"thumbnail":16},{"name":49,"slug":50},[522,523,524],{"name":53,"slug":53},{"name":55,"slug":56},{"name":58,"slug":59},{"slug":75,"title":76,"description":77,"publishedAt":78,"updatedAt":78,"category":526,"tags":527,"thumbnail":16},{"name":49,"slug":50},[528,529,530],{"name":58,"slug":59},{"name":83,"slug":84},{"name":86,"slug":86},{"slug":168,"title":169,"description":170,"publishedAt":171,"updatedAt":172,"category":532,"tags":533,"thumbnail":536},{"name":49,"slug":50},[534,535],{"name":25,"slug":26},{"name":58,"slug":59},{"url":178,"description":104},1793725976659]