RepoPilotOpen in app โ†’

Homebrew/brew

๐Ÿบ The missing package manager for macOS (or Linux)

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

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Embed this verdict

[![RepoPilot: GO](https://repopilot.app/api/badge/homebrew/brew)](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

  1. 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)
  2. 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, implement def run. (Library/Homebrew/bundle/commands/add.rb)
  3. If the command needs an alias, register it in the aliases layer. (Library/Homebrew/aliases/aliases.rb)

Add a new formula/cask API field

  1. Add the new field to the FormulaStruct or CaskStruct value object definition. (Library/Homebrew/api/formula_struct.rb)
  2. Update the struct generator to extract the new field from the raw API JSON hash. (Library/Homebrew/api/formula/formula_struct_generator.rb)
  3. Add serialization of the new field in api_hashable so the object can round-trip through the API. (Library/Homebrew/api_hashable.rb)
  4. 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

  1. 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)
  2. Register the new entry type keyword in the Brewfile DSL parser. (Library/Homebrew/bundle/brewfile.rb)
  3. Add checking logic for the new entry type in the bundle checker. (Library/Homebrew/bundle/checker.rb)
  4. Add the adder command support so brew bundle add --type works for the new type. (Library/Homebrew/bundle/adder.rb)

Add a new bottle platform/tag

  1. Add the new platform tag constant and detection logic to the bottle specification. (Library/Homebrew/bottle_specification.rb)
  2. Update bottle pouring logic to handle the new tag during installation. (Library/Homebrew/bottle.rb)
  3. Update build environment configuration if the new platform requires different compiler/linker flags. (Library/Homebrew/build_environment.rb)

Traps & gotchas

  1. 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 rspec to 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

  1. 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

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


Generated by RepoPilot. Verdict based on maintenance signals โ€” see the live page for receipts. Re-run on a new commit to refresh.

GO ยท Homebrew/brew โ€” RepoPilot Verdict