Claude Media
Claude CodeでHomebrewのformulaとtapを作る — auditとtestで検証させる

Claude CodeでHomebrewのformulaとtapを作る — auditとtestで検証させる

Claude Codeに自作CLIのHomebrew tapとformulaを作らせる手順です。brew audit --strictとbrew testを検証コマンドにし、CLAUDE.mdとStop hookで反復させます。

自作のCLIをHomebrewで配るなら、tapという自分用のGitリポジトリにformulaを置くのが最短の経路です。Claude Codeに任せるときは、brew audit --strict と brew test を検証コマンドに据えます。formulaはRubyの小さなファイルですが、URLやsha256の誤り、テストの書き方、命名の衝突など、動かして初めて分かる失敗が多いからです。

この記事では、tapの作成から公開まで、formulaの作成、検証コマンドの分担、CLAUDE.mdとStop hookへの落とし込み、Claudeに任せない操作の線引きを順に扱います。

tapとformulaの関係を3行で押さえる

tapは、formula・cask・外部コマンドを配るための外部ソースです。実体はGitが扱えるリポジトリで、ディレクトリだけでも成り立ちます。GitHubに置くなら、リポジトリ名を homebrew- で始めると brew tap の短い書式が使えます。

formulaは、パッケージの定義を書いたRubyのファイルです。tapの中では Formula サブディレクトリ、HomebrewFormula サブディレクトリ、リポジトリ直下のいずれかに置け、先に見つかったディレクトリだけが使われます。整理しやすいので、サブディレクトリに置く方式が推奨されています。

Claude Codeの役割は、この2つの型に沿ったファイルを作り、検証コマンドの出力を読んで直すことです。インストールの是非や配布の最終判断は人が持ちます。

tapを作って公開する手順

tapの雛形は brew tap-new で作ります。alice の部分は自分のGitHubユーザー名に読み替えてください。

brew tap-new alice/homebrew-tap
brew install gh
gh repo create alice/homebrew-tap --push --public \
  --source "$(brew --repository alice/homebrew-tap)"

brew tap-new はローカルにtapを作り、Library/Taps 配下にGitリポジトリを初期化します。出力の最後に表示される名前は alice/tap で、リポジトリ名の homebrew- は省かれます。以降の --tap オプションやinstallコマンドでは、この短い名前を使います。

雛形にはGitHub Actionsのワークフローが入っています。そのまま残せば、プルリクエストごとにボトル(バイナリのパッケージ)がActionsで作られます。GitHub Packagesにアップロードしたい場合は、brew tap-new に --github-packages を付けます。

ここで押さえておきたいのは、tapの作業場所です。brew tap-new が作るリポジトリは、Homebrewが管理する Library/Taps の下にあります。Claude Codeを起動するディレクトリも brew --repository alice/homebrew-tap の出力先にしておくと、後の検証コマンドでtap名とファイルが食い違いません。

formulaをClaude Codeに書かせる

formulaの下書きは brew create で作ります。URLにはソースのtarballやzipを渡します。

brew create https://example.com/hello-tool-1.0.0.tar.gz \
  --tap alice/homebrew-tap --set-name hello-tool

--set-name は、URLから名前が推測できないときに上書きする指定です。brew create はエディタを開くので、Claude Codeに作らせるときはファイルが生成された時点で中身を読ませ、そのまま編集させる流れになります。brew create --help には対応する言語・ビルド方式のテンプレートが並んでいて、合うオプションを渡すと下書きが近くなります。

例えば、単一のシェルスクリプトを配る最小のformulaは、次のような形になります。URLとsha256は仮の値で、公式のサンプルをそのまま転記したものではなく、構造だけをなぞった例示です。

