grew

command module
v0.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 5, 2026 License: MIT Imports: 8 Imported by: 0

README ΒΆ

πŸ₯€ grew

A lean, mean, package-managing machine. In Go.

Go Version

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.

πŸ’¬ A word from the author: I've been a die-hard Homebrew user for longer than I care to admit. brew and I? We go way back. Late nights, broken PATH, the works β€” and I loved every minute of it. I love brew so much, in fact, that I thought: "What if I just… made it better?" Audacious? Absolutely. Foolish? Possibly. Fun? You bet. grew is my love letter to brew β€” written in Go, with a cheeky grin.


✨ What it does

  • πŸ“¦ Formula + cask installs with SHA256 verification (no funny business)
  • 🚰 Tap auto-install β€” automatically clones missing taps when you request user/repo/formula
  • ⚑ Multi-hop binary delta updates β€” selfupdate uses bspatch to seamlessly apply sequences of intermediate patches to reach the latest version, saving bandwidth, with an automated CI patcher tool for releases and -U upgrade path verification
  • πŸ” Dual-hash verification β€” self-updates and release assets are verified against both SHA256 and SHA512 to prevent single-algorithm collision attacks
  • πŸ”’ Sandboxed source builds using macOS Seatbelt to keep your system safe
  • πŸ” Sandboxed post-install scripts β€” keg is read-only, network denied, minimal env (Homebrew runs these unsandboxed)
  • ✍️ Ed25519 bottle signing β€” cryptographic signatures on downloads, verified against a local trust store
  • 🏷️ Signed tap verification β€” refuse or warn on unsigned git commits in tap repos (HOMEGREW_TAP_VERIFY)
  • πŸ“‹ Install snapshots β€” per-file SHA256 manifests (.MANIFEST.json) recorded at install time for integrity verification
  • 🧾 Installation receipts β€” stores build options, dependencies, and provenance metadata (INSTALL_RECEIPT.json) in the keg for future reference
  • πŸ“Œ Lockfile β€” pin exact versions, hashes, and dependency trees for reproducible environments
  • πŸ”— Deterministic linking with opt symlinks and dry-run support (look before you link)
  • πŸ”„ Keg relocation β€” rewrites hardcoded library paths in bottles at install time via install_name_tool, so binaries just work without DYLD_LIBRARY_PATH hacks
  • 🌳 Dependency resolver with an optional tree view (for the visually inclined)
  • 🩺 Doctor that checks perms, HTTPS, broken links, snapshot integrity, stale kegs, and cask notarization
  • πŸ›‘οΈ Hardened command execution β€” -- end-of-options on all external commands, shell-free namespace setup with positional parameters, XML-safe plist generation
  • 🧱 Zip Slip protection β€” archive extraction validates symlink indirection to prevent writes outside the destination
  • πŸ” Vulnerability scanning β€” queries OSV.dev for known CVEs via the vuln-scan command
  • πŸ›‘οΈ macOS Quarantine β€” automatically applies com.apple.quarantine attributes to downloaded apps and binaries, ensuring Gatekeeper protection is active
  • πŸͺ΅ Structured logging via log/slog with CLI-friendly output (DEBUG/INFO/WARN/ERROR levels, -v/-d/-q flags). Debug logs include source file and line number context.
  • 🎨 Colorful output β€” ANSI-colored output with automatic TTY detection for a polished, Homebrew-like aesthetic.
  • 🐚 Alias + shellenv helpers so your workflows stay snappy (i, rm, ls, up, ug, dr)

πŸš€ Getting Started

Get Grew

Download the latest release for your platform from the Releases page, extract it, and run setup:

tar -xzf grew_*.tar.gz
./grew setup
Build from source

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
Set up the prefix

grew needs a home β€” a directory tree for the Cellar, symlinks, taps, and config. The setup command creates it and copies the binary into place:

./grew setup   # macOS ARM β†’ /opt/homegrew, Intel β†’ /usr/local/homegrew

The system prefix isolates sandboxed builds from $HOME, preventing them from reaching ~/.ssh, ~/.gnupg, or other sensitive dotfiles. After setup, ownership is transferred to your user β€” no root needed at runtime.

Wire up your shell

