CLI to manage your Homebrew packages across multiple machines using a single YAML file.
Managing Homebrew packages with a Brewfile is great, until you're juggling multiple machines. Hops
replaces scattered and duplicated configs with a single YAML declaration.
- ✅ One
hops.ymlconfig for all machines - 📦 Generates a specific
Brewfilefor each machine - 🧹 Prune unused floating packages
- âš¡ Installs, upgrades, and verifies with one command
- 💻 Designed for dotfiles
brewfile: /Users/snape/Brewfile
machines:
shared:
taps:
- homebrew/bundle
formulae:
- coreutils
casks:
- 1password
- raycast
- spotify
personal:
casks:
- adobe-creative-cloud
work:
casks:
- cursor
- loom
- slack
cursor:
- dbaeumer.vscode-eslint
- github.github-vscode-theme
ignore:
- google-chrome# Download the latest release
# Visit → https://github.com/revett/hops/releases
# Extract binary from archive
tar -xzf hops_X.Y.Z_darwin_arm64.tar.gz
# Stop macOS' Gatekeeper from blocking the binary
xattr -c ./hops
# Move binary
sudo mv hops /usr/local/bin
# Verify install
hops -h# Clone repo locally
git clone https://github.com/revett/hops.git
# Build binary
cd hops
make build
# Move binary
sudo mv hops /usr/local/bin
# Verify install
hops -hOptionally set the HOPS_CONFIG environment variable within your terminal profile:
# Defaults to ~/hops.yml if not set
export HOPS_CONFIG=/path/to/hops.ymlInitialise the configuration file:
hops initThis will create a hops.yml with a set of example packages; update these with your desired set of
machines and packages. This config file is designed to sit in your dotfiles and sync across all your
machines.
Apply the configuration for a specific machine:
hops generate --machine work
hops apply --machine workHops will take care of:
- Creating a local
Brewfilemade up of the correct shared and machine specific packages - Install any missing packages
- Update any outdated packages
- Remove any floating packages that are not outlined in the
Brewfile - Leave
ignorepackages alone, even if installed via Homebrew
# Initialize a new hops.yml configuration file with examples
hops init
# Generate a local Brewfile for a specific machine without installing anything
hops generate --machine work
# Generate Brewfile and apply changes via Homebrew commands (install, upgrade, cleanup)
hops apply --machine personal
# Format hops.yml (sort packages A-Z, order sections, 2-space indent)
hops format
# Add to .zshrc to remind every week to run apply command
hops reminderEvery run writes a plain text transcript to ~/.hops.log to help with debugging. It captures
everything: the command output, any errors, and the full live brew bundle stream during apply.
- Enabled by default
- Colour codes are stripped, so the file is clean plain text
- Overwritten on each run, so it only ever holds your most recent run
- A logging failure never stops a command from running
Disable it via hops.yml:
logging: falseSee hops.yml in revett/dotfiles.
Does it support Cursor extensions?
Yes, as part of the v4.5.0 release of Homebrew on 29th
April 2025, the brew bundle command looks for VS Code variants, see
#19545.
How do I stop hops touching a package managed by something else (e.g. an MDM)?
Add it to ignore under shared or the machine. Hops will not install, upgrade, or uninstall it,
and it is hidden from the floating package check.
- Ensure that version in
package.jsonis bumped git tag -a vX.Y.Z -m "Release vX.Y.Z"git push origin vX.Y.Zmake release VERSION=vX.Y.Z- Create release in GitHub
See CLAUDE.md.
