CHANGELOG
Changelog
All notable changes to zerobrew will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[Unreleased]
Changed
- Bump MSRV to 1.96, required to build the latest
cargo-audit in CI (#393)- Refresh
Cargo.lock for audit findings: crossbeam-epoch (RUSTSEC-2026-0204), quinn-proto (RUSTSEC-2026-0185), and anyhow (RUSTSEC-2026-0190) (#393)Fixed
- Relink on upgrade/reinstall: symlinks owned by another version of the same formula — including dangling links left behind by removed kegs — are now replaced during linking instead of failing the link step as conflicts with the formula itself, which left
bin/opt pointing at the old version while the DB reported the new one (#393)[0.3.2] - 2026-06-11
Security
- Verify SHA-256 checksums for resource and URL patch downloads in the formula build shim before extraction or application (CVE-2026-53970)
[0.3.1] - 2026-05-30
Fixed
- Centralize a single, sandbox-tolerant rustls
ClientConfig in network::tls: prefer native roots, and fall back to the bundled webpki-roots Mozilla roots when no system trust store is available (#375)- Correct migration behavior on unplannable formulas (#380)
Changed
- Clarify standalone installer shell setup and update flow: surface
zb init output, print shell-specific reload commands after shell config changes, print exact export/fish commands for --no-modify-path, report installed/updated/already-current status on reruns, and warn when an older zb still appears earlier in PATH (#381)- Clarify
zb update help/output and README update docs so users know zb update refreshes package metadata while the installer or Homebrew updates the zb binary itself (#381)[0.3.0] - 2026-05-29
Added
- Eleventy-based homepage with responsive styling, interactive panels, benchmark/install content, and site assets (#309)
-
zb doctor command with --repair flag for state diagnosis, recovery, orphaned store entries, and broken symlinks (#314)- Chinese translation of the README (#316)
-
zb upgrade command to upgrade installed packages, with --build-from-source and --no-link flags; supports upgrading all outdated packages or specific ones by name (#369)Fixed
- Validate root/prefix paths before passing to sudo to prevent shell injection (#311)
- Regex matches only version segments within Cellar-style paths when patching Mach-O binary strings (#317)
- Update vulnerable
aws-lc-sys, aws-lc-rs, and rustls-webpki dependencies (#318)- Make
just fmt apply formatting and document the workflow (#319)- Resolve formula aliases and oldnames after API 404s (#332)
- Skip linking
libexec Python site-packages paths to avoid conflicts (#368)- Make
zb upgrade clean old cellar metadata, stay idempotent after download failures, and exit non-zero for missing requested packages (#369)- Ignore stale macOS prefix environment defaults when initializing or resolving paths (#372)
- Resolve Linux
uses_from_macos dependencies, rewrite Linuxbrew bottle paths, and restrict Linux bottle fallback by architecture (#373)Changed
- Split monolithic install module into focused submodules (#312)
- Split monolithic download module into focused submodules (#313)
- Document Homebrew tap installation as an alternative install method (#325)
- Refresh dependency lockfile entries (#330)
- Make migration install only leaf formulae from Homebrew (#333)
- Prefer direct Homebrew install instructions in README files (#337)
- Refresh
Cargo.lock for audit findings (#345, #363)- Pin release workflow Ubuntu runners to 22.04 for stability (#352)
- Add CLI help text for command arguments and flags (#355)
- Add and then revert the security scanning workflow (#354, #358)
[0.2.1] - 2026-03-14
Fixed
- Fix
zb outdated panic caused by clap type mismatch between global verbose (u8 count) and subcommand verbose (bool) flags (#308)[0.2.0] - 2026-03-12
Added
- Batch processing for
zb migrate command (#285)-
zb outdated command with --quiet/--verbose/--json output modes (#266)-
zb update command (#266)- Tracing-based internal logging with
-v/--verbose and -q/--quiet flags (#275)- Configurable UI theme and writer-based output layer (#274)
- Fuzzy formula suggestions on missing package errors (#279)
-
ZEROBREW_API_URL support and persistent API cache (#252)- Build provenance attestation in release workflow (#247)
Fixed
- Added SQLite schema versioning with sequential migrations and downgrade protection(#305)
- Global lock on installer to prevent concurrent install corruption (#304)
- Strip zerobrew's bin paths from
PATH during install to prevent dyld errors on re-install (#289)- Warn when Mach-O in-place patching is skipped due to prefix length mismatch (Intel Mac) (#286)
- Prefer compatible macOS bottle tags over newer ones (#283)
- Ruby syntax backwards compatibility for source builds (#282)
- Skip extraction on raw binaries and copy to keg bin dir directly (#278)
- Chunked download robustness and memory efficiency (#270)
- Skip libexec virtualenv metadata links to avoid cross-formula conflicts (#248)
- Link formulas on Linux when Homebrew marks them keg-only (#249)
- Preprocess resolver before parsing (#244)
Changed
- Eliminate unwraps, reduce allocations, decompose install path (#292)
- Removed
--yes alias from global --auto-init flag (#287)[0.1.2] - 2026-02-15
Added
- Local source build fallback — compile packages from source when no bottle is available (#212)
-
--build-from-source / -s flag for zb install (#212)- External tap and cask support with safer install/uninstall behavior (#203)
- GitHub release installs with clone fallback (#198)
- Source-only tap formula support with scoped parsing (#232)
- Resolve tap formulas from
Formula/, HomebrewFormula/, and repo root (#231)-
zb bundle dump subcommand with Brewfile syntax support (#218)Fixed
- Include zbx binaries in GitHub releases (#229)
- Preserve execute bit when patching Mach-O binary strings (#228)
- Skip patching when new prefix is longer than old (#227)
- Prevent bricked installs from link conflicts, respect keg-only formulas (#207)
- Default macOS prefix to
/opt/zerobrew to stay within the 13-char Mach-O path limit (#206)- Shell init management and fish support (#200)
- Remove
-D flag from install since directories are already created (#221)- Force static liblzma linking and verify macOS binaries (#222)
- Formula token normalization across crates (#230)
- Default macOS prefix to root on install scripts (#239)
Changed
- Refreshed README with banner and star history (#224)
[0.1.1] - 2026-02-08
Initial release of zerobrew - a fast, modern package manager. We're excited for our pilot release and
want to thank all of the support from all channels, as well as all of our contributors up to this point.
To get an idea of the initial features zerobrew supports, take a look at the README.
See the full commit history for more details.
[Unreleased]: https://github.com/lucasgelfond/zerobrew/compare/v0.3.2...HEAD
[0.3.2]: https://github.com/lucasgelfond/zerobrew/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/lucasgelfond/zerobrew/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/lucasgelfond/zerobrew/compare/v0.2.1...v0.3.0
[0.2.1]: https://github.com/lucasgelfond/zerobrew/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/lucasgelfond/zerobrew/compare/v0.1.2...v0.2.0
[0.1.2]: https://github.com/lucasgelfond/zerobrew/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/lucasgelfond/zerobrew/releases/tag/v0.1.1
---
CONTRIBUTING
Contributing to zerobrew
Thanks for your interest in contributing to zerobrew! This document provides guidelines for contributing to the project.
Licensing
By contributing to zerobrew, you agree your contributions will be dual-licensed under either Apache OR MIT, at the licensee's choice.
Soft Prerequisites
- Rust 1.90 or later
- Access to either a macOS or Linux machine
A note on LLM usage
While we encourage the use of LLM's for thinking through problems, helping with tests, and even writing code, we simply
cannot accept or tolerate PRs with no clear guidance or thought put into them.
_Please understand_ that we reserve the right to simply close your PR if it exhibits clear indicators
of heavy LLM usage. We understand you are excited to contribute but the code must reach a level of quality
that's typically achieved through thoughtful engagement in the community and the issues/agenda of zerobrew- NOT
by throwing a prompt into an LLM and opening a PR with no direction.
If you ever need help or want to walk through an issue or idea that you have with one of the maintainers, feel free to join
the community discord; we would be more than happy to assist you.
Project Structure
zerobrew is organized as a Cargo workspace with three crates:
- zb_core: Core data models and domain logic (formula resolution, bottle selection)
- zb_io: I/O operations (API client, downloads, extraction, installation)
- zb_cli: Command-line interface
Any changes you make that touch several crates should be organized properly. See commit hygiene
General Development Workflow
We prefer that a PR is linked to an open issue or previously discussed through other channels.
If you are introducing changes that aren't otherwise reported or tracking please either reach
out in the Discord to give us a heads up or open an issue first to discuss your changes.
General flow:
1. Fork the repo
2. Make your changes and ensure, at the _least_:
- Code is formatted: cargo fmt --all
- No clippy warnings: cargo clippy --workspace --all-targets -- -D warnings
- Unit tests pass: cargo test --workspace
- Integration tests pass: cargo test --workspace -- --ignored (or just test for all tests)
These will run in CI but it's best you clean up your code _before_ opening a PR to ensure a quick
turnaround!
Using Just
This project includes a Justfile, Install just and use these commands instead of cargo (for ease of development):
- just build Check formatting, lint, then build the binary (Builds debug binary)
- just install Build and install zb to $HOME/.local/bin (Customizable with $ZEROBREW_BIN)
- just uninstall Remove all zerobrew installations and configurations
- just fmt Format code with rustfmt
- just fmt-check Check code formatting
- just lint Run clippy with strict warnings
- just test Run all workspace tests (unit & integration)
Before creating a PR make sure you build your changes and test them.
3. Write tests for new functionality. Each module should have accompanying tests.
4. Commit your changes with clear, descriptive commit messages (see below)
5. Push to your fork and submit a pull request.
Commit hygiene
We ask that you follow the format below for commits:
fix / feat: descriptionfor instance:
fix(zb_cli): foo bar moo bazAllowed prefixes:
fix # -> fixes a bug or regression
feat # -> new feature
chore # -> housekeeping (deps, typos in docs, etc.)
tests # -> added, changed or removed tests
ci # -> changes to ci
refactor # -> refactored code
perf # -> performance related
build # -> changes to build system (i.e. ext deps, tooling, scripts, etc)Generally speaking, we also ask that you please write isolated, atomic commits.
This means if you are approaching a PR that touches various parts of the codebase for example, ensure that your commits
are contained and cleanly seperated, properly describing/notating which commits belong where.
Testing
- Unit tests should be colocated with the code in mod tests blocks
- Use tempfile for filesystem tests
- Use wiremock for HTTP mocking in integration tests
- Tests should be deterministic and not rely on external network access
Running Benchmarks
To benchmark performance:
just bench --fullThis runs a 100-package installation suite comparing zerobrew to Homebrew. This is especially crucial to run if you are
planning on contributing to performance/optimization related changes.
Useful options:
just bench --quick
just bench --dry-run
just bench --full results/
just bench --format csv --output benchmark.csv
just bench --log bench.logNotes:
- Defaults to the quick package list (22 packages); use --full for all 100.
- --full [dir] writes all formats (txt/json/csv/html) to the directory.
- --output infers format from file extension when --format is omitted.
- Output includes cold + warm cache speedups per package.
macOS Homebrew permissions
On macOS, Homebrew should be installed with a user-writable prefix. If just bench fails with a permission error, fix it by running:
sudo chown -R "$(whoami)" "$(brew --prefix)"Questions?
For further questions, open an issue on GitHub.
---
README
<div align="center">
<h2>zerobrew</h2>
<p align="center">
<strong>English</strong> ·
<a href="README.zh.md">中文</a>
</p>
[](https://github.com/lucasgelfond/zerobrew/actions/workflows/ci.yml)
[](https://github.com/lucasgelfond/zerobrew/actions/workflows/test.yml)
[](https://github.com/lucasgelfond/zerobrew/releases)
[](https://discord.gg/ZaPYwm9zaw)
[](./LICENSE-MIT.md)
[](./LICENSE-APACHE.md)
<img alt="zerobrew demo" src="./assets/zb-demo.gif" />
<p><strong>zerobrew brings uv-style architecture to Homebrew packages on macOS and Linux.</strong></p>
</div>
Install
curl -fsSL https://zerobrew.rs/install | bashThe installer updates your shell config. After it finishes, restart your terminal
or run the source command it prints.
Or via Homebrew:
brew install lucasgelfond/zerobrew/zerobrewUpdate zerobrew
If you used the standalone installer, rerun it:
curl -fsSL https://zerobrew.rs/install | bash
zb --versionIf you installed with Homebrew:
brew update && brew upgrade zerobrewQuick start
zb install jq # install one package
zb install wget git # install multiple
zb bundle # install from Brewfile
zb bundle install -f myfile # install from custom file
zb bundle dump # export installed packages to Brewfile
zb bundle dump -f out --force # dump to custom file (overwrite)
zb uninstall jq # uninstall one package
zb outdated # list packages with newer versions
zb upgrade # upgrade all outdated packages
zb upgrade jq wget # upgrade specific packages
zb reset # uninstall everything
zb gc # garbage collect unused store entries
zbx jq --version # run without linkingPerformance snapshot
<div align="center">
| Package | Homebrew | ZB (cold) | ZB (warm) | Cold Speedup | Warm Speedup |
|---------|----------|-----------|-----------|--------------|--------------|
| Overall (top 100) | 452s | 226s | 59s | 2.0x | 7.6x |
| ffmpeg | 3034ms | 3481ms | 688ms | 0.9x | 4.4x |
| libsodium | 2353ms | 392ms | 130ms | 6.0x | 18.1x |
| sqlite | 2876ms | 625ms | 159ms | 4.6x | 18.1x |
| tesseract | 18950ms | 5536ms | 643ms | 3.4x | 29.5x |
</div>
Relationship with Homebrew
zerobrew is more of a performance-optimized client for the Homebrew ecosystem. We rely on:
- Homebrew's formula definitions (homebrew-core)
- Homebrew's pre-built bottles when available
- Homebrew's package metadata and infrastructure
Our innovations focus on:
- Content-addressable storage for deduplication
- APFS clonefiles for zero-overhead copying
- Source build fallback using Homebrew's Ruby DSL
zerobrew is experimental. We recommend running it alongside Homebrew rather than as a replacement, and do _not_
recommend purging homebrew and replacing it with zerobrew unless you are absolutely sure about the implications of
doing so.
Project status
<div align="center">
<a href="https://star-history.com/#lucasgelfond/zerobrew&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=lucasgelfond/zerobrew&type=Date&theme=dark" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=lucasgelfond/zerobrew&type=Date" />
</picture>
</a>
</div>
- Status: Experimental, but already useful for many common Homebrew formulas.
- Feedback: If you hit incompatibilities, please open an issue or PR.
- License: Dual-licensed under Apache 2.0 OR MIT, at your choice.
---
SECURITY
Security Policy
Supported Versions
We take security seriously and provide security updates for the latest version zerobrew.
We strongly recommend keeping your zerobrew dependencies up to date.
Reporting a Vulnerability
Please do not report security vulnerabilities through public GitHub issues.
If you discover a security vulnerability in nmrs or any of the related crates, please report it privately by emailing
lucas.gelfondATgmail.com.
Please include the following information in your report:
- A clear description of the vulnerability
- Steps to reproduce the issue
- Potential impact and attack scenarios
- Any suggested fixes or mitigations
- Your contact information for follow-up questions
What constitutes a security vulnerability?
For zerobrew, security vulnerabilities may include but are not limited to:
- Package substitution: Ability to install malicious packages by manipulating formula resolution or tap priority
- Privilege escalation: Unauthorized access to system directories or operations that should require elevated permissions
- Credential exposure: Leaking API tokens, tap credentials, or other sensitive data through logs, errors, or memory
- Path traversal: Malicious bottle archives that could write files outside the intended cellar/store directories
- Denial of service: Crashes, hangs, or resource exhaustion that prevent legitimate package management
- Information disclosure: Exposing installed packages, store paths, or system configuration to unauthorized processes
- Input validation failures: Improper handling of malformed formula names, tap references, or bottle data leading to undefined behavior
- Race conditions: Timing vulnerabilities in concurrent downloads, extraction, or linking that could lead to security issues
- Checksum bypass: Ability to install packages without proper SHA256 verification or with manipulated checksums
- Symlink attacks: Malicious symlinks in bottles that could overwrite system files during materialization or linking
- Dependency confusion: Installing malicious packages by exploiting tap resolution order or dependency specifications
- Supply chain attacks: Compromised taps or formula sources serving backdoored bottles
- Arbitrary code execution: Malicious bottles containing executables that run with user privileges during installation
- Dependency vulnerabilities: Security issues in upstream crates (reqwest, tokio, tar, etc.) that affect zerobrew
For the CLI specifically:
- Command injection: Malicious formula names or tap references that could execute unintended shell commands
- File system access: Unauthorized reading or writing of files outside the intended root/prefix directories
Response Timeline
We are committed to responding to security reports promptly:
- Acknowledgment: We will acknowledge receipt of your vulnerability report within
24 hours
- Initial assessment: We will provide an initial assessment of the report within
5 business days
- Regular updates: We will provide progress updates at least every 7 days until
resolution
- Resolution: We aim to provide a fix or mitigation within 30 days for critical
vulnerabilities
Response times may vary based on the complexity of the issue and availability of maintainers.
Disclosure Policy
We follow a coordinated disclosure process:
1. Private disclosure: We will work with you to understand and validate the vulnerability
2. Fix development: We will develop and test a fix in a private repository if necessary
3. Coordinated release: We will coordinate the public disclosure with the release of a fix
4. Public disclosure: After a fix is available, we will publish a security advisory
We request that you:
- Give us reasonable time to address the vulnerability before making it public
- Avoid accessing or modifying data beyond what is necessary to demonstrate the vulnerability
- Act in good faith and avoid privacy violations or destructive behavior
Security Advisories
Published security advisories will be available through:
- GitHub Security Advisories on the
zerobrew repository
- RustSec Advisory Database
- Release notes and changelog entries
Recognition
We appreciate the security research community's efforts to improve the security of zerobrew. With
your permission, we will acknowledge your contribution in:
- Security advisories
- Release notes
- Project documentation
If you prefer to remain anonymous, please let us know in your report.
Scope
This security policy covers zerobrew wholly.
Additional Resources
- Contributing Guidelines
- Code of Conduct
- Rust Security Policy
Thank you for helping to keep zerobrew and the Rust ecosystem secure!
---