class HelloTool < Formula
  desc "Prints a greeting for the current user"
  homepage "https://github.com/alice/hello-tool"
  url "https://github.com/alice/hello-tool/archive/refs/tags/v1.0.0.tar.gz"
  sha256 "<curl -L <URL> | shasum -a 256 の結果>"
  license "MIT"
 
  def install
    bin.install "hello-tool"
  end
 
  test do
    assert_match "Hello", shell_output("#{bin}/hello-tool alice")
  end
end

名前に関する規則は2つです。ファイル名は小文字で、クラス名はそのCamelCase表記になります。gnu-go なら GnuGo です。クラス名を変えたらファイル名も合わせて直します。もう1つは、homebrew-coreにある名前との衝突です。同名のformulaは並べて入れられないので、オプション違いのものを作るときは nginx-full のように別名にします。caskだけは事情が違い、名前がグローバルに一意でなければなりません。GitHubユーザー名を頭に付ける方法が案内されています。

検証コマンドを3つに分けて役割を決める

Claudeに「formulaを直して」と頼むと、書き換えた直後に完了と答えてしまいがちです。検証を3段に分け、それぞれ何が分かるコマンドなのかをはっきり渡します。

段階コマンド何が分かるか所要時間の感覚
1. 静的検査コマンドbrew audit --strict --online alice/tap/hello-tool何が分かるかスタイル違反、URLの扱い、メタデータの不備所要時間の感覚短い
2. ビルドコマンドbrew install --build-from-source alice/tap/hello-tool何が分かるかurl・sha256・依存宣言・installの誤り所要時間の感覚中程度
3. 動作確認コマンドbrew test alice/tap/hello-tool何が分かるかtest do ブロックのアサーション所要時間の感覚短い

brew audit は、Homebrewのコーディングスタイル違反を検査します。--strict で追加の厳しい検査、--online で通信が要る検査が加わります。名前を指定せずに実行すると、手元の全formulaが対象になり、スタイル検査は省かれます。Claudeに渡すときは、必ずtap名付きでformulaを指定させてください。問題が見つかると非ゼロの終了コードで終わるため、反復の合否判定に使えます。

brew test は、インストール済みのformulaが持つ test do ブロックを実行します。標準の出力や終了コードの決まりはなく、問題があれば利用者に分かる形で知らせる仕組みです。つまり、brew test はインストールが済んでいないと意味を持ちません。ここが、audit一本で済ませると抜け落ちる部分です。

新規のformulaをhomebrew-coreに提案する場合は、より厳しい brew audit --new --formula が使われます。この指定は --strict と --online を含みます。自分のtapで配るだけなら必須ではありませんが、検査の厳しさを一段上げたいときの選択肢にはなります。

testブロックの書き方がClaudeの出来を左右する

test do はClaudeが最も手を抜きやすい箇所です。Homebrewのガイドは、ユーザー入力が要らず、基本機能を試すテストを求めています。foo --version や foo --help は悪いテストの例として挙げられていて、それでもテストが無いよりは良いという位置づけです。

CLAUDE.mdには、この水準を数行で書き込んでおきます。例えば「testでは実際の入力ファイルを testpath に作り、出力を assert_match か assert_equal で比べる」と書けば、--version で済ませる案を出されにくくなります。testpath は、テスト中だけ使われる一時ディレクトリです。HOME もそこに向けられるので、ユーザーの実環境を汚しません。

認証情報が要るソフトのテストは、資格情報なしで接続して期待どおり失敗することを確かめる方法が勧められています。モックで済ませるより、この形が優先されます。外部APIに依存するCLIをClaudeに書かせるときは、その方針をCLAUDE.mdに写しておくと役立ちます。

CLAUDE.mdに書く反復のルール

検証コマンドが決まったら、tapのリポジトリ直下のCLAUDE.mdに規約として書きます。Claude CodeはCLAUDE.mdを、強制される設定ではなくコンテキストとして扱います。具体的で短い指示ほど守られやすく、1ファイルは200行以内が目安です。次の断片は、その前提で絞った例です。

# このtapのルール
 
