Official Homebrew tap for AntiBrow. Install and update the
macOS desktop app with brew.
brew tap antibrow/tap
brew install --cask antibrowOr in one line:
brew install --cask antibrow/tap/antibrowUpdate and remove:
brew upgrade --cask antibrow
brew uninstall --cask antibrow # removes the app, keeps your data
brew uninstall --zap --cask antibrow # also removes data and caches, see belowSince Homebrew 6.0, the first install from a third-party tap asks for confirmation
once. Answer yes; the decision is recorded in ~/.homebrew/trust.json and you are
not asked again. To trust the whole tap up front:
brew trust --tap antibrow/tap| Download | https://download.antibrow.com/desktop/AntiBrow-<version>.dmg |
| Installs to | /Applications/AntiBrow.app |
| Bundle ID | com.antibrow.desktop |
| Architecture | Universal binary (x86_64 + arm64), one build for Intel and Apple Silicon |
| Minimum macOS | 11 Big Sur |
| Notarization | Notarized by Apple (spctl reports Notarized Developer ID) |
| Self-update | Ships electron-updater, so the app also updates itself |
Because the app carries its own updater, both brew upgrade and the in-app updater
work. The version in the cask mainly serves first-time installs and brew info.
A plain brew install conflicts with an existing /Applications/AntiBrow.app.
Two ways out:
# Same version as the cask: take over the existing app without re-downloading
brew install --cask --adopt antibrow/tap/antibrow
# Different version, or you just want a clean reinstall
brew install --cask --force antibrow/tap/antibrowzap is opt-in. A plain uninstall never touches any of this.
~/Library/Application Support/anti-detect-desktop # profiles and fingerprints
~/Library/Caches/anti-detect-desktop-updater # updater downloads, can be hundreds of MB
~/Library/Caches/com.antibrow.desktop
~/Library/Caches/com.antibrow.desktop.ShipIt
~/Library/HTTPStorages/com.antibrow.desktop
~/Library/Preferences/com.antibrow.desktop.plist
~/Library/Saved Application State/com.antibrow.desktop.savedState
The first entry is user data. Use brew uninstall without --zap to keep it.
./scripts/bump-cask.sh --check # check only; exit 0 = up to date, 10 = update available
./scripts/bump-cask.sh # rewrite version + sha256 from the manifestOne source: https://download.antibrow.com/desktop/latest-mac.yml, the
electron-builder manifest the app's own updater reads. livecheck uses it too, via
strategy :electron_builder.
The manifest carries the version and, per artifact, both a sha512 and a sha256. A cask needs the sha256, so a bump reads it straight out and touches nothing else. Measured on 2026-08-17: about 1 second, versus roughly 2 minutes and a 220 MB download back when the sha256 had to be computed locally.
Two things the parsing has to get right:
- Read the sha256 from the DMG's entry, not the top level. The manifest repeats
sha512/sha256 at the top level for whatever
path:points at, which is the.zip, and those lines sit after the DMG's entry in the file. A naive "first sha256 after the dmg url" silently picks up the.zip's hash whenever the DMG entry lacks the field, and produces a cask that fails to install with a checksum mismatch.dmg_field()scopes to the entry and returns nothing instead. - Keep a fallback. If a future manifest omits the DMG's sha256, the script
downloads the DMG, checks it against the manifest's sha512, and hashes it locally.
Both paths are exercised; point the script at a test manifest with
ANTIBROW_FEED=http://... ./scripts/bump-cask.sh.
Nothing here trusts the manifest blindly at the end: CI performs a real
brew install --cask, so a wrong sha256 fails the job before anything is committed.
.github/workflows/bump.yml runs the script daily at 06:17 UTC. When a new version
appears it runs brew style, brew audit --new --strict --online and an
install/uninstall smoke test in the same job, and only commits to main if all of
them pass.
Verifying inside the bump workflow is deliberate. Commits pushed with GITHUB_TOKEN
do not trigger other workflows, so expecting ci.yml to run after the push would not
work.
Symlink this repo into Homebrew's Taps directory so edits here take effect immediately:
mkdir -p "$(brew --repository)/Library/Taps/antibrow"
ln -s "$PWD" "$(brew --repository)/Library/Taps/antibrow/homebrew-tap"
brew style antibrow/tap
brew audit --new --strict --cask --online antibrow/tap/antibrow
brew fetch --cask antibrow/tap/antibrow # checks url + sha256, leaves /Applications alone
brew livecheck --cask antibrow/tap/antibrow # checks that livecheck reads upstream correctlyThings that will trip you up:
brew styledoes not only check.rbfiles. It runs shfmt and shellcheck overscripts/too, and shfmt wantsthenon its own line.brew style --fix antibrow/tapfixes it automatically.- Do not embed multi-line Python (or any indentation-sensitive heredoc) inside a
shell script here.
brew style --fixreindents such strings and silently changes the block structure, and neitherbash -nnorbrew styleflags the result. It happened once during development and broke parsing with no error at all. Keep anything indentation-sensitive in its own file. - The string comparison form of
depends_on macos:(">= :big_sur") is deprecated. Use the bare symbol:big_sur, which already means "that version or newer". Note the underscore;:big-suris not a valid symbol. - The
verified:parameter onurlis deprecated. Do not add it, or--new --strictfails. - In zsh, do not write
brew audit $flags. zsh does not word-split unquoted variables, so the whole string arrives as a single argument.
Homebrew resolves brew tap <owner>/<name> to the GitHub repository
<owner>/homebrew-<name>; internally it is literally "homebrew-#{repository}".
So the only hard rule is the homebrew- prefix. The part after it is arbitrary and
becomes the short name users type:
| GitHub repository | Tap command |
|---|---|
antibrow/homebrew-tap |
brew tap antibrow/tap |
antibrow/homebrew-antibrow |
brew tap antibrow/antibrow |
antibrow/homebrew-cask |
brew tap antibrow/cask |
homebrew-tap is just the shortest and the most common convention.
The local working directory name is irrelevant. Homebrew only cares about the path
Library/Taps/<owner>/homebrew-<name>, which is a clone or a symlink it controls.
This repo lives in a directory named antibrow-tap and resolves as antibrow/tap
without issue.
For further products, one tap per GitHub owner is the cleaner split:
antibrow/homebrew-tap -> brew tap antibrow/tap -> Casks/antibrow.rb
otherproduct/homebrew-tap -> brew tap otherproduct/tap -> Casks/otherproduct.rb
Each product's install command then carries its own brand, and each repo has its own
CI and release cadence. Locally, name the directories <product>-tap so they do not
collide.
The alternative, one personal tap holding every product, works too. Just drop more
files into Casks/ (or Formula/ for command-line tools) of a single repo, and give
ci.yml a matrix over them. The cost is that the install command shows an account
name unrelated to the product being installed, which reads as unofficial. Only worth
it if several products share one GitHub account.
CI derives the tap owner from GITHUB_REPOSITORY, so moving this repo to another
account or org needs no workflow changes. Only the antibrow/tap strings in this
README need updating.
Not yet. Homebrew's Package Acceptance Policy judges a project's notability by stars,
forks and watchers on the canonical upstream repository, and states that projects less
than 30 days old are generally ineligible. As of 2026-08-14, github.com/antibrow/antibrow
had 2 stars, 0 forks and 0 watchers and was created on 2026-07-29, so it fails both.
Submitting now would very likely be rejected, and rejections leave a record.
Notability is the only thing missing. The distribution requirements are already met: hosted on a developer-owned domain, versioned URL, no account needed to download, signed and notarized, and an electron-builder manifest that livecheck can follow.
Casks/antibrow.rb also already clears the bar an official submission has to meet.
Measured on 2026-08-17, brew audit --new --strict --cask --online exits 0 with zero
offenses. Once notability is there, this exact file can be moved into homebrew-cask
as a PR with no rewriting.
The point of running it in an own tap first is that the eventual submission is a file CI has validated repeatedly across several releases, rather than something written the day of the PR.
BSD-2-Clause, see LICENSE.