Add this to your shell profile so grew-installed binaries and libraries are available:

# bash (~/.bashrc) or zsh (~/.zshrc)
eval "$(grew shellenv)"

# fish (~/.config/fish/config.fish)
grew shellenv fish | source
Install something
grew i jq                   # 'i' is an alias for 'install'
grew install --cask firefox

That's it. No dark rituals. No 47-step setup guide.


πŸ—‘οΈ Uninstallation

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:

1. Clean up installed packages (Casks and Services):

Uninstall casks and stop services first so grew can clean up /Applications and your service managers (launchd/systemd):

# 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

2. Delete the prefix directory:

  • macOS (Apple Silicon):
    sudo rm -rf /opt/homegrew
    
  • macOS (Intel):
    sudo rm -rf /usr/local/homegrew
    
  • Devmode (User-local install via --unsafe):
    rm -rf ~/.homegrew
    

3. Clean up your shell profile:

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.


πŸ“– Usage

For an in-depth look at how grew installs itself, its self-update mechanism, and the developer mode, check out the Architecture & Technical Details.

grew i jq nmap               # install multiple formulas (alias 'i')
grew install --force jq      # force reinstall even if already installed
grew install -s ldns         # build from source, like a purist
grew install --cask firefox  # going big
grew link jq                 # stitch it in
grew deps --tree jq          # what hath jq wrought
grew up                      # stay fresh (alias 'up' for update)
grew ug                      # upgrade all (alias 'ug')
grew version                 # what are we running
grew autoremove --dry-run    # see which orphaned dependencies would be removed
grew autoremove              # clean up unused dependencies
grew rm --force jq           # uninstall even if not installed (alias 'rm')
grew cleanup -n              # peek before you sweep
grew cleanup --scrub         # aggressive cache cleaning
grew cleanup --prune=7       # remove cache older than a week
grew verify jq               # check installed files against manifest
grew vuln-scan -q            # scan for CVEs and only show critical/high severity findings
grew lock                    # pin your environment
grew audit --strict          # lint your formulas
grew cache                   # show download cache
grew cache jq                # show cache path for jq
grew cache --os=darwin jq    # show cache path for a different OS
grew leaves -r | xargs grew uninstall # uninstall all top-level packages installed on request

πŸ—ΊοΈ Commands

Command What it does
install, i Install formulas or casks (-f to force, -s to build from source)
uninstall, rm Send formulas or casks to the void (-f to ignore missing or errors, delete all versions)
autoremove Uninstall formulae that were only installed as a dependency and are no longer needed (--dry-run supported)
list, ls See what you've collected
leaves [-r] [-p] List installed formulas that are not dependencies of another installed formula
info Stalk packages
search Find the thing
link Weave formulas into your PATH
unlink Cut the thread
update, up Refresh tap definitions
upgrade, ug Get the new hotness
outdated The hall of shame
reinstall Uninstall + install from scratch (--cask, -f without checking for previously installed keg-only or non-migrated versions)
cleanup Remove old versions and prune download cache (-s to scrub all, --prune=DAYS)
deps Dependency spelunking
alias Name things your way
audit Lint formula/cask definitions for quality and security
lock Generate, check, or show a reproducible lockfile
verify Check installed packages against their snapshot manifests
sign Sign formula SHA256 hashes with an Ed25519 key
services Manage background services (start, stop, restart, list)
setup One-time prefix setup
doctor, dr It's not a bug, it's a misconfiguration
vuln-scan Scan installed packages for security vulnerabilities
config What grew thinks it knows
shellenv Wire up your shell
pin / unpin Freeze formulas to prevent upgrades
completion Generate shell completion (bash, zsh, fish)
cache Display download cache root or specific package cache paths (alias --cache)
version Print version and exit
help You got this

βš™οΈ Configuration

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 else flows from the prefix:

