Homebrew/brew
๐บ The missing package manager for macOS (or Linux)
Healthy across the board
- โLast commit today
- โ5 active contributors
- โDistributed ownership (top contributor 46%)
- โBSD-2-Clause licensed
- โCI configured
- โTests present
- โ Small team โ 5 top contributors
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Embed this verdict
[](https://repopilot.app/r/homebrew/brew)Paste into your README โ the badge live-updates from the latest cached analysis.
Onboarding doc
Onboarding: Homebrew/brew
Generated by RepoPilot ยท 2026-05-05 ยท Source
Verdict
GO โ Healthy across the board
- Last commit today
- 5 active contributors
- Distributed ownership (top contributor 46%)
- BSD-2-Clause licensed
- CI configured
- Tests present
- โ Small team โ 5 top contributors
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
TL;DR
Homebrew is the primary package manager for macOS (and Linux), written mostly in Ruby (~6.9MB of Ruby source). It manages the installation, upgrade, and removal of developer tools and software via 'formulae' (Ruby DSL files describing packages) and 'casks' (for macOS GUI apps), resolving dependencies and building from source or downloading pre-built 'bottles'. The repo is a monolith centered on Library/Homebrew/ (the core Ruby engine), with commands in Library/Homebrew/cmd/, formula/cask DSLs in Library/Homebrew/formula.rb and related files, and CI/automation in .github/workflows/. Shell scripts for bootstrapping and environment setup live in the top-level and .devcontainer/ directories.
Who it's for
macOS and Linux developers who need to install open-source CLI tools and libraries (e.g. git, wget, openssl) without using the system package manager. Contributors are Ruby developers familiar with CLI tooling who want to add or improve package definitions or core brew infrastructure.
Maturity & risk
Homebrew is one of the most widely used open-source projects in the macOS ecosystem, with a well-established CI setup across multiple GitHub Actions workflows (tests.yml, sorbet.yml, codeql-analysis.yml, etc.) and a detailed CHANGELOG.md indicating years of active development. The presence of CodeQL static analysis, Sorbet type checking, Codecov integration, and a rigorous PR/review process signals a mature, production-ready project maintained by an active team.
Risk is low for consumers: Homebrew is a community-maintained project with multiple active maintainers (see CODEOWNERS), not a single-maintainer risk. The main risk for contributors is the complexity of the Ruby codebase (~6.9MB) and strict linting/typing requirements (Sorbet, RuboCop) that make PRs harder to get right quickly. The dependabot.yml and vendor-gems workflow manage gem dependencies, reducing supply chain risk.
Active areas of work
Active work visible includes: automated workflows for syncing default branches (sync-default-branches.yml), SBOM generation (sbom.yml), SPDX license updates (spdx.yml), Sorbet type checking improvements (sorbet.yml), and regular vendor-gems/vendor-version automation. The CHANGELOG.md and release.yml workflow indicate regular versioned releases.
Get running
git clone https://github.com/Homebrew/brew.git cd brew
No separate install step needed โ brew itself bootstraps
To run tests:
bundle install bundle exec rake test
Or run a specific Ruby test:
bundle exec ruby -Ilib -Itest Library/Homebrew/test/formula_spec.rb
Daily commands:
Run the local dev version of brew:
./bin/brew help
Run the full test suite:
bundle exec rake
Run Sorbet type checking:
bundle exec srb tc
Run RuboCop linting:
bundle exec rubocop
Map of the codebase
Library/Homebrew/brew.rbโ Main Ruby entry point that bootstraps the entire Homebrew runtime, dispatches commands, and sets up the load path โ every brew invocation passes through here.Library/Homebrew/brew.shโ Shell-level entry point that sets environment variables, locates Ruby, and hands off execution to brew.rb โ understanding this is essential before any Ruby code runs.Library/Homebrew/abstract_command.rbโ Base class for all brew CLI commands; defines the DSL (args, flags, description) and execution lifecycle that every command must follow.Library/Homebrew/api.rbโ Core API module that handles fetching, caching, and serving formula/cask data from Homebrew's JSON API โ central to the package metadata pipeline.Library/Homebrew/bottle_specification.rbโ Defines the BottleSpecification class which encodes platform-specific pre-built binary metadata, a critical abstraction for binary package distribution.Library/Homebrew/build.rbโ Orchestrates the formula build process (configure, compile, install) and is the heart of source-based package installation.Library/Homebrew/attestation.rbโ Handles cryptographic attestation verification for bottles/artifacts, a security-critical component that validates package provenance before installation.
How to make changes
Add a new brew CLI command
- Create a new Ruby file in the commands directory inheriting from AbstractCommand. Use the DSL to declare description, flags, and a run method. (
Library/Homebrew/abstract_command.rb) - Implement the command file itself (e.g. cmd/my-command.rb) following the pattern of existing commands: declare
cmd :my_command, set usage/description/flags, implementdef run. (Library/Homebrew/bundle/commands/add.rb) - If the command needs an alias, register it in the aliases layer. (
Library/Homebrew/aliases/aliases.rb)
Add a new formula/cask API field
- Add the new field to the FormulaStruct or CaskStruct value object definition. (
Library/Homebrew/api/formula_struct.rb) - Update the struct generator to extract the new field from the raw API JSON hash. (
Library/Homebrew/api/formula/formula_struct_generator.rb) - Add serialization of the new field in api_hashable so the object can round-trip through the API. (
Library/Homebrew/api_hashable.rb) - Update the API fetcher if the field requires new endpoint logic or cache invalidation. (
Library/Homebrew/api/formula.rb)
Add a new bundle Brewfile entry type
- Create a new entry handler class (e.g. bundle/tap.rb style) implementing install, installed?, and to_s methods consistent with existing handlers. (
Library/Homebrew/bundle/brew.rb) - Register the new entry type keyword in the Brewfile DSL parser. (
Library/Homebrew/bundle/brewfile.rb) - Add checking logic for the new entry type in the bundle checker. (
Library/Homebrew/bundle/checker.rb) - Add the adder command support so
brew bundle add --typeworks for the new type. (Library/Homebrew/bundle/adder.rb)
Add a new bottle platform/tag
- Add the new platform tag constant and detection logic to the bottle specification. (
Library/Homebrew/bottle_specification.rb) - Update bottle pouring logic to handle the new tag during installation. (
Library/Homebrew/bottle.rb) - Update build environment configuration if the new platform requires different compiler/linker flags. (
Library/Homebrew/build_environment.rb)
Traps & gotchas
- Sorbet type annotations are enforced in CI โ adding new Ruby files or methods without correct Sorbet signatures will fail the sorbet.yml workflow. 2. Gems are vendored (vendor-gems.yml) so you must run bundle install against the vendored path, not system gems. 3. On Linux, some macOS-specific APIs and formula assumptions won't apply โ the devcontainer is the safest way to get a reproducible Linux environment. 4. The CLAUDE.md and AGENTS.md files contain specific rules for automated agents; ignoring them can cause bot-triggered PRs to fail review.
Architecture
Concepts to learn
- Formula DSL (Domain-Specific Language) โ All packages in Homebrew are described as Ruby DSL files inheriting from Formula โ understanding this pattern is essential to adding or modifying packages.
- Bottles (pre-built binary packages) โ Bottles are platform-specific pre-built tarballs that brew downloads instead of building from source โ understanding them explains why installs are fast and how the CI bottle-building pipeline works.
- Taps (third-party repositories) โ Taps are git repos of formulae/casks that extend brew's package set โ the core repo only provides the engine, while homebrew-core and homebrew-cask are separate taps.
- Sorbet (Ruby static type checker) โ Homebrew uses Sorbet for gradual static typing of Ruby โ contributors must add correct T.sig type signatures or CI will reject the PR.
- Keg (installed package directory) โ A 'keg' is the directory under Cellar/ where a specific version of a formula is installed โ this is Homebrew's unit of installation and is referenced throughout the codebase.
- Cellar (versioned install root) โ The Cellar is the top-level directory (e.g. /usr/local/Cellar) holding all kegs, enabling multiple versions of a package to coexist before symlinking.
- SBOM (Software Bill of Materials) โ Homebrew generates SBOMs (see sbom.yml workflow) for supply chain security compliance โ an increasingly important concept for package managers distributing third-party software.
Related repos
Homebrew/homebrew-coreโ The main tap containing all official formulae (package definitions) that brew installs โ the content layer to brew's engine.Homebrew/homebrew-caskโ The companion tap for macOS GUI application casks, managed by the same brew infrastructure.nickg/nixโ Nix is a functional alternative package manager solving the same reproducible software installation problem on macOS/Linux.pkgxdev/pkgxโ A newer alternative package manager for macOS/Linux that competes directly with brew for developer tooling installation.Homebrew/formulae.brew.shโ The companion website repo that renders the online package browser at formulae.brew.sh, powered by brew's formula data.
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for Library/Homebrew/aliases/alias.rb and aliases/aliases.rb
The aliases directory contains alias.rb and aliases.rb which handle Homebrew command aliasing. Given the file structure shows no corresponding spec files (e.g. no aliases/alias_spec.rb or aliases/aliases_spec.rb visible), these files likely lack dedicated unit test coverage. Aliases are a core UX feature โ untested edge cases (duplicate alias names, aliases pointing to non-existent commands, circular references) can cause subtle breakage for users.
- [ ] Audit Library/Homebrew/aliases/alias.rb and Library/Homebrew/aliases/aliases.rb to understand all public methods and edge cases
- [ ] Create Library/Homebrew/test/aliases/alias_spec.rb covering: alias resolution, invalid alias targets, and name collision behavior
- [ ] Create Library/Homebrew/test/aliases/aliases_spec.rb covering: listing aliases, loading aliases from disk, and handling malformed alias files
- [ ] Run the existing test suite with
bundle exec rspecto confirm new specs integrate cleanly with .rspec_parallel config - [ ] Ensure new specs follow patterns in existing spec files under Library/Homebrew/test/ (mocking, subject/let conventions, etc.)
Add a GitHub Actions workflow for validating .editorconfig conformance across the codebase
The repo has a .editorconfig file defining formatting rules, but there is no corresponding CI workflow in .github/workflows/ that enforces these rules automatically on PRs. This means contributors can inadvertently introduce trailing whitespace, wrong indentation, or wrong line endings without immediate feedback. Adding an editorconfig-checker workflow closes this gap and reduces reviewer burden on purely mechanical formatting issues.
- [ ] Review the existing .editorconfig file at the repo root to understand the enforced rules (indent style, trim trailing whitespace, insert final newline, etc.)
- [ ] Create .github/workflows/editorconfig.yml that runs on pull_request and uses the editorconfig-checker/action (or ec CLI tool) against the full repo
- [ ] Exclude auto-generated or vendored paths (e.g. Library/Homebrew/vendor/) from the checker to avoid noise
- [ ] Verify the new workflow passes against the current HEAD before opening the PR
- [ ] Add the new workflow filename to .github/actionlint.yaml exclusions if needed and run actionlint to confirm the workflow YAML is valid
Refactor Library/Homebrew/abstract_command.rb by extracting argument validation into a dedicated module
abstract_command.rb is a central base class that all Homebrew commands inherit from. Base classes of this kind tend to accumulate mixed responsibilities over time โ command registration, argument parsing, validation, and help text generation often end up co-located. Extracting argument validation logic into a separate module (e.g. Homebrew::CommandArgValidation) improves testability of validation rules in isolation, reduces the surface area of the base class, and makes it easier for new contributors to add new argument types without understanding the entire command lifecycle.
- [ ] Read Library/Homebrew/abstract_command.rb in full and identify all methods related to argument validation vs. command dispatch vs. help generation
- [ ] Create Library/Homebrew/command_arg_validation.rb as a module containing the extracted validation methods, following the existing module naming conventions in the codebase
- [ ] Update abstract_command.rb to include the new module and remove the extracted methods, ensuring no behavior change
- [ ] Create or update Library/Homebrew/test/abstract_command_spec.rb to add regression tests that cover the extracted paths
- [ ] Create Library/Homebrew/test/command_arg_validation_spec.rb with isolated unit tests for the new module
- [ ] Run the full test suite and sorbet type checking (matching .github/workflows/sorbet.yml) to confirm no regressions
Good first issues
- Add missing Sorbet type signatures to Ruby files in Library/Homebrew/cmd/ that still have untyped methods (check sorbet.yml failures for candidates). 2. Improve test coverage for edge cases in Library/Homebrew/cask/ โ the cask system is large and test gaps are common there. 3. Add or improve inline YARD documentation comments for public methods in Library/Homebrew/formula.rb, which is central but can have sparse doc coverage on newer methods.
Top contributors
- @MikeMcQuaid โ 36 commits
- @ZhongRuoyu โ 18 commits
- @ooye-sanket โ 10 commits
- @samford โ 8 commits
- @HaraldNordgren โ 7 commits
Recent commits
e43b04fโ Merge pull request #22134 from Homebrew/github-actions-docker-cache-multi-platform-issue (MikeMcQuaid)0563536โ Improve Docker cache reuse (MikeMcQuaid)c94270eโ Merge pull request #22133 from Homebrew/perf-system-command-lazy-requires (MikeMcQuaid)0f181e5โ Merge pull request #22131 from Homebrew/fix-bundle-cask-tap-cleanup (MikeMcQuaid)31d6c69โ Merge pull request #22132 from Homebrew/brew-rs-autoremove-cleanup-gate (MikeMcQuaid)2677aedโ system_command: avoid loading plist and URI libraries at startup (dduugg)95637a0โ Merge pull request #22130 from HaraldNordgren/caveats/shadowed-path (MikeMcQuaid)d73ad55โ caveats: add HOMEBREW_NO_PATH_SHADOW_CHECK opt-out hint (HaraldNordgren)c3c517fโ caveats: still check shadowing for linked keg-only formulae (HaraldNordgren)6980d9aโ caveats: add HOMEBREW_NO_PATH_SHADOW_CHECK opt-out (HaraldNordgren)
Security observations
- Medium ยท Docker Build Cache Mount Exposes APT Cache โ
Dockerfile. The Dockerfile uses '--mount=type=cache,target=/var/cache/apt,sharing=locked' which caches apt packages across builds. While this improves build speed, cached packages may become stale and include outdated or vulnerable packages that won't be refreshed unless the cache is explicitly invalidated. This could lead to installation of packages with known vulnerabilities. Fix: Regularly invalidate the Docker build cache for apt-related layers, or implement a mechanism to verify package checksums/signatures after installation. Consider pinning package versions and auditing them periodically. - Medium ยท Unpinned Base Image Version (Ubuntu ARG) โ
Dockerfile. The Dockerfile uses 'ARG version=22.04' and 'FROM ubuntu:"${version}"' allowing the base image version to be overridden at build time. While a default is provided, the use of an ARG rather than a fixed digest means the image could be built with an unintended or potentially vulnerable Ubuntu version if the ARG is overridden. Additionally, there is no image digest pinning (e.g., sha256), making the build susceptible to image tag mutation or supply chain attacks. Fix: Pin the base image to a specific SHA256 digest (e.g., 'FROM ubuntu:22.04@sha256:<digest>') to ensure reproducible and verifiable builds. If the ARG override is intentional, document and restrict who can set it. - Medium ยท Hardcoded User ID (UID=1000) May Cause Privilege Escalation Risk in Shared Environments โ
Dockerfile. The Dockerfile sets ENV USER_ID=1000 and explicitly deletes the default ubuntu user to avoid UID conflicts for the 'linuxbrew' user. While this is done for determinism, hardcoding a well-known UID (1000) in a shared or orchestrated container environment could potentially allow the container process to access host resources or files owned by UID 1000 on the host, especially if user namespace remapping is not configured. Fix: Ensure Docker user namespace remapping is enabled in production environments, or document that the container should not be run in environments where UID 1000 on the host has sensitive file permissions. Consider using a higher, less-common UID. - Medium ยท PEM Certificate File Embedded in Source Repository โ
Library/Homebrew/api/homebrew-1.pem. A PEM certificate file ('Library/Homebrew/api/homebrew-1.pem') is committed directly into the repository. While this may be a public certificate used for API response verification (e.g., attestation), storing certificates in source control can be risky if the certificate is ever used for signing or if it is inadvertently a private key or contains sensitive data. It also makes rotation difficult without a code change. Fix: Verify the PEM file contains only a public certificate and no private key material. If it is a public certificate for verification purposes, document this clearly. Implement a certificate rotation process that does not require a full release cycle. Consider loading certificates from a secure configuration store rather than embedding them in source. - Medium ยท Potential Command Injection Risk in Shell Script (on-create-command.sh) โ
.devcontainer/on-create-command.sh. The devcontainer setup script 'on-create-command.sh' runs during container creation and could be a vector for command injection if it processes any external input (e.g., environment variables, mounted files) without proper sanitization. Shell scripts used in automated DevContainer or CI/CD workflows are a common attack surface, especially if they interpolate unvalidated variables. Fix: Review the script for any usage of unquoted variables, eval statements, or external input interpolation. Use 'set -euo pipefail' at the top of all shell scripts, quote all variable expansions, and validate any external inputs. Run shellcheck against the script (a .shellcheckrc is present, suggesting this is partially addressed). - Low ยท GitHub Actions Workflow Supply Chain Risk โ
.github/workflows/. The repository contains numerous GitHub Actions workflow files under '.github/workflows/'. If any third-party Actions are referenced by mutable tags (e.g., 'uses: actions/checkout@v3') rather than pinned to a specific SHA commit, a compromised upstream Action could inject malicious code into the CI/CD pipeline, leading to secret exfiltration or malicious artifact generation. Fix: Pin all third-party GitHub Actions to a specific commit
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues โ current backlog
- Recent PRs โ what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals โ see the live page for receipts. Re-run on a new commit to refresh.