HopCLI is a package manager for the terminal. Every install runs as one transaction — downloaded, verified and linked in parallel — and every change is one command away from undone, with no re-download.
Nothing here is a knock on Homebrew — it's the reason a whole generation of developers expects installing a CLI tool to be one line. HopCLI is what that idea looks like designed around a transaction log instead of a mutable prefix.
| Homebrew | hop | |
|---|---|---|
| Refreshing the index | clones or pulls a large git repository of formula files | one conditional HTTP request — usually a 304, done in milliseconds |
| Installing | downloads and links serially, mutating the prefix as it goes | every artifact downloads in parallel, verified before anything touches disk |
| A failed install | can leave a half-linked formula behind | changes nothing — the previous generation stays live until the very last step |
| Undoing a change | not really a supported operation | hop rollback — a symlink swap, ~10ms, no network |
| What a recipe can do | arbitrary Ruby, executed on your machine at install time | a JSON document. hop never executes a recipe — only downloads and unpacks what it names |
| Checksums | present on many formulae, absent on others | every built-in recipe is SHA-256 pinned against bytes hop actually downloaded and tested |
| Project reproducibility | a Brewfile, with no lockfile | hopfile.toml + hop.lock — the second machine gets the same bytes as the first |
| Startup cost | a Ruby interpreter boots on every invocation | a static binary — single-digit milliseconds |
| Leftover dependencies | accumulate; brew autoremove is a separate step you have to remember |
swept automatically the moment nothing needs them anymore |
hop never modifies an installed package. It builds a new, complete snapshot — a generation — and switches to it with one filesystem rename.
Every package hop installs lands in a content-addressed store, named by its own hash: ripgrep-15.2.0-3750b2e9…. That directory is never touched again — not by an upgrade, not by a removal.
An install, upgrade or removal computes an entirely new generation: the full list of what should be on your PATH. Once every artifact is downloaded and verified, hop does the only thing that actually changes your environment — it repoints one symlink, current → profiles/7.
That rename is atomic at the filesystem level. It can't half-happen. Every earlier generation is still sitting on disk, which is the entire mechanism behind hop rollback: pointing the same symlink at an older number.
generation 7 is a symlink target — generations 5 and 6 sit untouched, one rename away
The built-in index isn't hand-typed. A generator resolves each package's latest release, downloads the real artifact, and derives its checksum by opening it — nothing here is guessed. Close to 200 entries come straight from Homebrew's own bottle infrastructure, with their real dependency graphs relocated into hop's own store rather than Homebrew's. Images span more than Linux cloud builds: freebsd-vm, openbsd-vm and netbsd-iso are genuinely non-Linux, fedora-workstation and archlinux-iso are real installer ISOs rather than cloud images, security-focused distros like kali-linux and tails sit alongside everyday ones, and eleven separate macos-* recipes span Lion through Tahoe from Apple's own infrastructure. raspios-lite honestly has no amd64 build at all — Pi hardware is arm64-only, so hop says so. Windows isn't here on purpose: Microsoft's ISOs sit behind an interactive, EULA-gated web flow with no stable checksum manifest, which every other entry in this index deliberately has — that's the line hop stays behind.
hop migrate reads Homebrew's Cellar directly — brew doesn't need to be running, and nothing about your Homebrew installation is touched.
hop installs the overlap under its own store and tells you exactly what to run to retire the Homebrew copies — it never calls brew uninstall for you. Removing software installed by another tool is your decision, not a package manager's.
Built entirely on the Go standard library — no dependency to audit, no toolchain to install beyond Go itself. Works offline the moment it's built: the recipe index is compiled into the binary.
clone and build
$ git clone https://github.com/samuelbanapour/hopcli && cd hop && make build
or, with Go installed
$ go install github.com/samuelbanapour/hopcli/cmd/hop@latest
then put it on PATH
$ eval "$(hop shellenv)" # add to ~/.zshrc