- formulaは Formula/ 直下に置く。ファイル名は小文字、クラス名はCamelCase
- formulaを編集したら、完了と言う前に次を順に実行し、出力を読む
  1. brew audit --strict --online alice/tap/<name>
  2. brew install --build-from-source alice/tap/<name>
  3. brew test alice/tap/<name>
- audit の警告は握りつぶさず、formula側を直す
- test do は --version や --help だけにしない。testpath に入力を作って結果を比べる
- sha256 は curl -L <URL> | shasum -a 256 で自分で計算して入れる。推測値を書かない
- brew pr-pull、git push、brew untap は実行しない。人が実行する

最後の1行が重要です。ボトルの公開に使う brew pr-pull は、レビュー済みのコミットSHAを渡して実行する前提の操作で、--head-sha を付けるとレビュー後に変更されたコミットを公開してしまう事故を防げます。公開は人がSHAを確かめて行う作業として、Claudeの範囲から外します。

sha256の行も同じ理由で入れます。モデルが値を推測して埋めると、installの段階で初めて不一致が分かります。公式の手順は、curl -L <URL> | shasum -a 256 で実際のハッシュを求める方法です。

Stop hookでauditを自動実行する

CLAUDE.mdの指示は、守られない場合があります。確実に走らせたい最初の1段、つまり brew audit は、Stop hookに預けます。Stopは、Claude Codeの本体が応答を終えたときに動くイベントです。終了コード2を返すと、Claudeに作業の続行を促せます。

.claude/settings.json に次を書きます。

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/audit-formula.sh"
          }
        ]
      }
    ]
  }
}

スクリプトは、Gitで変更が出ているformulaだけを対象にします。例えば次のような形です。

#!/bin/bash
INPUT=$(cat)
# すでにStop hookの結果で続行中なら、同じ失敗の往復を避けて抜ける
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0
fi
 
TAP="alice/tap"
for f in $(git status --porcelain Formula | sed -n 's#^.. Formula/\(.*\)\.rb$#\1#p'); do
  if ! out=$(brew audit --strict --online "$TAP/$f" 2>&1); then
    echo "brew audit failed for $f:" >&2
    echo "$out" >&2
    exit 2
  fi
done
exit 0

stop_hook_active は、すでにStop hookの結果として続行している最中かどうかを示す値です。解決しない条件でブロックし続けないよう、確認することが勧められています。さらにClaude Codeには安全弁があり、Stop hookが8回連続でターンの終了を止めると、次のブロックは無視されて終了します。ツール呼び出しを挟むたびに連続回数は戻ります。auditの警告を直すのに8回を超える往復が要るなら、CLAUDE_CODE_STOP_HOOK_BLOCK_CAP で上限を変えられます。

hookの終了コード1は、ブロックしない軽いエラー扱いです。方針を強制したいときは exit 2 を使います。同じ型のhookをテストコマンドに使った例はClaude CodeでKtorサーバーを作る手順にあります。

brew install --build-from-source は時間がかかるため、hookには入れていません。CLAUDE.mdで順序を指示し、auditだけを確実に回す分担です。

反復の流れと、詰まったときの切り分け

実際の作業は、Claudeが次の順で回す形になります。

手順

formulaの修正ループ

  1. 1

    formulaを書く、または直す

    Formula/hello-tool.rb を編集します。sha256は実際のtarballから計算した値を使います。

  2. 2

    auditを通す

    brew audit --strict --online alice/tap/hello-tool を実行し、警告が0になるまでformulaを直します。

  3. 3

    ソースからビルドする

    brew install --build-from-source alice/tap/hello-tool で、url・sha256・installの誤りを洗い出します。

  4. 4

    testを走らせる

    brew test alice/tap/hello-tool の結果を読み、失敗ならtestかinstallを直して2へ戻ります。

詰まったときは、症状から原因を切り分けます。ここに挙げる4つは、tapの保守ガイドが失敗の典型として整理しているものです。

