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 dual SHA-256/512 verification (no funny business)
Tap auto-install β automatically clones missing taps when you request user/repo/formula
Multi-hop binary delta updates β selfupdate applies sequences of intermediate patches to reach the latest version seamlessly
Ed25519 bottle signing β cryptographic signatures verified against a local trust store
Sandboxed builds & post-install β macOS Seatbelt enforcement, network denied, keg read-only for post-install
Install snapshots β per-file SHA-256 manifests (.MANIFEST.json) recorded at install time for integrity verification
Lockfile β pin exact versions, hashes, and dependency trees for reproducible environments
Keg relocation β rewrites hardcoded library paths in bottles at install time via install_name_tool or patchelf
Doctor + audit β checks perms, HTTPS, broken links, snapshot integrity, and formula quality
Vulnerability scanning β queries OSV.dev for known CVEs via the integrated vuln-scan command
macOS Quarantine β automatically applies com.apple.quarantine attributes to downloaded apps and binaries
Colorful output β ANSI-colored output with automatic TTY detection for a polished aesthetic
Zip Slip protection β archive extraction validates symlink indirection to prevent writes outside the destination
Installation receipts β stores build options, dependencies, and provenance metadata in the keg
Structured logging via log/slog with CLI-friendly output β DEBUG, INFO, WARN, ERROR levels
Alias + shellenv helpers β manage daemons, name things your way, and wire up your shell with snappy aliases
Download the latest release for your platform, extract it, and run setup:
# Download from GitHub Releases
tar -xzf grew_*.tar.gz
./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:
sudo ./grew setup # macOS ARM β /opt/homegrew, Intel/Linux β /usr/local/homegrew
Developer builds (make dev) can install to ~/.homegrew without root using ./grew setup --unsafe.
# bash (~/.bashrc) or zsh (~/.zshrc)
eval "$(grew shellenv)"
# fish (~/.config/fish/config.fish)
grew shellenv fish | source
grew i jq # 'i' is an alias for 'install'
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 up # stay fresh (alias for update)
grew ug # upgrade all (alias for upgrade)
grew autoremove # clean up unused dependencies
grew verify jq # check installed files against manifest
grew vuln-scan # scan for CVEs and integrity issues
grew lock # pin your environment
grew audit --strict # lint your formulas
grew dr # check for common problems (alias for doctor)
grew stores most of its data in its prefix directory, but some items (like Cask applications and background services) are linked to system directories. To completely remove grew and all of its traces:
# Stop and remove all background services
for s in $(grew services ls | awk 'NR>1 {print $1}'); do grew services stop $s; done
# Uninstall all macOS casks
for c in $(grew list --cask | awk '{print $1}'); do grew uninstall --cask $c; done
# macOS (Apple Silicon):
sudo rm -rf /opt/homegrew
# macOS (Intel) & Linux:
sudo rm -rf /usr/local/homegrew
# Devmode (User-local install via --unsafe):
rm -rf ~/.homegrew
Open your shell configuration file (e.g., ~/.zshrc, ~/.bashrc, or ~/.config/fish/config.fish) and remove the line that initializes grew:
# Remove this line:
eval "$(/opt/homegrew/bin/grew shellenv)"
Restart your terminal, and grew is completely gone.
| Command | What it does |
|---|---|
install, i | Install a formula or cask (-s to build from source, -f to force) |
uninstall, rm | Send it to the void (-f to ignore missing) |
autoremove | Uninstall formulae that are no longer needed (no longer a dependency) |
reinstall | Uninstall + install from scratch |
list, ls | See what you've collected |
leaves | List installed formulas that are not dependencies of others |
info, abv | Stalk a package |
search | Find the thing |
link | Weave a formula into your PATH |
unlink | Cut the thread |
update, up | Refresh tap definitions |
upgrade, ug | Get the new hotness |
outdated | The hall of shame |
cleanup | Marie Kondo your Cellar (--scrub for aggressive cleaning) |
deps | Dependency spelunking (--tree for the visual view) |
verify | Check installed packages against their snapshot manifests |
vuln-scan | Scan installed packages for security vulnerabilities (OSV.dev) |
audit | Lint formula/cask definitions for quality and security |
lock | Generate, check, or show a reproducible lockfile |
sign | Sign formula checksums with an Ed25519 key |
services | Manage background services (start, stop, restart, list) |
setup | One-time prefix setup (requires sudo unless --unsafe) |
alias | Name things your way |
doctor, dr | It's not a bug, it's a misconfiguration |
pin / unpin | Freeze a formula to prevent upgrades |
completion | Generate shell completion (bash, zsh, fish) |
config | What grew thinks it knows |
shellenv | Wire up your shell |
version | Print version and exit |
--cache | Display download cache root or specific package paths |
help | You got this |
grew keeps its stuff tidy under one roof. Tweak it with env vars:
| Variable | Default | What it is |
|---|---|---|
HOMEGREW_PREFIX | (inferred from binary location) | Root of the grew tree |
HOMEGREW_APPDIR | /Applications | Where casks live |
HOMEGREW_TAP_VERIFY | off | Tap commit signature policy (off, warn, strict) |
HOMEGREW_ALLOWED_HOSTS | (built-in allowlist) | Additional hosts for SSRF-protected downloads |
HOMEGREW_CLEANUP_MAX_AGE_DAYS | 120 | Max age in days for cached downloads |
Everything flows from the prefix:
/opt/homegrew/ (or /usr/local/homegrew on Intel/Linux)
βββ Cellar/ β installed packages (each keg has a .MANIFEST.json)
βββ Taps/ β formula definitions (git-cloned or API-fetched)
βββ bin/ β symlinked binaries
βββ lib/ β symlinked libraries
βββ include/ β symlinked headers
βββ opt/ β per-formula keg symlinks
βββ etc/ β trusted-keys (Ed25519 public keys, one per line)
βββ tmp/ β ephemeral stuff
βββ var/log/ β audit log
βββ 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 β relies on HTTPS + SHA256 only |
| Tap verification | Optional GPG/SSH commit signature enforcement (HOMEGREW_TAP_VERIFY) | None |
| Post-install sandbox | Read-only keg, no network, minimal env | Unsandboxed |
| Source build sandbox | macOS Seatbelt / Linux namespaces, no network | macOS Seatbelt only, no Linux sandbox |
| Dual-hash verification | Self-updates and assets use both SHA256 and SHA512 | SHA256 only |
| Self-update health check | Patched binaries are execution-tested in a sandbox before replacement | None |
| Install manifests | Per-file SHA256 snapshot (.MANIFEST.json) at install time | None |
| Installation receipts | Provenance and dependency metadata stored alongside the manifest | Metadata stored in INSTALL_RECEIPT.json |
| Lockfile | Full dependency tree with exact hashes | None |
| Integrity check | grew verify + grew doctor snapshot check | None |
| Vulnerability scanning | Integrated vuln-scan via OSV.dev | None (requires external tools) |
| macOS Quarantine | Automatically applies com.apple.quarantine to all downloads | None |
| HTTPS enforcement | At parse time β HTTP URLs rejected before download | At download time |
| Path traversal protection | Validated at cellar, linker, and archive extraction layers | Partial |
| Shell injection prevention | Namespace setup uses positional parameters; systemd/launchd values escaped | N/A |
| Zip Slip protection | Symlink indirection attacks blocked during extraction | Partial |
| Command hardening | -- end-of-options on all external commands (git, tar, etc.) | Not consistently applied |
Gradual rollout: signature verification doesn't block installs until you add keys to etc/trusted-keys. Adopt security features at your own pace.
make check # go test -v -race ./...
make build # go generate + go build
make dev # devmode build (user-local)
make lint # golangci-lint
Developer builds (make dev) can install to ~/.homegrew without root using grew setup --unsafe. See the README for details.
grew ships with a standalone patcher tool to generate and verify multi-hop binary updates:
patcher -v -D dist/ v1.0 v1.1 # Generate patches
patcher -U v1.0 v1.2 # Verify upgrade path
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!)