{"id":46634993,"url":"https://github.com/homegrew/grew","last_synced_at":"2026-06-16T03:01:43.020Z","repository":{"id":342795355,"uuid":"1175348132","full_name":"homegrew/grew","owner":"homegrew","description":"A lean, mean, package-managing machine. In Go.","archived":false,"fork":false,"pushed_at":"2026-06-07T00:14:59.000Z","size":48578,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-07T01:13:59.603Z","etag":null,"topics":["brew","cask","casks","formula","go","golang","grew","homebrew","json","macos","package-manager","ruby","shell","swift"],"latest_commit_sha":null,"homepage":"https://homegrew.xyz","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/homegrew.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-07T15:35:06.000Z","updated_at":"2026-06-04T08:52:09.000Z","dependencies_parsed_at":"2026-05-29T09:02:08.153Z","dependency_job_id":null,"html_url":"https://github.com/homegrew/grew","commit_stats":null,"previous_names":["homegrew/grew"],"tags_count":47,"template":false,"template_full_name":null,"purl":"pkg:github/homegrew/grew","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homegrew%2Fgrew","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homegrew%2Fgrew/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homegrew%2Fgrew/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homegrew%2Fgrew/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/homegrew","download_url":"https://codeload.github.com/homegrew/grew/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homegrew%2Fgrew/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34020187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["brew","cask","casks","formula","go","golang","grew","homebrew","json","macos","package-manager","ruby","shell","swift"],"created_at":"2026-03-08T01:10:59.140Z","updated_at":"2026-06-07T12:02:30.950Z","avatar_url":"https://github.com/homegrew.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🥤 grew\n\n\u003e *A lean, mean, package-managing machine. In Go.*\n\n[![Go Version][go-badge]][go-url]\n\n`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.\n\n\u003e 💬 **A word from the author:**\n\u003e *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.*\n\n---\n\n## ✨ What it does\n\n- 📦 **Formula + cask installs** with SHA256 verification (no funny business)\n- 🚰 **Tap auto-install** — automatically clones missing taps when you request `user/repo/formula`\n- ⚡ **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\n- 🔐 **Dual-hash verification** — self-updates and release assets are verified against both SHA256 and SHA512 to prevent single-algorithm collision attacks\n- 🔒 **Sandboxed source builds** using macOS Seatbelt to keep your system safe\n- 🔐 **Sandboxed post-install scripts** — keg is read-only, network denied, minimal env (Homebrew runs these unsandboxed)\n- ✍️ **Ed25519 bottle signing** — cryptographic signatures on downloads, verified against a local trust store\n- 🏷️ **Signed tap verification** — refuse or warn on unsigned git commits in tap repos (`HOMEGREW_TAP_VERIFY`)\n- 📋 **Install snapshots** — per-file SHA256 manifests (`.MANIFEST.json`) recorded at install time for integrity verification\n- 🧾 **Installation receipts** — stores build options, dependencies, and provenance metadata (`INSTALL_RECEIPT.json`) in the keg for future reference\n- 📌 **Lockfile** — pin exact versions, hashes, and dependency trees for reproducible environments\n- 🔗 **Deterministic linking** with opt symlinks and dry-run support (look before you link)\n- 🔄 **Keg relocation** — rewrites hardcoded library paths in bottles at install time via `install_name_tool`, so binaries just work without `DYLD_LIBRARY_PATH` hacks\n- 🌳 **Dependency resolver** with an optional tree view (for the visually inclined)\n- 🩺 **Doctor** that checks perms, HTTPS, broken links, snapshot integrity, stale kegs, and cask notarization\n- 🛡️ **Hardened command execution** — `--` end-of-options on all external commands, shell-free namespace setup with positional parameters, XML-safe plist generation\n- 🧱 **Zip Slip protection** — archive extraction validates symlink indirection to prevent writes outside the destination\n- 🔍 **Vulnerability scanning** — queries OSV.dev for known CVEs via the `vuln-scan` command\n- 🛡️ **macOS Quarantine** — automatically applies `com.apple.quarantine` attributes to downloaded apps and binaries, ensuring Gatekeeper protection is active\n- 🪵 **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.\n- 🎨 **Colorful output** — ANSI-colored output with automatic TTY detection for a polished, Homebrew-like aesthetic.\n- 🐚 **Alias + shellenv helpers** so your workflows stay snappy (`i`, `rm`, `ls`, `up`, `ug`, `dr`)\n\n---\n\n## 🚀 Getting Started\n\n### Get Grew\n\nDownload the latest release for your platform from the [Releases](https://github.com/homegrew/grew/releases/latest) page, extract it, and run setup:\n\n```bash\ntar -xzf grew_*.tar.gz\n./grew setup\n```\n\n### Build from source\n\n**Prerequisites:** Go 1.26+, `git`, and a dream.\n\n```bash\ngit clone https://github.com/homegrew/grew.git\ncd grew\nmake build          # or: go generate ./pkg/... \u0026\u0026 go build -o grew\n```\n\n### Set up the prefix\n\ngrew needs a home — a directory tree for the Cellar, symlinks, taps, and config. The `setup` command creates it and copies the binary into place:\n\n```bash\n./grew setup   # macOS ARM → /opt/homegrew, Intel → /usr/local/homegrew\n```\n\nThe 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.\n\n### Wire up your shell\n\nAdd this to your shell profile so grew-installed binaries and libraries are available:\n\n```bash\n# bash (~/.bashrc) or zsh (~/.zshrc)\neval \"$(grew shellenv)\"\n\n# fish (~/.config/fish/config.fish)\ngrew shellenv fish | source\n```\n\n### Install something\n\n```bash\ngrew i jq                   # 'i' is an alias for 'install'\ngrew install --cask firefox\n```\n\nThat's it. No dark rituals. No 47-step setup guide.\n\n---\n\n## 🗑️ Uninstallation\n\n`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:\n\n**1. Clean up installed packages (Casks and Services):**\n\nUninstall casks and stop services first so `grew` can clean up `/Applications` and your service managers (launchd/systemd):\n\n```bash\n# Stop and remove all background services\nfor s in $(grew services ls | awk 'NR\u003e1 {print $1}'); do grew services stop $s; done\n\n# Uninstall all macOS casks\nfor c in $(grew list --cask | awk '{print $1}'); do grew uninstall --cask $c; done\n```\n\n**2. Delete the prefix directory:**\n\n*   **macOS (Apple Silicon):**\n    ```bash\n    sudo rm -rf /opt/homegrew\n    ```\n*   **macOS (Intel):**\n    ```bash\n    sudo rm -rf /usr/local/homegrew\n    ```\n*   **Devmode (User-local install via `--unsafe`):**\n    ```bash\n    rm -rf ~/.homegrew\n    ```\n\n**3. Clean up your shell profile:**\n\nOpen your shell configuration file (e.g., `~/.zshrc`, `~/.bashrc`, or `~/.config/fish/config.fish`) and remove the line that initializes `grew`:\n\n```bash\n# Remove this line:\neval \"$(/opt/homegrew/bin/grew shellenv)\"\n```\n\nRestart your terminal, and `grew` is completely gone.\n\n---\n\n## 📖 Usage\n\nFor an in-depth look at how `grew` installs itself, its self-update mechanism, and the developer mode, check out the [Architecture \u0026 Technical Details](docs/tech.md).\n\n```bash\ngrew i jq nmap               # install multiple formulas (alias 'i')\ngrew install --force jq      # force reinstall even if already installed\ngrew install -s ldns         # build from source, like a purist\ngrew install --force-bottle jq  # pour a bottle (current or newest macOS), never build\ngrew install --cask firefox  # going big\ngrew link jq                 # stitch it in\ngrew deps --tree jq          # what hath jq wrought\ngrew up                      # stay fresh (alias 'up' for update)\ngrew ug                      # upgrade all (alias 'ug')\ngrew version                 # what are we running\ngrew autoremove --dry-run    # see which orphaned dependencies would be removed\ngrew autoremove              # clean up unused dependencies\ngrew rm --force jq           # uninstall even if not installed (alias 'rm')\ngrew cleanup -n              # peek before you sweep\ngrew cleanup --scrub         # aggressive cache cleaning\ngrew cleanup --prune=7       # remove cache older than a week\ngrew verify jq               # check installed files against manifest\ngrew vuln-scan -q            # scan for CVEs and only show critical/high severity findings\ngrew lock                    # pin your environment\ngrew audit --strict          # lint your formulas\ngrew cache                   # show download cache\ngrew cache jq                # show cache path for jq\ngrew cache --os=darwin jq    # show cache path for a different OS\ngrew leaves -r | xargs grew uninstall # uninstall all top-level packages installed on request\n```\n\n---\n\n## 🗺️ Commands\n\n| Command | What it does |\n|---|---|\n| `install, i` | Install formulas or casks (`-f` to force, `-s` to build from source, `--force-bottle` to force a bottle) |\n| `uninstall, rm` | Send formulas or casks to the void (`-f` to ignore missing or errors, delete all versions) |\n| `autoremove` | Uninstall formulae that were only installed as a dependency and are no longer needed (`--dry-run` supported) |\n| `list, ls` | See what you've collected |\n| `leaves [-r] [-p]` | List installed formulas that are not dependencies of another installed formula |\n| `info` | Stalk packages |\n| `search` | Find the thing |\n| `link` | Weave formulas into your PATH |\n| `unlink` | Cut the thread |\n| `update, up` | Refresh tap definitions |\n| `upgrade, ug` | Get the new hotness |\n| `outdated` | The hall of shame |\n| `reinstall` | Uninstall + install from scratch (`--cask`, `-f` without checking for previously installed keg-only or non-migrated versions) |\n| `cleanup` | Remove old versions and prune download cache (`-s` to scrub all, `--prune=DAYS`) |\n| `deps` | Dependency spelunking |\n| `alias` | Name things your way |\n| `audit` | Lint formula/cask definitions for quality and security |\n| `create \u003curl\u003e` | Scaffold a new formula from a URL (infers name, version, and SHA256) |\n| `homepage \u003cformula\u003e` | Open a formula or cask's homepage in the default browser |\n| `uses \u003cformula\u003e` | Show installed formulae that depend on the specified formula |\n| `tap \u003cuser/repo\u003e` | Add a formula repository |\n| `untap \u003cuser/repo\u003e` | Remove a tapped formula repository |\n| `linkage \u003cformula\u003e` | Inspect dynamic library dependencies for an installed formula |\n| `lock` | Generate, check, or show a reproducible lockfile |\n| `verify` | Check installed packages against their snapshot manifests |\n| `sign` | Sign formula SHA256 hashes with an Ed25519 key |\n| `services` | Manage background services (start, stop, restart, list) |\n| `setup` | One-time prefix setup |\n| `doctor, dr` | It's not a bug, it's a misconfiguration |\n| `vuln-scan` | Scan installed packages for security vulnerabilities |\n| `config` | What grew thinks it knows |\n| `shellenv` | Wire up your shell |\n| `pin` / `unpin` | Freeze formulas to prevent upgrades |\n| `completion` | Generate shell completion (bash, zsh, fish) |\n| `cache` | Display download cache root or specific package cache paths (alias `--cache`) |\n| `version` | Print version and exit |\n| `help` | You got this |\n\n---\n\n## ⚙️ Configuration\n\ngrew keeps its stuff tidy under one roof. Tweak it with env vars:\n\n| Variable | Default | What it is |\n|---|---|---|\n| `HOMEGREW_PREFIX` | *(inferred from binary location)* | Root of the grew tree |\n| `HOMEGREW_APPDIR` | `/Applications` | Where casks live |\n| `HOMEGREW_TAP_VERIFY` | `off` | Tap commit signature policy (`off`, `warn`, `strict`) |\n| `HOMEGREW_ALLOWED_HOSTS` | *(built-in allowlist)* | Additional hosts for SSRF-protected downloads |\n| `HOMEGREW_CLEANUP_MAX_AGE_DAYS` | `120` | Max age in days for cached downloads |\n\nEverything else flows from the prefix:\n\n```\n/opt/homegrew/              (or /usr/local/homegrew on Intel)\n├── Cellar/        ← installed packages (each keg has a .MANIFEST.json)\n├── Taps/          ← formula definitions (git-cloned or API-fetched)\n├── bin/           ← symlinked binaries\n├── lib/           ← symlinked libraries\n├── include/       ← symlinked headers\n├── opt/           ← per-formula keg symlinks\n├── etc/           ← trusted-keys (Ed25519 public keys, one per line)\n├── tmp/           ← ephemeral stuff\n├── var/log/       ← audit log\n└── grew.lock      ← lockfile (opt-in, created by `grew lock`)\n```\n\n---\n\n## 🛠️ Development\n\n[![Go Reference][pkg-badge]][pkg-url]\n\n```bash\nmake test-unit     # run unit tests\nmake test-smoke    # run quick health checks\nmake test-integration # run command-level integration tests\nmake test-e2e      # run full lifecycle E2E tests (takes several minutes)\nmake check-all     # run all of the above\nmake dev           # build with 'devmode' tag enabled\n```\n\n### Developer mode\n\nRelease 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:\n\n```bash\nmake dev\n./grew setup --unsafe    # installs to ~/.homegrew as your user\n./grew install jq        # works without root\n```\n\nBoth gates are required — the build tag compiles in the code path, and `--unsafe` activates it at setup time. Release binaries ignore `--unsafe` entirely.\n\n### Project layout\n\n```\ngrew/\n├── cmd/              ← standalone command packages (install, upgrade, etc.)\n├── pkg/\n│   ├── auditlog/     ← persistent record of all install/upgrade/tap actions\n│   ├── bpatch/       ← binary delta patching (using bspatch)\n│   ├── cache/        ← download cache management and pruning\n│   ├── cask/         ← cask parsing, Caskroom, and helpers\n│   ├── cellar/       ← installed package management and cleanup\n│   ├── cli/          ← shared CLI initialization and command registration\n│   ├── cmd/          ← legacy command bridge and high-level orchestration\n│   ├── depgraph/     ← dependency resolution (Kahn's toposort)\n│   ├── downloader/   ← HTTP download + SHA256/512 + archive extraction\n│   ├── flags/        ← global CLI flags (-v, -d, -q)\n│   ├── formula/      ← formula parsing and dependency gathering\n│   ├── fsutil/       ← atomic file writes, safe tree copies, advisory locking, mode sanitization\n│   ├── homebrew/     ← Homebrew JSON API client and compatibility logic\n│   ├── installer/    ← core installation logic (formula, cask, self-update)\n│   ├── linkage/      ← dynamic library linkage analysis\n│   ├── linker/       ← deterministic symlink management\n│   ├── lockfile/     ← reproducible environment pinning\n│   ├── osvdev/       ← OSV.dev API client for vulnerability scanning\n│   ├── quarantine/   ← macOS quarantine attribute and Trash management\n│   ├── receipt/      ← installation receipt management\n│   ├── release/      ← grew release management and download helpers\n│   ├── relocation/   ← keg relocation (rewrite dylib/ELF paths)\n│   ├── runtime/      ← runtime environment (root detection, prefix, devmode gate)\n│   ├── sandbox/      ← build + post-install sandboxing (macOS Seatbelt)\n│   ├── service/      ← background service management\n│   ├── signing/      ← Ed25519 bottle signing + trust store\n│   ├── sudo/         ← secure privilege escalation handling\n│   ├── tap/          ← tap repo management + commit verification\n│   ├── config/       ← prefix and path resolution\n│   ├── context/      ← unified execution context (Context, InstallContext)\n│   ├── doctor/       ← diagnostic engine and checks\n│   ├── logger/       ← CLI-friendly log/slog handler with source context\n│   ├── safepath/     ← path traversal and Zip Slip protection (SafeJoin, CleanPath, etc.)\n│   ├── snapshot/     ← per-file manifest capture + integrity verification\n│   ├── validation/   ← name/version/SHA256/path validation\n│   └── version/      ← embedded version and helpers\n├── tests/\n│   ├── integration/  ← command-level integration tests\n│   ├── smoke/        ← quick health checks\n│   ├── e2e/          ← full lifecycle end-to-end tests\n│   ├── testbin/      ← test proxy binary source\n│   └── testhelper/   ← shared test utilities\n├── root.go           ← Root CLI command definition (Grew)\n├── main.go           ← CLI entry point\n└── tools/            ← genrepo (converter), patcher (delta patch generator)\n```\n\n---\n\n## 🔐 Security Model\n\ngrew is designed to be more secure than Homebrew out of the box:\n\n| Feature | grew | Homebrew |\n|---|---|---|\n| **Bottle signing** | Ed25519 signatures verified against local trust store | None — relies on HTTPS + SHA256 only |\n| **Tap verification** | Optional GPG/SSH commit signature enforcement | None |\n| **Post-install sandbox** | Read-only keg, no network, minimal env | Unsandboxed |\n| **Source build sandbox** | macOS Seatbelt, no network | macOS Seatbelt only |\n| **Install manifests** | Per-file SHA256 snapshot (`.MANIFEST.json`) at install time | None |\n| **Installation receipts** | Provenance and dependency metadata (`INSTALL_RECEIPT.json`) stored alongside the manifest | Metadata stored in `INSTALL_RECEIPT.json` |\n| **Lockfile** | Full dependency tree with hashes | None |\n| **Integrity check** | `grew verify` + `grew doctor` snapshot check | None |\n| **Dual-hash verification** | Self-updates and release assets use both SHA256 and SHA512 | None |\n| **Self-update health check** | Patched binaries are execution-tested in a sandbox before replacement | None |\n| **HTTPS enforcement** | At parse time — HTTP URLs rejected before download | At download time |\n| **Path traversal protection** | Validated at cellar, linker, loader, and archive extraction layers | Partial |\n| **Shell injection prevention** | Namespace setup uses positional parameters to eliminate injection risks; systemd `ExecStart` and launchd plist values properly escaped | N/A |\n| **Zip Slip protection** | Symlink indirection attacks blocked during tar/zip extraction | Partial |\n| **Command argument hardening** | `--` end-of-options separator on all external commands (`git`, `systemctl`, `launchctl`, `hdiutil`, `tar`, etc.) | Not consistently applied |\n| **macOS Quarantine** | `Apply()` via LaunchServices for all downloads | None |\n| **Vulnerability scanning** | Integrated `vuln-scan` powered by OSV.dev | Requires external gems/tools |\n\n**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.\n\n---\n\n## 🗺️ Roadmap\n\nGot ideas? Bugs? Grievances? → [Open an issue](https://github.com/homegrew/grew/issues)\n\nHot takes on the list:\n- Build vs Runtime Dependency distinction\n- SLSA provenance attestations for bottles\n- Content-addressable bottle storage\n- Windows support (one day, probably, maybe)\n\n---\n\n## 🤝 Contributing\n\n1. Fork it\n2. Branch it (`git checkout -b feature/your-cool-thing`)\n3. Commit it (`git commit -m \"Add the cool thing\"`)\n4. Push it (`git push origin feature/your-cool-thing`)\n5. PR it\n\nPRs welcome. Drama not so much.\n\n---\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n---\n\n## 📬 Contact\n\n- 🐛 [Open an issue](https://github.com/homegrew/grew/issues)\n- 🔗 [Project on GitHub](https://github.com/homegrew/grew)\n\n---\n\n## 💛 Acknowledgments\n\n- [Best-README-Template](https://github.com/othneildrew/Best-README-Template) — the scaffold beneath the scaffold\n- Everyone who ever squinted at a wall of package manager output and thought *\"there has to be a better way\"*\n\n[go-badge]: https://img.shields.io/badge/go-1.26-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white\n[go-url]: https://go.dev\n[pkg-badge]: https://pkg.go.dev/badge/github.com/homegrew/grew.svg\n[pkg-url]: https://pkg.go.dev/github.com/homegrew/grew\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhomegrew%2Fgrew","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhomegrew%2Fgrew","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhomegrew%2Fgrew/lists"}