症状まず見る場所
tapを入れたのにformulaが見つからないまず見る場所ファイルが Formula/ にあるか、拡張子が .rb か
installが失敗するまず見る場所url と sha256 の値。curl -L <URL> | shasum -a 256 で再計算する
利用者の手元でtapが更新されないまず見る場所brew untap user/repository && brew tap user/repository で取り直してもらう
homebrew-coreのformulaと衝突するまず見る場所名前を変えるか、keg-onlyにする

Claudeに症状とコマンド出力をそのまま渡し、どの行を疑うかを1つずつ決めさせます。ここでも、直した理由をコミットメッセージに1行書かせておくと、後から差分を追えます。

利用者に配る側の書き方

tapを公開したら、利用者には brew install alice/homebrew-tap/hello-tool の1コマンドを案内します。Homebrewがtapを自動で追加してから、そのformulaだけをインストールします。この方法は、インストールするformulaだけを信頼する点でも推奨される形です。

先にtapだけを追加したい人には、brew tap alice/homebrew-tap を案内します。GitHub以外にホストしているなら、末尾にGitのクローンURLを足します。tapを追加した後は、homebrew-coreに同名がなければ brew install hello-tool で入ります。衝突を避けたいときは、brew install alice/homebrew-tap/hello-tool と完全な形で書きます。

公式でないtapは、既定で明示的な信頼が必要です。tap全体を信頼する必要がなければ、brew trust --formula alice/homebrew-tap/hello-tool で個別のformulaだけを信頼できます。brew trust --tap は、tap内のformula・cask・外部コマンドをすべて信頼するときに限って使う指定です。READMEには、どちらの案内を載せるかを書いておきます。

更新は、利用者が brew update を実行するたびにtapが更新され、古くなったformulaは brew upgrade で上がります。新しいリリースを切ったら、formulaの url と sha256 を新しい値に書き換えてpushするだけです。この書き換えはClaudeに任せやすい作業ですが、タグ付けとpushは人が行います。リリース番号はセマンティックバージョニングで付ける、READMEにformulaの説明を書く、依存は depends_on で漏れなく宣言する、というのもガイドが挙げる運用上のポイントです。

過去のバージョンのformulaを自分のtapに残したいときは brew extract --version=1.2.3 foo alice/homebrew-tap が使えます。これはファイルを作るだけです。コミット、push、非推奨化への対応、セキュリティ更新はすべて自分で受け持つことになります。

cask(GUIアプリなど)もtapで配れます。tapの直下に Casks ディレクトリを作ってファイルを置きます。外部コマンドを提供したい場合は cmd サブディレクトリに入れます。この記事の検証コマンドはformula向けなので、caskを扱うときは brew audit の対象指定とcask向けの検査を別に確かめます。

Claude Code自体の配布との違い

ここまでは、自作のCLIをtapで配る話でした。Claude Code自体をHomebrewで入れるときは、formulaではなくcaskの claude-code を使います。更新方式の違いはClaude CodeをHomebrewで入れる方法と更新に整理しました。tapの運用では、自作ソフトの更新はあなたのtapの更新が起点で、Claude Code側の更新とは別の流れだと分けて考えると混乱しません。

macOSで手元の環境を整える段階の話はClaude Code Macインストールが先に読める記事です。

まとめ

tapとformulaは、検証コマンドが決まっている分、Claude Codeに反復させやすい題材です。brew audit --strict --online はStop hookで確実に走らせ、brew install --build-from-source と brew test はCLAUDE.mdで順序を指示する。この分担が、時間のかかる検査でhookを重くしない折衷点です。

test do の質、sha256の実計算、brew pr-pull を人の手に残す線引きの3点を最初にCLAUDE.mdへ書いておくと、Claudeの出力がレビューしやすい形に揃います。

この記事を共有:XはてブLinkedIn