grew is what happens when you look at your package manager and think: "This could be so much simpler." Deterministic installs. Clean symlinks. A doctor that actually tells you what's wrong. No drama.
Formula + cask installs with SHA256 verification (no funny business)
Ed25519 bottle signing β cryptographic signatures verified against a local trust store
Sandboxed builds & post-install β network denied, keg read-only for post-install, minimal env
Install snapshots β per-file SHA256 manifests for tamper detection via grew verify
Lockfile β pin exact versions, hashes, and dependency trees for reproducible environments
Deterministic linking with opt symlinks and dry-run support (look before you link)
Dependency resolver with an optional tree view (for the visually inclined)
Doctor + audit β checks perms, HTTPS, broken links, snapshot integrity, cask notarization, and formula quality
Hardened command execution β POSIX shell quoting via shellescape, -- end-of-options on all external commands, XML-safe plists, systemd specifier escaping
Zip Slip protection β archive extraction validates symlink indirection to prevent writes outside the destination directory
Services, aliases, shellenv β manage daemons, name things your way, wire up your shell
The fastest way β downloads the latest release binary with SHA256 verification:
go install github.com/homegrew/grew/tools/getgrew@latest
getgrew
sudo grew setup
Prerequisites: Go 1.26+, git, and a dream.
git clone https://github.com/homegrew/grew.git
cd grew
make build # or: go generate ./internal/... && go build -o grew
grew needs a home β a directory tree for the Cellar, symlinks, taps, and config:
# User-local install (no root needed) β installs to ~/.grew
./grew setup
# System install (recommended β isolates builds from $HOME)
sudo grew setup # macOS ARM β /opt/grew, Intel/Linux β /usr/local/grew
The system prefix is more secure: sandboxed source builds can't reach ~/.ssh, ~/.gnupg, or other sensitive dotfiles.
# bash (~/.bashrc) or zsh (~/.zshrc)
eval "$(grew shellenv)"
# fish (~/.config/fish/config.fish)
grew shellenv fish | source
grew install jq # the classic
grew install -s ldns # build from source, like a purist
grew install --cask firefox # going big
That's it. No dark rituals. No 47-step setup guide.
grew link jq # stitch it in
grew deps --tree jq # what hath jq wrought
grew upgrade # stay fresh
grew cleanup -n # peek before you sweep
grew verify jq # check installed files against manifest
grew lock # pin your environment
grew audit --strict # lint your formulas
grew doctor # check for common problems
| Command | What it does |
|---|---|
install | Install a formula or cask (-s to build from source) |
uninstall | Send it to the void |
reinstall | Uninstall + install from scratch |
list | See what you've collected |
info | Stalk a package |
search | Find the thing |
link | Weave a formula into your PATH |
unlink | Cut the thread |
update | Refresh tap definitions |
upgrade | Get the new hotness |
outdated | The hall of shame |
cleanup | Marie Kondo your Cellar |
deps | Dependency spelunking |
verify | Check installed packages against their snapshot manifests |
audit | Lint formula/cask definitions for quality and security |
lock | Generate, check, or show a reproducible lockfile |
sign | Sign formula SHA256 hashes with an Ed25519 key |
services | Manage background services (start, stop, restart, list) |
setup | One-time prefix setup (user-local or system-wide with sudo) |
alias | Name things your way |
doctor | It's not a bug, it's a misconfiguration |
config | What grew thinks it knows |
shellenv | Wire up your shell |
help | You got this |
grew keeps its stuff tidy under one roof. Tweak it with env vars:
| Variable | Default | What it is |
|---|---|---|
HOMEGREW_PREFIX | ~/.grew | The kingdom |
HOMEGREW_APPDIR | ~/Applications | Where casks live |
HOMEGREW_TAP_VERIFY | off | Tap commit signature policy (off, warn, strict) |
HOMEGREW_NO_INSTALL_FROM_API | (unset) | Force git clone instead of API tarball for taps |
Everything flows from the prefix:
~/.grew/
βββ Cellar/ β installed packages (each keg has a .MANIFEST.json)
βββ Taps/ β formula definitions (git-cloned or API-fetched)
βββ bin/ β symlinked binaries
βββ etc/ β trusted-keys (Ed25519 public keys, one per line)
βββ tmp/ β ephemeral stuff
βββ grew.lock β lockfile (opt-in, created by `grew lock`)
grew is designed to be more secure than Homebrew out of the box:
| Feature | grew | Homebrew |
|---|---|---|
| Bottle signing | Ed25519 signatures verified against local trust store | None β HTTPS + SHA256 only |
| Tap verification | Optional GPG/SSH commit signature enforcement | None |
| Post-install sandbox | Read-only keg, no network, minimal env | Unsandboxed |
| Source build sandbox | macOS Seatbelt / Linux bwrap+unshare, no network | macOS Seatbelt only, no Linux |
| Install manifests | Per-file SHA256 snapshot at install time | None |
| Lockfile | Full dependency tree with hashes | None |
| Integrity check | grew verify + grew doctor snapshot check | None |
| HTTPS enforcement | At parse time β HTTP URLs rejected before download | At download time |
| Path traversal protection | Validated at cellar, linker, loader, and archive extraction layers | Partial |
| Shell injection prevention | POSIX shell quoting via shellescape for sandbox scripts; systemd and launchd values properly escaped | N/A |
| Zip Slip protection | Symlink indirection attacks blocked during tar/zip extraction | Partial |
| Command argument hardening | -- end-of-options on all external commands (git, systemctl, launchctl, hdiutil, tar, etc.) | Not consistently applied |
Gradual rollout: signature verification doesn't block installs until you add keys to etc/trusted-keys. Tap verification is opt-in via HOMEGREW_TAP_VERIFY. Adopt security features at your own pace.
make check # go test -v -race ./...
make build # go generate + go build
make lint # golangci-lint
Project layout: packages under internal/ (cmd, cellar, formula, cask, linker, depgraph, downloader, tap, sandbox, signing, snapshot, lockfile, service, config, version) and pkg/ (validation).
git checkout -b feature/cool-thing)PRs welcome. Drama not so much.
Acknowledgments: Best-README-Template, and everyone who ever squinted at a wall of package manager output and thought "there has to be a better way".
License: (Add a LICENSE to your repo!)