# Homebrew Admin & Architecture Guide

This guide is for the people who operate Homebrew at depth: administrators rolling it out across machines, power users who want to understand what happens under the hood, and developers who write or maintain formulae and casks. It documents Homebrew's architecture, its complete configuration surface, its security model, day-to-day operations, internals, and the developer command set.

For end-user installation and everyday package management, see the companion **User Guide**. This guide assumes you've read it.

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Architecture](#2-architecture)
3. [Filesystem Layout](#3-filesystem-layout)
4. [Requirements & Platform Support](#4-requirements--platform-support)
5. [Installation & Deployment](#5-installation--deployment)
6. [Configuration Reference (Environment Variables)](#6-configuration-reference-environment-variables)
7. [Security Model](#7-security-model)
8. [Operations](#8-operations)
9. [The Formula & Cask Model](#9-the-formula--cask-model)
10. [Developer Commands](#10-developer-commands)
11. [Codebase Internals](#11-codebase-internals)
12. [Testing & Quality](#12-testing--quality)
13. [Troubleshooting (Operational)](#13-troubleshooting-operational)
14. [Potential Improvements](#14-potential-improvements)
15. [Quick Reference](#15-quick-reference)

---

## 1. Executive Summary

Homebrew is a package manager for macOS and Linux written in **Ruby**. It installs software into a self-contained **prefix** owned by the installing user, then symlinks the results onto the user's `PATH`. It deliberately avoids `sudo`, system directories, and OS package managers, which makes installs and removals clean and reversible.

There are two package types. **Formulae** are built from upstream source or, more usually, poured from pre-built binary **bottles**. **Casks** install pre-compiled applications (typically macOS GUI apps). Both are Ruby definitions hosted in Git repositories called **taps**; the official taps are `homebrew/core` (formulae) and `homebrew/cask` (casks).

Operationally, the things an administrator most needs to understand are:

- **API mode** — by default Homebrew reads `homebrew/core` and `homebrew/cask` as a JSON API from `formulae.brew.sh` rather than cloning multi-hundred-megabyte Git repositories. This is the single biggest behavioural change in modern Homebrew.
- **The `HOMEBREW_*` environment variables** — Homebrew has no config file in the traditional sense; ~110 environment variables are the configuration surface (plus an optional system-wide `/etc/homebrew/brew.env`).
- **The security model** — no-`sudo` policy, a build sandbox, bottle attestation verification, tap trust, and a family of "forbidden"/"allowed" allowlist variables for managed fleets.

The codebase is ~4.6 MB of Ruby across ~2,600 files, fully annotated with **Sorbet** type signatures and linted with custom **RuboCop** cops. The project is its own canonical documentation source: `docs/Manpage.md` is the authoritative command/flag reference and `Library/Homebrew/env_config.rb` is the authoritative environment-variable registry.

---

## 2. Architecture

### The big picture

```
            user types:  brew install wget
                              │
                              ▼
   ┌──────────────────────────────────────────────────────────┐
   │  bin/brew  (Bash launcher)                                │
   │   • locates the prefix, sets HOMEBREW_* path vars         │
   │   • selects vendored or system Ruby                       │
   │   • exec → Library/Homebrew/brew.rb                       │
   └──────────────────────────────┬───────────────────────────┘
                                   ▼
   ┌──────────────────────────────────────────────────────────┐
   │  Library/Homebrew/brew.rb  (Ruby dispatcher)              │
   │   • parse ARGV → extract command + global flags           │
   │   • internal command?  ── yes ─→ AbstractCommand subclass │
   │   • external command?  ── yes ─→ brew-<cmd>[.rb] / exec   │
   │   • fetch JSON API (unless HOMEBREW_NO_INSTALL_FROM_API)   │
   └──────────────────────────────┬───────────────────────────┘
                                   ▼
   ┌──────────────────────────────────────────────────────────┐
   │  Command instance (cmd/<name>.rb or dev-cmd/<name>.rb)    │
   │   • CLI::Parser builds its option grammar                 │
   │   • .run executes:                                        │
   │       Formulary / CaskLoader → Formula / Cask object      │
   │       → DownloadStrategy → UnpackStrategy → build/pour    │
   │       → Keg → symlink into prefix                         │
   └──────────────────────────────────────────────────────────┘
```

### Startup and dispatch

The entry point is the Bash script `bin/brew`, which establishes the environment (`HOMEBREW_BREW_FILE`, `HOMEBREW_PREFIX`, `HOMEBREW_REPOSITORY`, `HOMEBREW_PATH`, the cache and library paths), chooses Ruby (a vendored, relocatable Ruby unless a suitable system Ruby is available — see `HOMEBREW_FORCE_VENDOR_RUBY`), and hands off to `Library/Homebrew/brew.rb`.

`brew.rb` is the dispatcher. Reading its logic (`Library/Homebrew/brew.rb`):

1. It scans `ARGV` to separate the **command** from global help flags (`-h`, `--help`, `--usage`, `help <cmd>`).
2. It parses the remaining arguments with `Homebrew::CLI::Parser` (allowing invalid options at this stage, since formula names look like arguments).
3. It resolves the command through `Commands`:
   - **Internal command** (`Commands.valid_internal_cmd?` / `valid_internal_dev_cmd?`) → look up the matching `Homebrew::AbstractCommand` subclass and call `.new.run`.
   - **External Ruby v2 command** → a tap-provided command that subclasses `AbstractCommand`.
   - **External Ruby command** (`brew-<cmd>.rb` on `PATH`) → `require`d.
   - **External executable** (`brew-<cmd>` on `PATH`) → `exec`'d directly.
4. Unless `HOMEBREW_NO_INSTALL_FROM_API` is set, it calls `Homebrew::API.fetch_api_files!` to refresh the JSON formula/cask data before running the command.
5. It reports the command run to analytics (unless disabled) and executes `command_instance.run`.

A single top-level `begin/rescue` block in `brew.rb` defines the program's exit-code and error-reporting contract: `UsageError` prints help; `BuildError` reports the build failure (and suppresses issue reporting for non–Tier 1 configurations); `Interrupt` exits 130; deprecated-method and tap errors print an issue-reporting URL; everything else prints the error and exits 1.

### Command architecture

Every built-in command lives in `Library/Homebrew/cmd/<name>.rb` (user commands) or `Library/Homebrew/dev-cmd/<name>.rb` (developer commands) and subclasses `Homebrew::AbstractCommand`. Each declares its option grammar in a `cmd_args do ... end` block that configures a `Homebrew::CLI::Parser`.

`CLI::Parser` (`Library/Homebrew/cli/parser.rb`) wraps Ruby's `OptionParser` and provides Homebrew's declarative option DSL:

- `switch` — a boolean flag (optionally bound to an env var, with `depends_on`, `hidden`, deprecation, and per-subcommand scoping).
- `flag` — an option that takes a value (`--name=` required, `--name` optional).
- `comma_array` — an option that parses a comma-separated list.
- `named_args` — declares the type/min/max of positional arguments (`:formula`, `:cask`, `:tap`, `:command`, `:none`, …).
- `conflicts` / `depends_on` — express mutual-exclusion and dependency constraints between options, enforced at parse time.
- `cask_options` / `formula_options` — mix in the global cask directory options, or allow formula-defined options to be parsed.

The four global options — `-d/--debug`, `-q/--quiet`, `-v/--verbose`, `-h/--help` — are added to every parser (`Parser.global_options`). Parsed arguments are frozen into a `Homebrew::CLI::Args` object; `Homebrew::CLI::NamedArgs` then resolves positional names into `Formula`, `Cask` or `Keg` objects via `Formulary` and `Cask::CaskLoader`, transparently handling the formula-vs-cask name collision (formulae win, with a warning, unless `--formula`/`--cask` is given).

### Install pipeline (conceptual)

When you `brew install <formula>`, the resolved `Formula` object drives: dependency resolution → download (a **DownloadStrategy** picks curl/Git/etc. based on the URL) → unpack (an **UnpackStrategy** handles the archive type) → either pour a **bottle** or run the formula's `install` method in a sandbox → relocate and place the result as a **keg** in the Cellar → symlink (`link`) the keg into the prefix. Casks follow an analogous path through `Cask::Installer` and a set of **artifact** classes (`app`, `pkg`, `binary`, `font`, …), each knowing how to install and uninstall its artifact type.

---

## 3. Filesystem Layout

Homebrew is entirely contained in its **prefix**. The default prefix depends on the platform:

| Platform | Default prefix |
|----------|----------------|
| macOS, Apple Silicon | `/opt/homebrew` |
| macOS, Intel | `/usr/local` |
| Linux | `/home/linuxbrew/.linuxbrew` |

> [!IMPORTANT]
> The default prefix is not cosmetic. Bottles are built for, and relocate to, these specific prefixes. Installing elsewhere forces source builds for nearly everything, which is slow and unsupported. `/opt/homebrew` was chosen on Apple Silicon precisely so it can coexist with a Rosetta 2 `/usr/local` install.

Inside the prefix:

| Path | Contents |
|------|----------|
| `bin/`, `sbin/` | Symlinks to installed executables (this is what's on your `PATH`). |
| `Cellar/<name>/<version>/` | Installed formula **kegs** — the real files. |
| `Caskroom/<token>/<version>/` | Installed cask versions. |
| `opt/<name>/` | Stable symlink to the active keg (used by other formulae). |
| `etc/`, `var/` | Configuration and state for installed software. |
| `Library/Taps/<user>/homebrew-<repo>/` | Cloned tap repositories. |
| `Library/Homebrew/` | Homebrew's own Ruby source. |
| `.git/` | Homebrew's Git checkout (this *is* the project). |

Outside the prefix:

| Path | Contents | Override |
|------|----------|----------|
| Download cache | macOS `~/Library/Caches/Homebrew`, Linux `~/.cache/Homebrew` | `HOMEBREW_CACHE` |
| Logs | macOS `~/Library/Logs/Homebrew`, Linux `~/.cache/Homebrew/Logs` | `HOMEBREW_LOGS` |
| Build temp | macOS `/private/tmp`, Linux `/var/tmp` | `HOMEBREW_TEMP` |
| User config | `${XDG_CONFIG_HOME}/homebrew/` or `~/.homebrew/` | (holds `trust.json`, `livecheck_watchlist.txt`, etc.) |
| System config | `/etc/homebrew/brew.env` | System-wide environment defaults |

You can always discover these at runtime with `brew --prefix`, `brew --cellar`, `brew --caskroom`, `brew --cache`, `brew --repository`, and `brew --taps`.

---

## 4. Requirements & Platform Support

| Platform | Requirements |
|----------|--------------|
| **macOS** | 64-bit Intel or Apple Silicon; latest macOS best supported. Requires Xcode Command Line Tools (`xcode-select --install`). |
| **Linux** | 64-bit x86_64 or ARM; `glibc` ≥ 2.13; `gcc`, `make`, and basic build tooling; a single-user (not shared) account. |

Homebrew uses a **Support Tiers** model: builds on non–Tier 1 configurations may fail by design, and `brew.rb` explicitly suppresses issue-reporting prompts for them (pointing instead at <https://docs.brew.sh/Support-Tiers>). Homebrew is designed for **single-user** installations and does not support shared/role-account or multi-user setups.

On Linux, Homebrew can simulate macOS code paths for auditing macOS formulae via `HOMEBREW_SIMULATE_MACOS_ON_LINUX`.

---

## 5. Installation & Deployment

### Interactive install

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

Wire Homebrew into shells with `brew shellenv` (see the User Guide). On Linux this is mandatory; on macOS the default-prefix `bin` is usually already on `PATH`.

### Fleet / MDM deployment

For managed deployments (MDM, Munki, Jamf), a few facilities matter:

- **`brew as-console-user <command>`** runs a `brew` command as the active macOS console user even when `brew` is invoked as `root` — the standard pattern for MDM workflows where management tooling runs as root but Homebrew must operate as the logged-in user. The nested command is dispatched through `HOMEBREW_BREW_FILE`.
- **`/etc/homebrew/brew.env`** sets system-wide environment defaults. With `HOMEBREW_SYSTEM_ENV_TAKES_PRIORITY` set inside that file, it is loaded *last* so it overrides prefix and user settings — useful for enforcing fleet policy.
- **`HOMEBREW_FORCE_BREW_WRAPPER`** requires `brew` to be invoked through a specific wrapper for non-trivial commands, letting you interpose policy/logging.
- **`brew bundle`** with a checked-in `Brewfile` is the supported way to declare and converge the desired package set across machines.

### Deployment checklist

- [ ] Install to the **default prefix** so bottles work.
- [ ] Add `brew shellenv` output to the appropriate shell profile.
- [ ] Pin auto-update behaviour for fleets (`HOMEBREW_NO_AUTO_UPDATE` or a higher `HOMEBREW_AUTO_UPDATE_SECS`) so machines update on your schedule.
- [ ] Set allowlist/denylist policy (`HOMEBREW_ALLOWED_TAPS`, `HOMEBREW_FORBIDDEN_*`) where required.
- [ ] Decide on analytics policy (`HOMEBREW_NO_ANALYTICS`).
- [ ] Distribute a `Brewfile` and converge with `brew bundle install`.
- [ ] Verify with `brew config` and `brew doctor`.

---

## 6. Configuration Reference (Environment Variables)

Homebrew is configured almost entirely through `HOMEBREW_*` environment variables, defined authoritatively in `Library/Homebrew/env_config.rb` (the `ENVS` hash). Set them in shell profiles or in `/etc/homebrew/brew.env`.

> [!NOTE]
> A variable must have a **value** to be detected — `export HOMEBREW_NO_INSECURE_REDIRECT=1`, not a bare `export HOMEBREW_NO_INSECURE_REDIRECT`. Boolean variables come in two flavours internally: `:set` toggles enable on any non-empty value, while plain booleans also honour falsy values (`false`, `no`, `off`, `nil`, `0`).

### Update & API behaviour

| Variable | Default | Effect |
|----------|---------|--------|
| `HOMEBREW_NO_AUTO_UPDATE` | — | Skip auto-`update` before install/upgrade/tap. |
| `HOMEBREW_AUTO_UPDATE_SECS` | 86400 | Minimum seconds between auto-updates. |
| `HOMEBREW_API_AUTO_UPDATE_SECS` | 450 | Seconds between API data refreshes. |
| `HOMEBREW_FORCE_API_AUTO_UPDATE` | — | Refresh API data even if auto-update is disabled. |
| `HOMEBREW_NO_INSTALL_FROM_API` | — | Use local Git checkouts of core/cask taps instead of the JSON API. |
| `HOMEBREW_API_DOMAIN` | `formulae.brew.sh/api` | Mirror for the JSON API. |
| `HOMEBREW_UPDATE_TO_TAG` | — | Always update to the latest stable tag, even after dev commands. |
| `HOMEBREW_NO_UPDATE_REPORT_NEW` | — | Don't list newly added formulae/casks after `update`. |

### Download sources & mirrors

| Variable | Default | Effect |
|----------|---------|--------|
| `HOMEBREW_BOTTLE_DOMAIN` | `ghcr.io/v2/homebrew/core` | Mirror for bottle downloads. |
| `HOMEBREW_ARTIFACT_DOMAIN` | — | Prefix all download URLs (bottle URLs have their domain replaced). |
| `HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK` | — | Error instead of falling back when the artifact domain fails. |
| `HOMEBREW_BREW_GIT_REMOTE` | official | Git remote for Homebrew/brew. |
| `HOMEBREW_CORE_GIT_REMOTE` | official | Git remote for homebrew-core. |
| `HOMEBREW_PIP_INDEX_URL` | `pypi.org/simple` | Index for PyPI resource downloads. |
| `HOMEBREW_DOCKER_REGISTRY_TOKEN` / `..._BASIC_AUTH_TOKEN` | — | Auth for a registry proxying GitHub Packages. |

### Network, proxies & TLS

| Variable | Effect |
|----------|--------|
| `http_proxy` / `https_proxy` / `all_proxy` / `ftp_proxy` / `no_proxy` | Standard proxy settings honoured by curl/git/svn. |
| `HOMEBREW_NO_INSECURE_REDIRECT` | Forbid HTTPS→HTTP redirects. |
| `HOMEBREW_CURL_RETRIES` (3) | Retry count passed to curl. |
| `HOMEBREW_CURLRC` | Pass a curl config / don't disable `.curlrc`. |
| `HOMEBREW_FORCE_BREWED_CURL` / `..._GIT` / `..._CA_CERTIFICATES` | Use Homebrew's own curl/git/CA certs (auto-set if the system version is too old). |
| `HOMEBREW_SSH_CONFIG_PATH` | Use a custom SSH config for Git-over-SSH fetches. |

### Build behaviour

| Variable | Default | Effect |
|----------|---------|--------|
| `HOMEBREW_MAKE_JOBS` | CPU cores | Parallel `make` jobs. |
| `HOMEBREW_DOWNLOAD_CONCURRENCY` | auto (2× cores) | Parallel download connections (`1` = serial). |
| `HOMEBREW_ARCH` | native | Linux `-march` value. |
| `HOMEBREW_CC` (via `--cc`) | — | Override the compiler. |
| `HOMEBREW_FORMULA_BUILD_NETWORK` | allow | Sandbox network policy during build (`allow`/`deny`). |
| `HOMEBREW_FORMULA_POSTINSTALL_NETWORK` | allow | …during post-install. |
| `HOMEBREW_FORMULA_TEST_NETWORK` | allow | …during `brew test`. |
| `HOMEBREW_FAIL_LOG_LINES` (15) | — | Lines of output shown on a `system` failure. |
| `HOMEBREW_DISPLAY_INSTALL_TIMES` | — | Print per-formula install times. |
| `HOMEBREW_KEEP_TMP` (via `--keep-tmp`) | — | Retain build temp files. |

### Cleanup & autoremove

| Variable | Default | Effect |
|----------|---------|--------|
| `HOMEBREW_NO_INSTALL_CLEANUP` | — | Never auto-`cleanup` after installs. |
| `HOMEBREW_NO_CLEANUP_FORMULAE` | — | Comma-separated formulae to never clean up/autoremove. |
| `HOMEBREW_CLEANUP_MAX_AGE_DAYS` | 120 | Age threshold for cached downloads. |
| `HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS` | 30 | Days between full periodic cleanups. |
| `HOMEBREW_NO_AUTOREMOVE` | — | Don't auto-remove unused dependents on cleanup/uninstall. |

### Cask & upgrade behaviour

| Variable | Effect |
|----------|--------|
| `HOMEBREW_CASK_OPTS` | Default options appended to all cask commands (`--*dir`, `--language`, `--require-sha`, `--no-binaries`). |
| `HOMEBREW_UPGRADE_GREEDY` | Pass `--greedy` to all cask upgrades. |
| `HOMEBREW_UPGRADE_GREEDY_CASKS` | Space-separated casks treated as `--greedy`. |
| `HOMEBREW_UPGRADE_AUTO_UPDATES_CASKS` | Auto-upgrade `auto_updates true` casks (default with `HOMEBREW_DEVELOPER`; default in 5.2.0). |
| `HOMEBREW_NO_UPGRADE_QUIT_CASKS` | Don't quit running apps during cask upgrades. |
| `HOMEBREW_FORBID_CASKS` | Refuse to install any casks. |
| `HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK` | Skip the post-install broken-linkage/outdated-dependents check. |
| `HOMEBREW_NO_INSTALL_UPGRADE` | `brew install <x>` won't upgrade an outdated `<x>`. |

### Policy & allowlists (fleet-relevant)

| Variable | Effect |
|----------|--------|
| `HOMEBREW_ALLOWED_TAPS` | Only install formulae from official taps or this space-separated list. |
| `HOMEBREW_FORBIDDEN_FORMULAE` / `..._CASKS` / `..._TAPS` / `..._LICENSES` | Refuse to install anything (or any dependency) matching these lists. |
| `HOMEBREW_FORBIDDEN_CASK_ARTIFACTS` | Forbid specific cask artifact types (e.g. `pkg installer`). |
| `HOMEBREW_FORBIDDEN_OWNER` / `..._OWNER_CONTACT` | Identify who set the forbidden policy (shown in errors). |
| `HOMEBREW_FORBID_PACKAGES_FROM_PATHS` | Refuse to read formulae/casks from local file paths (default true unless `HOMEBREW_DEVELOPER`). |
| `HOMEBREW_REQUIRE_TAP_TRUST` / `HOMEBREW_NO_REQUIRE_TAP_TRUST` | Require (or not) `brew trust` for non-official taps before loading them. |
| `HOMEBREW_DISABLE_LOAD_FORMULA` | Refuse to load formulae at all (for untrusted contexts like PRs). |

### Security & provenance

| Variable | Effect |
|----------|--------|
| `HOMEBREW_VERIFY_ATTESTATIONS` / `HOMEBREW_NO_VERIFY_ATTESTATIONS` | Verify (or skip) cryptographic build-provenance attestations for homebrew-core bottles via `gh`. |
| `HOMEBREW_SANDBOX_LINUX` / `HOMEBREW_NO_SANDBOX_LINUX` | Enable/disable the `bwrap` Linux build sandbox (default with `HOMEBREW_DEVELOPER`; default in 5.2.0). |
| `HOMEBREW_NO_SANDBOX_CASK` | Disable sandboxing for cask artifacts that run executables. |
| `HOMEBREW_SUDO_THROUGH_SUDO_USER` | Use `$SUDO_USER` when Homebrew must call `sudo`. |
| `HOMEBREW_GITHUB_API_TOKEN` / `HOMEBREW_GITHUB_PACKAGES_TOKEN` / `..._USER` | Tokens for the GitHub API and Packages registry. |

### Output & UX

| Variable | Effect |
|----------|--------|
| `HOMEBREW_NO_ANALYTICS` | Disable anonymous analytics. |
| `HOMEBREW_NO_COLOR` / `HOMEBREW_COLOR` | Force colour off / on. |
| `HOMEBREW_NO_EMOJI` | Suppress the success badge. |
| `HOMEBREW_INSTALL_BADGE` (🍺) | The success badge text. |
| `HOMEBREW_NO_ENV_HINTS` | Suppress env-var hints. |
| `HOMEBREW_VERBOSE` / `HOMEBREW_DEBUG` / `HOMEBREW_VERBOSE_USING_DOTS` | Always-verbose / always-debug / dotted progress. |
| `HOMEBREW_EDITOR` / `HOMEBREW_BROWSER` / `HOMEBREW_DISPLAY` | Editor / browser / X11 display for `edit`/`home`. |
| `HOMEBREW_BAT` / `HOMEBREW_BAT_THEME` / `HOMEBREW_BAT_CONFIG_PATH` | Use `bat` for `brew cat`. |

### Developer mode

| Variable | Effect |
|----------|--------|
| `HOMEBREW_DEVELOPER` | Turn warnings into errors and enable developer-friendly defaults (sandbox, attestations, ask mode, etc.). |
| `HOMEBREW_NO_INSTALL_FROM_API` | (See above) required to edit core formulae locally. |
| `HOMEBREW_SORBET_RUNTIME` / `HOMEBREW_SORBET_RECURSIVE` | Enable Sorbet runtime typechecking. |
| `HOMEBREW_PRY` / `HOMEBREW_DISABLE_DEBREW` | Use Pry for `brew irb` / disable the `--debug` formula debugger. |
| `HOMEBREW_GIT_NAME` / `HOMEBREW_GIT_EMAIL` / `..._COMMITTER_*` | Git author/committer identity for PR commands. |

> [!TIP]
> This table is curated for operators. The exhaustive list — including the many `HOMEBREW_BUNDLE_*` toggles and several deprecated transitional flags — lives in `Library/Homebrew/env_config.rb` and is rendered into the ENVIRONMENT section of `man brew`.

---

## 7. Security Model

Homebrew's security posture is built around the principle that **build scripts are untrusted code** and should never run with elevated privileges.

### No `sudo`

Homebrew refuses to run as root. Because the prefix is owned by the installing user, no privilege escalation is needed to install software. A formula's `make`/`configure` scripts run arbitrary code; running them as root would let a malicious or buggy script modify anything on the system. The macOS sandbox blocks much of this, but the sandbox doesn't function as root — hence the hard no-`sudo` rule. The single exception is `sudo brew services`, where only the resulting service runs elevated.

### Build sandbox

- **macOS** uses `sandbox-exec` to confine builds.
- **Linux** uses `bwrap` (Bubblewrap) when `HOMEBREW_SANDBOX_LINUX` is set (default under `HOMEBREW_DEVELOPER`; becoming the default in 5.2.0).
- Per-phase **network** access is controllable independently for build, post-install and test via `HOMEBREW_FORMULA_BUILD_NETWORK` / `..._POSTINSTALL_NETWORK` / `..._TEST_NETWORK` (each `allow`/`deny`), overriding formula DSL settings.
- Cask artifacts that execute binaries are also sandboxed unless `HOMEBREW_NO_SANDBOX_CASK` is set.

### Bottle provenance (attestations)

For `homebrew-core` bottles, Homebrew can verify **cryptographic build-provenance attestations** using the `gh` CLI (`HOMEBREW_VERIFY_ATTESTATIONS`; suppress with `HOMEBREW_NO_VERIFY_ATTESTATIONS`). This confirms a bottle was built by Homebrew's CI and not tampered with.

### Tap trust

Third-party taps run code on your machine. Homebrew is introducing a **tap-trust** mechanism: with `HOMEBREW_REQUIRE_TAP_TRUST` set, non-official tap formulae, casks and commands must be explicitly trusted with `brew trust` before they load. Trust entries are stored in `${XDG_CONFIG_HOME}/homebrew/trust.json` (or `~/.homebrew/trust.json`). `brew untrust` revokes them. This supersedes the older `HOMEBREW_EVAL_ALL` model.

### Allowlists & denylists for managed environments

Administrators can constrain what Homebrew will install:

- `HOMEBREW_ALLOWED_TAPS` — refuse anything not in an official tap or this list.
- `HOMEBREW_FORBIDDEN_FORMULAE` / `_CASKS` / `_TAPS` / `_LICENSES` / `_CASK_ARTIFACTS` — refuse matching packages, dependencies, licenses or artifact types.
- `HOMEBREW_FORBID_CASKS` — block all casks.
- `HOMEBREW_FORBID_PACKAGES_FROM_PATHS` — block installing formulae/casks from arbitrary local paths.
- `HOMEBREW_DISABLE_LOAD_FORMULA` — refuse to evaluate formula Ruby entirely (e.g. when reviewing untrusted PRs).

### Ownership & permissions

On macOS, Homebrew-managed files default to the installing user and the `admin` group; on Linux, to the installing user and their group. Directory/file permissions default to `0755` — only the owner can modify files in the prefix, while all users may read and execute installed binaries. Installed binaries run with the privileges of whoever launches them.

> [!WARNING]
> Homebrew is a single-user system. Multi-user / shared-account configurations are unsupported and have real security and correctness pitfalls. Don't `chown root` the prefix.

---

## 8. Operations

### Health & diagnostics

```bash
brew doctor                 # check for problems (non-zero exit if any found)
brew doctor --list-checks   # list every diagnostic check
brew config                 # full system + Homebrew config (attach to bug reports)
brew missing                # check installed kegs for missing dependencies
brew --version              # versions of brew + tapped core/cask
```

### Updating Homebrew itself

```bash
brew update                 # fetch newest brew + formula/cask data, run migrations
brew update --force         # force a full update check
brew update-reset           # hard-reset all Homebrew Git repos to origin/HEAD
```

> [!CAUTION]
> `brew update-reset` destroys *all* uncommitted and committed local changes in Homebrew's repositories. Use it to recover a corrupted checkout, not casually.

### Logs and build failures

```bash
brew --cache                # download cache location
brew --prefix/opt/...       # locate installed software
brew gist-logs <formula>    # upload a failed build's logs to a Gist
```

`HOMEBREW_LOGS` controls where logs are written; `HOMEBREW_FAIL_LOG_LINES` controls how much output is shown on a `system` failure.

### Backups & migration

The supported backup unit is the **Brewfile**:

```bash
brew bundle dump --global --describe   # snapshot to ~/.Brewfile
# ... on the new machine, after installing Homebrew:
brew bundle install --global
```

Because the prefix is self-contained, you can also archive the prefix itself, but a `Brewfile` + fresh install is cleaner and avoids relocating absolute paths.

### Developer mode

```bash
brew developer on    # warnings → errors; track main instead of stable tags
brew developer off   # back to stable behaviour
brew developer state
```

Running a developer command (e.g. `brew edit`, `brew create`) implicitly enables developer mode, which also makes auto-update run more frequently and track the `main` branch. Reset with `brew developer off` (or keep stable tags with `HOMEBREW_UPDATE_TO_TAG=1`).

---

## 9. The Formula & Cask Model

### Formulae

A **formula** is a Ruby class (a subclass of `Formula`) that declares a package's source URL, checksum, dependencies, and an `install` method. The canonical reference for authoring is the Formula Cookbook; the key operational facts:

- Formulae normally install a **bottle** (pre-built binary). Bottles are hosted on GitHub Packages (`ghcr.io`) and are *relocatable* to the standard prefixes.
- A formula installs into a **keg** (`Cellar/<name>/<version>`) and is then **linked** (symlinked) into the prefix. `brew link`/`brew unlink` control this; **keg-only** formulae are intentionally never linked.
- Dependencies have kinds: required, recommended, optional, build, test, and implicit. `brew deps`/`brew uses` expose the graph; the `--include-*`/`--skip-recommended` options select which kinds to traverse.
- Formulae can define `service do ... end` blocks consumed by `brew services` (rendered to a launchd plist or systemd unit).

### Casks

A **cask** is a Ruby definition (in `Library/Homebrew/cask/`) describing a pre-built application and its **artifacts**. Each artifact type — `app`, `pkg`, `binary`, `font`, `colorpicker`, `service`, `qlplugin`, and ~20 more — is a class under `cask/artifact/` that knows how to install and uninstall itself, where to put files (the `--*dir` options), and how to clean up (`uninstall`, `zap`). Casks marked `auto_updates true` or `version :latest` interact specially with `brew upgrade` (see the User Guide FAQ).

### API mode vs. local taps

By default Homebrew serves `homebrew/core` and `homebrew/cask` as a **JSON API** (`Homebrew::API`, data from `formulae.brew.sh/api`), avoiding the cost of cloning these very large repositories. `brew install` resolves formula/cask metadata from this JSON. Setting `HOMEBREW_NO_INSTALL_FROM_API=1` reverts to full local Git checkouts — slower, larger, but required when you want to `brew edit` core formulae or run them against local changes.

---

## 10. Developer Commands

Homebrew ships ~60 developer commands (in `Library/Homebrew/dev-cmd/`) for people who write and maintain formulae and casks. They are hidden from the everyday command list but documented in `man brew` under DEVELOPER COMMANDS. The most important:

### Authoring & editing

| Command | Purpose |
|---------|---------|
| `create <url>` | Generate a new formula from a source URL. |
| `edit [<formula>\|<cask>\|<tap>]` | Open a formula/cask/tap in `$HOMEBREW_EDITOR`. |
| `cat <formula>` | Print a formula/cask's source. |
| `extract <formula> <tap>` | Extract a specific version of a formula into a tap. |
| `tap-new <user>/<repo>` | Scaffold a new tap repository. |

### Auditing & style

| Command | Purpose |
|---------|---------|
| `audit` | Check a formula/cask for style and correctness violations (run before submitting). |
| `style` | Run RuboCop style checks on formulae/casks/taps. |
| `typecheck` (`tc`) | Run Sorbet type checking. |
| `readall` | Import all formulae/casks to catch Ruby errors. |
| `linkage` | Check a keg's library linkage. |

### Building & bottling

| Command | Purpose |
|---------|---------|
| `bottle` | Generate a bottle from an installed keg. |
| `unbottled` | List formulae without bottles. |
| `unpack` | Unpack a formula's source into a directory. |
| `test` | Run a formula's test block. |
| `dispatch-build-bottle` | Trigger CI bottle builds. |

### Pull-request workflow

| Command | Purpose |
|---------|---------|
| `bump` / `bump-formula-pr` / `bump-cask-pr` / `bump-revision` | Update versions and open PRs. |
| `bump-unversioned-casks` | Bump casks without explicit versions. |
| `pr-pull` / `pr-publish` / `pr-automerge` / `pr-upload` | Maintainer PR/bottle-publishing pipeline. |
| `release` | Cut a Homebrew/brew release. |
| `contributions` | Report contribution statistics. |

### Maintenance & introspection

| Command | Purpose |
|---------|---------|
| `livecheck` (`lc`) | Check whether newer upstream versions exist. |
| `update-python-resources` / `update-perl-resources` | Regenerate language-specific resource stanzas. |
| `generate-formula-api` / `generate-cask-api` / `generate-man-completions` | Regenerate the JSON API, man page and completions. |
| `irb` / `ruby` / `sh` / `prof` / `debugger` | Interactive Ruby console, ad-hoc Ruby, build-env shell, profiler, debugger. |
| `tests` | Run Homebrew's own test suite. |
| `vendor-gems` / `install-bundler-gems` | Manage Homebrew's Ruby gem dependencies. |

> [!NOTE]
> Most developer commands require a **local tap checkout** (`HOMEBREW_NO_INSTALL_FROM_API=1` + `brew tap --force homebrew/core`) because they read and write formula Ruby files directly.

---

## 11. Codebase Internals

### Languages & structure

The codebase is Ruby, organized under `Library/Homebrew/`:

| Directory | Responsibility |
|-----------|----------------|
| `cmd/` | Built-in user commands (88 files). |
| `dev-cmd/` | Developer commands (58 files). |
| `cli/` | The CLI parser, args, named-args resolution, and error types. |
| `cask/` | Cask DSL, loader, installer, and artifact classes. |
| `services/` | `brew services` implementation (launchd/systemd). |
| `bundle/` | `brew bundle` / Brewfile implementation. |
| `api/` | JSON API client for core/cask data. |
| `download_strategy/`, `unpack_strategy/` | Pluggable download and archive handlers. |
| `extend/`, `extend/os/` | Core-class extensions and OS-specific (mac/linux) overrides. |
| `utils/` | Shared utilities (output, GitHub, bottles, AST, …). |
| `rubocops/` | Custom RuboCop cops that enforce formula/cask conventions. |
| `sorbet/` | Sorbet RBI type stubs and configuration. |
| `shims/` | Compiler/tool shims used during sandboxed builds. |
| `test/` | The RSpec test suite. |

### OS abstraction

Cross-platform behaviour is handled by the `extend/os/` tree: a base implementation lives in the main module and `extend/os/mac/` or `extend/os/linux/` override OS-specific pieces (e.g. `services/cli.rb` branches on `System.launchctl?` vs `System.systemctl?`). This keeps the bulk of the code OS-agnostic with thin platform shims.

### Type safety & conventions

- Every file carries a Sorbet **`# typed:`** sigil (`strict`, `true`, etc.) and `# frozen_string_literal: true`.
- Methods are annotated with `sig { ... }` signatures; `brew typecheck` runs Sorbet.
- Homebrew's own RuboCop cops (`rubocops/`) enforce formula/cask DSL conventions on top of standard style rules.
- Generated Sorbet RBI files (`sorbet/rbi/`) describe the dynamically-defined command and DSL methods.

### Ruby runtime

Homebrew ships a **vendored, relocatable Ruby** so it doesn't depend on the system Ruby (which Apple has been removing). `HOMEBREW_FORCE_VENDOR_RUBY` forces its use; `HOMEBREW_USE_RUBY_FROM_PATH` (build-time) and `setup-ruby` manage the alternative. Non-vendored gems are declared in `Library/Homebrew/Gemfile` in optional groups (doc, style, tests, typecheck, prof, …); a handful are vendored unconditionally (`addressable`, `concurrent-ruby`, `plist`, `ruby-macho`, `sorbet-runtime`, …).

---

## 12. Testing & Quality

| Layer | Tool | How to run |
|-------|------|------------|
| Unit & integration tests | RSpec (`test/`) | `brew tests` |
| Type checking | Sorbet | `brew typecheck` (`tc`) |
| Style | RuboCop + custom cops | `brew style` |
| Formula/cask audit | `brew audit` | `brew audit --strict <formula>` |
| Load-all sanity | `brew readall` | `brew readall` |
| CI bottle builds | `brew test-bot` | (CI) |

Runtime Sorbet typechecking can be forced with `HOMEBREW_SORBET_RUNTIME` (set automatically during `brew test`/`brew tests`). For contributors, the recommended first task is to run `brew audit --strict <some-formula>` and fix what it reports.

> [!TIP]
> Homebrew's contribution culture is mature: read `CONTRIBUTING.md` and the Formula/Cask Cookbooks, run `brew audit --strict` and `brew style` before submitting, and use `brew bump-formula-pr`/`brew bump-cask-pr` to open version-bump PRs in the correct shape.

---

## 13. Troubleshooting (Operational)

### `brew` insists on the Command Line Tools

Install or repair them: `xcode-select --install`. Required again after every major macOS upgrade — follow with `brew upgrade`.

### Corrupted Homebrew checkout / "untracked working tree files" on `update`

```bash
cd "$(brew --repository)"
git reset --hard FETCH_HEAD
cd "$(brew --repository)/Library"
git clean -fd
```

For a complete reset to upstream across all Homebrew repos: `brew update-reset` (destroys local changes).

### Install fails with `unknown revision or path not in the working tree`

A network problem between the machine and GitHub during the initial clone, not a Homebrew bug. Try a wired connection or VPN, or disable network-monitoring tools. (Common in restricted corporate networks — pair with the proxy variables.)

### Linkage broken after a macOS upgrade

```bash
xcode-select --install
brew upgrade
```

`brew missing` and `brew linkage <formula>` help identify what broke.

### Dual installations after Migration Assistant

A copied Intel `/usr/local` Homebrew on an Apple Silicon Mac. Confirm `arch` prints `arm64`, reinstall under `/opt/homebrew`, restore with `brew bundle`, then uninstall the old `/usr/local` install with the official uninstaller (`--path=/usr/local`).

### Cask permission denied / metadata loss on upgrade

Grant the terminal **App Management** or **Full Disk Access** so Homebrew can do in-place cask upgrades; otherwise it falls back to uninstall/reinstall and macOS forgets Dock/Launchpad position and permissions. Fix Caskroom ownership with `sudo chown -R "$(whoami)" "$(brew --caskroom)"`.

---

## 14. Potential Improvements

Several transitions are visible in the source and are worth tracking when planning upgrades:

- **Homebrew 5.2.0 defaults shift.** Multiple variables are documented as "becoming the default in 5.2.0": the Linux `bwrap` sandbox (`HOMEBREW_SANDBOX_LINUX`), auto-upgrading `auto_updates true` casks (`HOMEBREW_UPGRADE_AUTO_UPDATES_CASKS`), SBOM generation (`HOMEBREW_SBOM`), and several `HOMEBREW_BUNDLE_*` describe/jobs/secrets behaviours. Audit any scripts that depend on today's defaults.
- **Tap-trust supersedes `HOMEBREW_EVAL_ALL`.** `HOMEBREW_EVAL_ALL` is deprecated in favour of `HOMEBREW_REQUIRE_TAP_TRUST` / `HOMEBREW_NO_REQUIRE_TAP_TRUST` and `brew trust`. Migrate fleet policy accordingly.
- **Internal API beta.** `HOMEBREW_USE_INTERNAL_API` toggles a new beta path for fetching formula/cask data, slated to become default.
- **`--ask` becoming default.** `HOMEBREW_ASK` is documented to become the default behaviour, so installs will print a plan and prompt by default; set `HOMEBREW_NO_ASK` where non-interactive behaviour is required (CI/automation).
- **Several `odeprecated`/`hidden` flags** are marked for removal in 5.2.0 (e.g. `HOMEBREW_CASK_OPTS_BINARIES`, `HOMEBREW_NO_UPGRADE_AUTO_UPDATES_CASKS`). Replace them with the supported `HOMEBREW_CASK_OPTS` / cask-options forms.

These are transitional concerns inherent to a mature, continuously-released tool, not defects.

---

## 15. Quick Reference

### Key paths

```bash
brew --prefix        # install root (/opt/homebrew, /usr/local, /home/linuxbrew/.linuxbrew)
brew --cellar        # Cellar (installed formula kegs)
brew --caskroom      # Caskroom (installed casks)
brew --cache         # download cache
brew --repository    # Homebrew's own Git checkout
brew --taps          # Taps directory
```

### Operations cheat-sheet

```bash
brew doctor                       # diagnose
brew config                       # system info for bug reports
brew update && brew upgrade       # update everything
brew update-reset                 # hard-reset Homebrew repos (destructive)
brew bundle dump --global         # snapshot installed packages
brew bundle install --global      # restore them
sudo brew services start <name>   # system-wide service at boot
brew as-console-user <command>    # run as the console user (MDM)
```

### High-value configuration

```bash
export HOMEBREW_NO_AUTO_UPDATE=1            # control update timing (fleets)
export HOMEBREW_NO_ANALYTICS=1             # disable analytics
export HOMEBREW_NO_INSTALL_FROM_API=1      # use local taps (formula editing)
export HOMEBREW_ALLOWED_TAPS="..."          # restrict installable taps
export HOMEBREW_FORBIDDEN_LICENSES="GPL-3.0" # license policy
export HOMEBREW_VERIFY_ATTESTATIONS=1      # verify bottle provenance
```

### Authoritative source files

| File | What it defines |
|------|-----------------|
| `docs/Manpage.md` | Every command and flag (rendered to `man brew`). |
| `Library/Homebrew/env_config.rb` | Every `HOMEBREW_*` environment variable. |
| `Library/Homebrew/brew.rb` | Command dispatch and the global error/exit contract. |
| `Library/Homebrew/cli/parser.rb` | The option-parsing DSL. |
| `Library/Homebrew/cmd/` & `dev-cmd/` | Command implementations. |

---

_Generated June 2026 from Homebrew/brew at 5472a6b. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
