<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Herdr on AIquoteBA</title>
        <link>https://blog.mayaton.net/tags/herdr/</link>
        <description>Recent content in Herdr on AIquoteBA</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>ja-jp</language>
        <lastBuildDate>Fri, 18 Sep 2026 01:00:00 +0900</lastBuildDate><atom:link href="https://blog.mayaton.net/tags/herdr/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>herdrからghqリポジトリを開くpopup pickerを作った話</title>
            <link>https://blog.mayaton.net/posts/herdr-repo-picker/</link>
            <pubDate>Fri, 18 Sep 2026 01:00:00 +0900</pubDate>
            <guid>https://blog.mayaton.net/posts/herdr-repo-picker/</guid>
            <description>&lt;h2 id=&#34;概要&#34;&gt;概要&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/atolab-io/herdr&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;herdr&lt;/a&gt;から、ghqで並んでいるリポジトリを中央popupのfuzzy pickerで選び、そのリポジトリのworkspaceに一発で飛べるプラグイン&lt;a class=&#34;link&#34; href=&#34;https://github.com/mayaton/herdr-repo-picker&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;herdr-repo-picker&lt;/a&gt;を書いた。&lt;/li&gt;&#xA;&lt;li&gt;同名のworkspaceが既に開いていればfocus、無ければ新規作成して初期ペインで&lt;code&gt;claude&lt;/code&gt;を起動する。&lt;/li&gt;&#xA;&lt;li&gt;未allowの&lt;code&gt;.envrc&lt;/code&gt;があると起動をブロックし、&lt;code&gt;direnv allow&lt;/code&gt;の手順を表示する安全側の挙動を入れた。&lt;/li&gt;&#xA;&lt;li&gt;実装はRust (ratatui / crossterm / nucleo)で、herdr 0.7.4以降の&lt;code&gt;placement = &amp;quot;popup&amp;quot;&lt;/code&gt;に乗せて画面中央の小窓として開くようにした。&lt;/li&gt;&#xA;&lt;li&gt;prefix + pに割り当てておけば、複数リポジトリを行き来しながらClaude Codeで作業する日常が地味に軽くなる。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;動機&#34;&gt;動機&#xA;&lt;/h2&gt;&lt;p&gt;herdrで日常の作業をやっていると、リポジトリごとに1つworkspaceを立てる運用に自然と落ち着く。&lt;br&gt;&#xA;&lt;code&gt;~/ghq/github.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;&lt;/code&gt;に入って&lt;code&gt;claude&lt;/code&gt;を起動し、そこからworktreeを切って作業していく形だ。&lt;/p&gt;&#xA;&lt;p&gt;問題は、リポジトリを切り替えるたびに手順を踏み直すことだった。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;既存のworkspaceがあるかどうかを目で確認する。&lt;/li&gt;&#xA;&lt;li&gt;無ければ&lt;code&gt;herdr workspace create --cwd &amp;lt;path&amp;gt;&lt;/code&gt;を叩き、初期ペインで&lt;code&gt;claude&lt;/code&gt;を起動し直す。&lt;/li&gt;&#xA;&lt;li&gt;リポジトリ数が増えるほど、この儀式が体感の摩擦になる。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;やりたいのは「prefix + pでpopupを開き、リポ名を数文字打って選び、あとは勝手にworkspaceを開いてほしい」の1点だった。&lt;br&gt;&#xA;既存プラグインを軽く漁ったが、ghqと相性の良いものが見当たらなかったので自作した。&lt;/p&gt;&#xA;&lt;h2 id=&#34;何ができるか&#34;&gt;何ができるか&#xA;&lt;/h2&gt;&lt;p&gt;主な挙動は次の通り。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;fuzzy検索&lt;/strong&gt;: &lt;a class=&#34;link&#34; href=&#34;https://github.com/helix-editor/nucleo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;nucleo&lt;/a&gt; (HelixやZedと同じmatcher) で&lt;code&gt;ghq list&lt;/code&gt;の結果を絞り込む。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;既存workspaceのfocus&lt;/strong&gt;: 同名workspaceが開いていれば、新規作成せず単にfocusする。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;workspaceの新規作成 + &lt;code&gt;claude&lt;/code&gt;起動&lt;/strong&gt;: 無ければ&lt;code&gt;herdr workspace create&lt;/code&gt;して、初期ペインでconfigの&lt;code&gt;launch_command&lt;/code&gt; (既定は&lt;code&gt;claude&lt;/code&gt;) を走らせる。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;direnvガード&lt;/strong&gt;: 選んだリポジトリに未allowの&lt;code&gt;.envrc&lt;/code&gt;があれば、起動をブロックして&lt;code&gt;direnv allow&lt;/code&gt;の手順を表示する。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;中央popup UI&lt;/strong&gt;: herdrの&lt;code&gt;placement = &amp;quot;popup&amp;quot;&lt;/code&gt;で、60%×60%の小窓として画面中央に浮かぶ (full-screenは潰さない)。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;prefix + pでpopupを開いた直後の画面。中央60%×60%にRepo pickerが浮かび、ghq listのフル一覧が並んでいる。&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;408px&#34; data-flex-grow=&#34;170&#34; height=&#34;1050&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://blog.mayaton.net/posts/herdr-repo-picker/popup-open.png&#34; srcset=&#34;https://blog.mayaton.net/posts/herdr-repo-picker/popup-open_hu_773c3aae358ad2f4.png 800w, https://blog.mayaton.net/posts/herdr-repo-picker/popup-open_hu_415381f123ed8334.png 1600w, https://blog.mayaton.net/posts/herdr-repo-picker/popup-open.png 1788w&#34; width=&#34;1788&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;インストール&#34;&gt;インストール&#xA;&lt;/h2&gt;&lt;p&gt;herdrのプラグインとしてinstallする。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;herdr plugin install mayaton/herdr-repo-picker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;installの過程で、release済みのprebuildバイナリをGitHub Releasesから取ってくる。&lt;br&gt;&#xA;DLに失敗した場合はcargoでの手元ビルドにフォールバックする&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;&#xA;&lt;p&gt;対応プラットフォームは&lt;code&gt;linux/x86_64&lt;/code&gt; / &lt;code&gt;linux/aarch64&lt;/code&gt; / &lt;code&gt;macos/x86_64&lt;/code&gt; / &lt;code&gt;macos/aarch64&lt;/code&gt;の4種。&lt;/p&gt;&#xA;&lt;h2 id=&#34;キーバインドを割り当てる&#34;&gt;キーバインドを割り当てる&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;~/.config/herdr/config.toml&lt;/code&gt;に、popupを開くキーを1つ足す。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[&lt;span style=&#34;color:#a6e22e&#34;&gt;keys&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;]]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;prefix+p&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;plugin_action&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;herdr-repo-picker.open-picker&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;description&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Open ghq repo picker&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存したら&lt;code&gt;herdr server reload-config&lt;/code&gt;で反映する。&lt;br&gt;&#xA;prefix + pを叩くと、画面中央にpickerが浮かぶ。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;検索欄に「do」と打った状態。nucleoが絞り込んだリポジトリだけがpopup内に並ぶ。&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;381px&#34; data-flex-grow=&#34;159&#34; height=&#34;574&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://blog.mayaton.net/posts/herdr-repo-picker/fuzzy-search.png&#34; srcset=&#34;https://blog.mayaton.net/posts/herdr-repo-picker/fuzzy-search_hu_12436286d5552e1e.png 800w, https://blog.mayaton.net/posts/herdr-repo-picker/fuzzy-search.png 913w&#34; width=&#34;913&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;動作の流れ&#34;&gt;動作の流れ&#xA;&lt;/h2&gt;&lt;p&gt;popupを開いてから抜けるまでの流れは、次の3ステップで閉じる。&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;ghq list&lt;/code&gt;のフル一覧が&lt;code&gt;ghq root&lt;/code&gt;との合成で絶対パス化されて表示される。&lt;/li&gt;&#xA;&lt;li&gt;数文字打つとnucleoで絞り込まれ、上下キー / Enterで選択する。&lt;/li&gt;&#xA;&lt;li&gt;選ばれたリポジトリに対し、同名のworkspaceがあればfocus、無ければ新規作成 + &lt;code&gt;claude&lt;/code&gt;起動でジャンプする。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;余計な確認は挟まない。&lt;br&gt;&#xA;popup自体はEscで閉じるだけで、副作用は残らない。&lt;/p&gt;&#xA;&lt;h2 id=&#34;configで挙動を差し替える&#34;&gt;configで挙動を差し替える&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;herdr plugin config-dir herdr-repo-picker&lt;/code&gt;が指すディレクトリに&lt;code&gt;config.toml&lt;/code&gt;を置くと、コマンド類を差し替えられる。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# リポジトリ列挙 (ghq 互換ならなんでも良い)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;list_command&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ghq&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 相対パスを絶対パスに合成する root コマンド&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;root_command&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ghq&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 新規 workspace 作成時に初期ペインで走らせるコマンド&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 空配列にすると素の shell のまま&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;launch_command&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;claude&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 未 allow の .envrc を検出したら起動をブロックする&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;direnv_guard&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;launch_command&lt;/code&gt;だけを差し替えるユースケースが一番多いはず。&lt;br&gt;&#xA;&lt;code&gt;claude&lt;/code&gt;の代わりに&lt;code&gt;claude --model opus&lt;/code&gt;や&lt;code&gt;nvim&lt;/code&gt;、&lt;code&gt;lazygit&lt;/code&gt;などに書き換えれば、pickerは単に「ghqから選んでworkspaceに何かを走らせるランチャ」として使える。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;list_command&lt;/code&gt;と&lt;code&gt;root_command&lt;/code&gt;は、ghqと同じインターフェース (パス一覧 + rootディレクトリ) を返すコマンドなら差し替え可能なので、&lt;code&gt;fd&lt;/code&gt;や独自スクリプトを載せても動く。&lt;/p&gt;&#xA;&lt;h2 id=&#34;direnvガードの意図&#34;&gt;direnvガードの意図&#xA;&lt;/h2&gt;&lt;p&gt;未allowの&lt;code&gt;.envrc&lt;/code&gt;を含むリポジトリに入ると、direnvは環境変数を読まずに警告だけ出す。&lt;br&gt;&#xA;その状態で&lt;code&gt;claude&lt;/code&gt;を起動すると、開発に必要な環境変数を欠いたまま作業に入ってしまう。&lt;/p&gt;&#xA;&lt;p&gt;これに気付かず「なぜかテストが通らない」で時間を溶かした経験が何度かあったので、pickerの段階でブロックする挙動をデフォルトにした。&lt;/p&gt;&#xA;&lt;p&gt;ブロック画面には、そのリポジトリで&lt;code&gt;direnv allow&lt;/code&gt;を打つための手順がそのまま表示される。&lt;br&gt;&#xA;allowしてからpickerを開き直せば普通に飛べる。&lt;br&gt;&#xA;「毎回allowを促されるのは煩わしい」場合は&lt;code&gt;direnv_guard = false&lt;/code&gt;で無効化できる。&lt;/p&gt;&#xA;&lt;h2 id=&#34;感想&#34;&gt;感想&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;「prefix + pで既存workspaceにfocus、無ければ作る」だけの薄い機能で、リポ切り替えの体感摩擦が数秒→ほぼゼロまで落ちた。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;placement = &amp;quot;popup&amp;quot;&lt;/code&gt;は&lt;code&gt;herdr plugin pane open --help&lt;/code&gt;の&lt;code&gt;--placement&lt;/code&gt;一覧に出てこない指定で、他プラグインのmanifestを眺めていて存在に気付いた。&lt;/li&gt;&#xA;&lt;li&gt;中央小窓のUIはfull-screen overlayとは体験が違うので、他プラグインでも試す価値がある。&lt;/li&gt;&#xA;&lt;li&gt;Rust側の実装はratatui + crossterm + nucleoでコード全体1000行程度に収まった。&lt;/li&gt;&#xA;&lt;li&gt;ghq互換のインターフェースを外部コマンドとして受け取る設計で、picker本体はghqそのものには依存していない。&lt;/li&gt;&#xA;&lt;li&gt;MITライセンスで公開したので、ghqとherdrを併用している方は気軽に試してもらえれば。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;code&gt;scripts/fetch-or-build.sh&lt;/code&gt;が&lt;code&gt;v&amp;lt;version&amp;gt;&lt;/code&gt;のtagに紐付いたtarballを取得しSHA256でverifyしてから展開し、取得に失敗した場合は&lt;code&gt;cargo build --release&lt;/code&gt;にフォールバックする。&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item></channel>
</rss>
