🧑💻 BrewUI
Homebrew's official macOS GUI: making package management approachable for users who prefer graphical interfaces over Terminal, while maintaining complete transparency about underlying Homebrew operations.
💡 Motivation
Enable CLI-averse users to safely discover, install, update and manage Homebrew packages through a native SwiftUI interface that never hides what Homebrew is doing.
📲 Tech
- Swift with strict concurrency · SwiftUI · Swift Package Manager
- Toolchain and macOS requirements: Package.swift, .swift-version and Xcode project
- Data from the
brewCLI and the Homebrew JSON API
📦 Installation
brew install --cask homebrew-app
Homebrew configuration
Put Homebrew options in brew.env and relaunch BrewUI after changing them. Shell aliases and
exported variables do not configure the app. See Homebrew configuration.
🛠️ Development
After cloning:
./scripts/bootstrap
This installs Mint from Brewfile, runs mint bootstrap to build the SwiftFormat and SwiftLint versions pinned in Mintfile, enables repository git hooks and resolves Swift package dependencies for Homebrew.xcodeproj.
After bootstrap, commits automatically run checks on staged Swift files:
mint run swiftformatmint run swiftlint(with--fix, then strict validation)
See development setup for signing configuration, conventions and testing for contributor guidance and architecture for system design.
🌍 Translations
Translations are community-sourced and a partial one is welcome: any string without a translation
falls back to English. Copy lives in one Localizable.xcstrings catalog per UI target, Homebrew/
for the window, sidebar and menus, and Resources/ in BrewUIComponents and each BrewFeature*
package. Edit a catalog in Xcode. See localisation for the reasoning
behind the steps below.
Adding a language
- Open
Homebrew/Localizable.xcstrings, press+, pick the language and translate at least one
scripts/localize verify fails. Adding it also records the language in knownRegions
in Homebrew.xcodeproj; commit that.
- Add the language to each package catalog you want to translate and do as much of it as you like.
- Never leave a translation blank. An empty value renders as empty text rather than falling back to
verify fails on a blank.
- Run
scripts/localize verify, thenscripts/localize statusto see how far the language has got.
Translating a string
- Find the catalog that holds it:
grep -rl "Run Again" Homebrew/Localizable.xcstrings Sources/*/Resources/Localizable.xcstrings.
- Read the comment before translating. It says where the string appears and what each
%@or
%lld stands for.
- Keep every format specifier the English has, and number them (
%1$@,%2$lld) if your language
- English needs only two plural forms, so the code picks between two keys itself (
1 packageand
%lld packages). A language with more categories varies the %lld key by plural
(Vary By Plural in Xcode) and translates 1 package as well.
- Mark the string as reviewed once you are happy with it. One left in Needs Review still ships,
- Run
scripts/localize verify.
Changing English copy
The key is the English text, so rewording a string makes a new entry rather than editing one.
- Change the literal in the Swift source, keeping
bundle: #bundleand updating thecomment:if
- Run
scripts/localize sync, which an Xcode build does for you. It adds the new key and marks the
"extractionState" : "stale", keeping its translations.
- Carry each translation over to the new key where the wording still means the same thing. Where it
- Delete the stale entry once its translations have been carried over or discarded. Nothing fails
- Commit the
.xcstringschanges with the code. CI compares the catalogs against the built sources
🚧 Status
Stable and under active development.
The read-only Services tab shows installed formula services, their status, owner, login registration and service/log paths. Filter by All, Running or Stopped; start, stop and configure services in Terminal.
📄 Licence
AGPL-3.0. If you reuse or adapt the source the AGPL terms apply, including the network-use clause.