/opt/homegrew/              (or /usr/local/homegrew on Intel)
β”œβ”€β”€ 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`)

πŸ› οΈ Development

Go Reference

make test-unit     # run unit tests
make test-smoke    # run quick health checks
make test-integration # run command-level integration tests
make test-e2e      # run full lifecycle E2E tests (takes several minutes)
make check-all     # run all of the above
make dev           # build with 'devmode' tag enabled
Developer mode

Release builds will prompt for elevated privileges to setup the system prefix. For local development you can build with the devmode tag and pass --unsafe to setup to install to ~/.homegrew without root:

make dev
./grew setup --unsafe    # installs to ~/.homegrew as your user
./grew install jq        # works without root

Both gates are required β€” the build tag compiles in the code path, and --unsafe activates it at setup time. Release binaries ignore --unsafe entirely.

Project layout
grew/
β”œβ”€β”€ cmd/              ← standalone command packages (install, upgrade, etc.)
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ auditlog/     ← persistent record of all install/upgrade/tap actions
β”‚   β”œβ”€β”€ bpatch/       ← binary delta patching (using bspatch)
β”‚   β”œβ”€β”€ cache/        ← download cache management and pruning
β”‚   β”œβ”€β”€ cask/         ← cask parsing, Caskroom, and helpers
β”‚   β”œβ”€β”€ cellar/       ← installed package management and cleanup
β”‚   β”œβ”€β”€ cli/          ← shared CLI initialization and command registration
β”‚   β”œβ”€β”€ cmd/          ← legacy command bridge and high-level orchestration
β”‚   β”œβ”€β”€ depgraph/     ← dependency resolution (Kahn's toposort)
β”‚   β”œβ”€β”€ downloader/   ← HTTP download + SHA256/512 + archive extraction
β”‚   β”œβ”€β”€ flags/        ← global CLI flags (-v, -d, -q)
β”‚   β”œβ”€β”€ formula/      ← formula parsing and dependency gathering
β”‚   β”œβ”€β”€ fsutil/       ← filesystem utilities (DiskUsage, PruneEmptyDirs, Lock)
β”‚   β”œβ”€β”€ homebrew/     ← Homebrew JSON API client and compatibility logic
β”‚   β”œβ”€β”€ installer/    ← core installation logic (formula, cask, self-update)
β”‚   β”œβ”€β”€ linkage/      ← dynamic library linkage analysis
β”‚   β”œβ”€β”€ linker/       ← deterministic symlink management
β”‚   β”œβ”€β”€ lockfile/     ← reproducible environment pinning
β”‚   β”œβ”€β”€ osvdev/       ← OSV.dev API client for vulnerability scanning
β”‚   β”œβ”€β”€ quarantine/   ← macOS quarantine attribute and Trash management
β”‚   β”œβ”€β”€ receipt/      ← installation receipt management
β”‚   β”œβ”€β”€ release/      ← grew release management and download helpers
β”‚   β”œβ”€β”€ relocation/   ← keg relocation (rewrite dylib/ELF paths)
β”‚   β”œβ”€β”€ runtime/      ← runtime environment (root detection, prefix, devmode gate)
β”‚   β”œβ”€β”€ sandbox/      ← build + post-install sandboxing (macOS Seatbelt)
β”‚   β”œβ”€β”€ service/      ← background service management
β”‚   β”œβ”€β”€ signing/      ← Ed25519 bottle signing + trust store
β”‚   β”œβ”€β”€ sudo/         ← secure privilege escalation handling
β”‚   β”œβ”€β”€ tap/          ← tap repo management + commit verification
β”‚   └── version/      ← embedded version and helpers
β”œβ”€β”€ pkg/
β”‚   β”œβ”€β”€ config/       ← prefix and path resolution
β”‚   β”œβ”€β”€ context/      ← unified execution context (Context, InstallContext)
β”‚   β”œβ”€β”€ doctor/       ← diagnostic engine and checks
β”‚   β”œβ”€β”€ logger/       ← CLI-friendly log/slog handler with source context
β”‚   β”œβ”€β”€ safepath/     ← safe path manipulation and normalization
β”‚   β”œβ”€β”€ snapshot/     ← per-file manifest capture + integrity verification
β”‚   β”œβ”€β”€ ui/           ← zero-dependency ANSI color and TTY detection
β”‚   └── validation/   ← name/version/SHA256/path validation
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ integration/  ← command-level integration tests
β”‚   β”œβ”€β”€ smoke/        ← quick health checks
β”‚   β”œβ”€β”€ e2e/          ← full lifecycle end-to-end tests
β”‚   β”œβ”€β”€ testbin/      ← test proxy binary source
β”‚   └── testhelper/   ← shared test utilities
β”œβ”€β”€ root.go           ← Root CLI command definition (Grew)
β”œβ”€β”€ main.go           ← CLI entry point
└── tools/            ← genrepo (converter), patcher (delta patch generator)

πŸ” Security Model

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 None
Post-install sandbox Read-only keg, no network, minimal env Unsandboxed
Source build sandbox macOS Seatbelt, no network macOS Seatbelt only
Install manifests Per-file SHA256 snapshot (.MANIFEST.json) at install time None
Installation receipts Provenance and dependency metadata (INSTALL_RECEIPT.json) stored alongside the manifest Metadata stored in INSTALL_RECEIPT.json
Lockfile Full dependency tree with hashes None
Integrity check grew verify + grew doctor snapshot check None
Dual-hash verification Self-updates and release assets use both SHA256 and SHA512 None
Self-update health check Patched binaries are execution-tested in a sandbox before replacement 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 Namespace setup uses positional parameters to eliminate injection risks; systemd ExecStart and launchd plist values properly escaped N/A
Zip Slip protection Symlink indirection attacks blocked during tar/zip extraction Partial
Command argument hardening -- end-of-options separator on all external commands (git, systemctl, launchctl, hdiutil, tar, etc.) Not consistently applied
macOS Quarantine Apply() via LaunchServices for all downloads None
Vulnerability scanning Integrated vuln-scan powered by OSV.dev Requires external gems/tools

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. This lets you adopt security features incrementally.


πŸ—ΊοΈ Roadmap

Got ideas? Bugs? Grievances? β†’ Open an issue

Hot takes on the list:

  • Build vs Runtime Dependency distinction
  • SLSA provenance attestations for bottles
  • Content-addressable bottle storage
  • Windows support (one day, probably, maybe)

🀝 Contributing

  1. Fork it
  2. Branch it (git checkout -b feature/your-cool-thing)
  3. Commit it (git commit -m "Add the cool thing")
  4. Push it (git push origin feature/your-cool-thing)
  5. PR it

PRs welcome. Drama not so much.


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ“¬ Contact


πŸ’› Acknowledgments

  • Best-README-Template β€” the scaffold beneath the scaffold
  • Everyone who ever squinted at a wall of package manager output and thought "there has to be a better way"

Documentation ΒΆ

Overview ΒΆ

Command grew is the entry point for the grew package manager.

Directories ΒΆ

Path Synopsis
cmd
alias
Package alias implements the 'alias' command.
Package alias implements the 'alias' command.
audit
Package audit implements the 'audit' command.
Package audit implements the 'audit' command.
autoremove
Package autoremove implements the 'autoremove' command.
Package autoremove implements the 'autoremove' command.
cache
Package cache implements the 'cache' command.
Package cache implements the 'cache' command.
cleanup
Package cleanup implements the 'cleanup' command.
Package cleanup implements the 'cleanup' command.
completion
Package completion implements the 'completion' command.
Package completion implements the 'completion' command.
config
Package config implements the 'config' command.
Package config implements the 'config' command.
create
Package create implements the 'create' command.
Package create implements the 'create' command.
deps
Package deps implements the 'deps' command.
Package deps implements the 'deps' command.
doctor
Package doctor implements the 'doctor' command.
Package doctor implements the 'doctor' command.
extract
Package extract implements the 'extract' command.
Package extract implements the 'extract' command.
homepage
Package homepage implements the 'homepage' command.
Package homepage implements the 'homepage' command.
info
Package info implements the 'info' command.
Package info implements the 'info' command.
install
Package install implements the 'install' command.
Package install implements the 'install' command.
leaves
Package leaves implements the 'leaves' command.
Package leaves implements the 'leaves' command.
link
Package link implements the 'link' command.
Package link implements the 'link' command.
linkage
Package linkage implements the 'linkage' command.
Package linkage implements the 'linkage' command.
list
Package list implements the 'list' command.
Package list implements the 'list' command.
lock
Package lock implements the 'lock' command.
Package lock implements the 'lock' command.
pin
Package pin implements the 'pin' command.
Package pin implements the 'pin' command.
reinstall
Package reinstall implements the 'reinstall' command.
Package reinstall implements the 'reinstall' command.
resetupdate
Package resetupdate implements the 'reset-update' command.
Package resetupdate implements the 'reset-update' command.
search
Package search implements the 'search' command.
Package search implements the 'search' command.
services
Package services implements the 'services' command.
Package services implements the 'services' command.
setup
Package setup implements the 'setup' command.
Package setup implements the 'setup' command.
shellenv
Package shellenv implements the 'shellenv' command.
Package shellenv implements the 'shellenv' command.
sign
Package sign implements the 'sign' command.
Package sign implements the 'sign' command.
tap
Package tap implements the 'tap' command.
Package tap implements the 'tap' command.
uninstall
Package uninstall implements the 'uninstall' command.
Package uninstall implements the 'uninstall' command.
unlink
Package unlink implements the 'unlink' command.
Package unlink implements the 'unlink' command.
unpin
Package unpin implements the 'unpin' command.
Package unpin implements the 'unpin' command.
untap
Package untap implements the 'untap' command.
Package untap implements the 'untap' command.
update
Package update implements the 'update' command.
Package update implements the 'update' command.
upgrade
Package upgrade implements the 'upgrade' command.
Package upgrade implements the 'upgrade' command.
verify
Package verify implements the 'verify' command.
Package verify implements the 'verify' command.
version
Package version implements the 'version' command.
Package version implements the 'version' command.
vulnscan
Package vulnscan implements the 'vuln-scan' command.
Package vulnscan implements the 'vuln-scan' command.
internal
auditlog
Package auditlog provides a tamper-evident append-only log of grew operations.
Package auditlog provides a tamper-evident append-only log of grew operations.
cli
cmd
flags
Package flags defines global CLI flags shared across all grew commands.
Package flags defines global CLI flags shared across all grew commands.
linkage
Package linkage inspects dynamic library dependencies of installed kegs and classifies them as system, self, other-formula, or broken.
Package linkage inspects dynamic library dependencies of installed kegs and classifies them as system, self, other-formula, or broken.
release
Package release provides helpers for downloading, verifying, and installing grew binary releases from GitHub.
Package release provides helpers for downloading, verifying, and installing grew binary releases from GitHub.
relocation
Package relocation rewrites hardcoded library paths inside Mach-O and ELF binaries after a bottle is poured into the Cellar.
Package relocation rewrites hardcoded library paths inside Mach-O and ELF binaries after a bottle is poured into the Cellar.
tap
pkg
config
Package config provides the central path management and configuration discovery for grew.
Package config provides the central path management and configuration discovery for grew.
context
Package context provides a unified environment for grew commands.
Package context provides a unified environment for grew commands.
doctor
Package doctor provides a diagnostic engine for verifying the health, security, and structural integrity of a grew installation.
Package doctor provides a diagnostic engine for verifying the health, security, and structural integrity of a grew installation.
logger
Package logger configures the default log/slog logger for CLI use.
Package logger configures the default log/slog logger for CLI use.
safepath
Package safepath provides utilities for safe filesystem path manipulation, ensuring that paths remain within expected boundaries and are well-formed.
Package safepath provides utilities for safe filesystem path manipulation, ensuring that paths remain within expected boundaries and are well-formed.
snapshot
Package snapshot provides mechanisms for capturing, storing, and verifying cryptographic manifests of installed software packages (kegs).
Package snapshot provides mechanisms for capturing, storing, and verifying cryptographic manifests of installed software packages (kegs).
ui
validation
Package validation provides utilities for validating package names, versions, and cryptographic checksums.
Package validation provides utilities for validating package names, versions, and cryptographic checksums.
tests
integration
Package tests contains integration and end-to-end (E2E) tests for the grew binary.
Package tests contains integration and end-to-end (E2E) tests for the grew binary.
testbin command
tools
genrepo command
Command genrepo is a unified tool for importing Homebrew formulas and casks into grew-compatible YAML definitions.
Command genrepo is a unified tool for importing Homebrew formulas and casks into grew-compatible YAML definitions.
patcher command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL