Homebrew taps: distributing your own CLI tools to your team without writing an installer

You wrote a small CLI tool — a deploy script, a log parser, a backup wrapper. Two coworkers want to use it on their Macs. You email them a tarball. Three months later you fix a bug. Now you have to remember whose machines have it, who’s on the old version, and how to redeploy. By the time the team is five people you’ve reinvented half of apt.

The right answer for “I have a tool, and a few Macs need to install it” is a Homebrew tap. It costs you a single GitHub repo and ten lines of Ruby. Your team installs your tool with one command, gets updates with brew upgrade, and you get a real version-history. Here’s the smallest possible setup.

What a tap actually is

A “tap” is a public or private GitHub repo named homebrew-<something> that contains formulas: small Ruby files describing how to download and install a piece of software. When someone runs brew tap your-org/your-tap, brew clones that repo into $(brew --repository)/Library/Taps/your-org/homebrew-your-tap. From then on, every formula in the repo behaves exactly like a formula from the official Homebrew core — brew install, brew upgrade, brew uninstall all work.

The repo is just a folder of Ruby files. You don’t need to write an installer, you don’t need to maintain a signing pipeline, you don’t need to host binaries on your own server (though you can). For most internal tools, the formula points at a tagged GitHub release tarball.

Step 1 — make your tool installable

Your CLI tool needs:

  • A GitHub repo (public or private — both work).
  • A tagged release. Even v0.1.0 on a single commit is fine.
  • A way to install itself when someone unpacks the tarball — a Makefile with a make install target, or a bin/ directory with the executable already at the right path. For a single shell script, just chmod +x bin/mytool.

For example, if your tool is a single Bash script:

# my-tool/Makefile
PREFIX ?= /usr/local

install:
	install -m 0755 bin/mytool $(PREFIX)/bin/mytool

That’s all the install logic you need. Tag the repo:

git tag v0.1.0 && git push --tags

Step 2 — create the tap repo

The repo MUST be named homebrew-<name>. Convention: name it after your team or your product line, not after the tool. So if your team is “platform” and you’ll publish 3 tools, the tap is your-org/homebrew-platform.

gh repo create your-org/homebrew-platform --public
git clone https://github.com/your-org/homebrew-platform.git
cd homebrew-platform
mkdir Formula

Step 3 — the formula

Create Formula/mytool.rb:

class Mytool < Formula
  desc "One-line description of what mytool does"
  homepage "https://github.com/your-org/my-tool"
  url "https://github.com/your-org/my-tool/archive/refs/tags/v0.1.0.tar.gz"
  sha256 "REPLACE_ME_AFTER_FIRST_DOWNLOAD"
  license "MIT"

  def install
    system "make", "install", "PREFIX=#{prefix}"
  end

  test do
    assert_match "mytool 0.1.0", shell_output("#{bin}/mytool --version")
  end
end

To get the SHA256 for the url, run:

curl -sL "https://github.com/your-org/my-tool/archive/refs/tags/v0.1.0.tar.gz" | shasum -a 256

Paste that hash into the formula. Commit and push the tap repo. That’s it — your tap is live.

Step 4 — your team installs it

brew tap your-org/platform
brew install mytool

# from now on, this just works
mytool --version
brew upgrade mytool      # when you tag v0.2.0

If your tool is in a private repo, brew can clone it via SSH if your team has GitHub keys set up:

brew tap your-org/platform git@github.com:your-org/homebrew-platform.git

Releasing a new version

  1. Tag a new release of your tool repo: git tag v0.2.0 && git push --tags. GitHub creates the tarball automatically.
  2. Recompute the SHA256 of the new tarball.
  3. Edit the formula in the tap repo: bump the version in the url line and update the sha256.
  4. Commit + push the tap repo.
  5. Done. brew upgrade mytool will pick up the new version on every team Mac.

You can automate steps 2–4 with a GitHub Action triggered on the tool repo’s release event — but for a small team, doing it by hand the first few times is fine.

What about Linux?

Homebrew on Linux is a real thing — the same tap works on both macOS and Linux installs of brew. You don’t need to do anything special unless your tool has macOS-specific dependencies (in which case add an on_macos do block to the formula).

Why this beats writing your own installer

  • You inherit version pinning, dependency declarations, audit logs, and uninstall. brew tracks all of it.
  • Your users don’t memorize per-tool install commands. They learned brew install once.
  • You get free Apple Silicon + Intel + Linux support as long as your tool is portable. brew’s bottle system can even cache pre-compiled artifacts if your tool has a real build step.
  • It scales to the team’s whole tool catalog without becoming the work of one dedicated SRE. The marginal cost of formula #2 is two minutes.

This site uses Akismet to reduce spam. Learn how your comment data is processed.