homebrew-cask-authoring
Create, update, validate, and submit Homebrew Casks (macOS and Linux/AppImage). Use when the user mentions Homebrew cask/cask, Homebrew/homebrew-cask, adding a new cask, updating or bumping a cask, cask token naming, generate-cask-token, sha256, livecheck, zap/uninstall, AppImage/app_image, on_linux/on_macos, cross-platform cask, or when asked to run brew style, brew audit or brew lgtm for a cask.
How do I install this agent skill?
npx skills add https://github.com/connorads/dotfiles --skill homebrew-cask-authoringIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill provides a standard and comprehensive workflow for authoring Homebrew casks. It utilizes common developer tools for binary analysis, file system management, and version control via GitHub. All external references are to trusted or well-known services.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
- Runlayerpass
2/2 files flagged
- ZeroLeakspass
Score: 93/100 · 2 sections analyzed
What does this agent skill do?
Homebrew Cask Authoring
Would a homebrew-cask maintainer merge this without asking a question?
Homebrew's cops and audits enforce layout, ordering and most syntax. This skill
covers what they can't: eligibility, naming, cleanup paths, testing and PR
conduct. When a rule here and brew style/brew audit disagree, the tool wins -
it tracks Homebrew's current release, this file doesn't.
Operating rules
- Fetch homebrew-cask's own agent policy before a PR and follow it:
gh api repos/Homebrew/homebrew-cask/contents/AGENTS.md -H 'Accept: application/vnd.github.raw'. Official docs: Cask Cookbook, Acceptable Casks. - Keep casks minimal: only stanzas required for correct install, uninstall and cleanup.
- Never write
url ..., verified:. It is deprecated and ignored; drop it from any cask you edit. - A cask supporting one OS needs a top-level
depends_on :macos(or a versioneddepends_on macos: :<sym>) ordepends_on :linux. Artifact type no longer implies the OS. - A cross-platform cask has no top-level OS dependency. Gate OS-specific artifacts
inside
on_macos(app,pkg,suite, ...) oron_linux(app_image);binaryis portable. Putdepends_on macos:insideon_macos- at top level it drops Linux. - Call out any
rm, tap or system change before running it. Restore standard Homebrew state after testing unless the user asks to keep the override.
Pre-flight (new casks)
- Notability (policy): GitHub projects under 30 forks/watchers or 75 stars are likely rejected; 3x (90/90/225) when the PR author owns the upstream repo. Linux-only and AppImage casks get no exemption.
- Age: the repo and the homepage domain must be at least 30 days old, or
brew audit --newfails regardless of cask quality. - Gatekeeper: macOS artifacts must be signed and notarised
(
spctl -a -vv <App>.app). Unsigned apps are ineligible; never suggest--no-quarantineor disabling Gatekeeper as a workaround. - Rosetta: new
requires_rosetta/ x86_64-only macOS casks become ineligible once macOS 27 is the latest stable macOS. Check before drafting one. Linux-only casks are exempt. - Right repo: an open-source CLI with no compiled app belongs in homebrew/core. A homebrew/core rejection does not make it eligible as a cask.
- Prior art: search closed unmerged PRs and open PRs for the token. Don't resubmit a refusal for an unfixable reason.
- Linux build: check whether upstream ships an AppImage. Reviewers ask for it on new casks, so include it when it exists.
- Pre-releases: if upstream marks every GitHub release pre-release, the
online audit fails with
<tag> is a GitHub pre-release. Add"<token>": "all"toaudit_exceptions/github_prerelease_allowlist.jsonin the same commit (precedent:agent-tars,duplicati);"all"also errors if a non-pre-release appears later. Insert beside its neighbours - the file is not strictly sorted, so re-sorting it is a drive-by diff. Justify it in the PR body.
Workflow
1) Token
Start from brew generate-cask-token "<App Name>.app", then apply the judgement
rules it doesn't:
- Remove "Mac" unless the app is not a port and "Mac" is inseparable from the name (
playonmac). - Drop "Desktop" by default. A maintainer accepted
executorfor a desktop app, with a later homebrew/core CLI takingexecutor-cli. The bare name goes to whichever component lands in Homebrew first. - Keep "Desktop" only when it is the brand (
docker-desktop,ltx-desktop) or a sibling already exists in Homebrew under the bare name. A CLI that exists only upstream (npm, crates.io) is not a reason. - The
cask token mentions desktopaudit is strict-only (fires under--new). Justify the choice in the PR body either way. - Variants:
@beta,@nightly,@latest,@<major>.
Confirm the token with the user before writing the file.
2) Draft
Scaffold with brew create --cask <url> --set-name <token>, then trim to:
cask "token" do
version "1.2.3"
sha256 "..."
url "https://example.com/app-#{version}.dmg"
name "Official App Name"
desc "Short one-line description"
homepage "https://example.com/"
depends_on :macos
app "AppName.app"
end
desc: factual, no marketing, no platform words ("for macOS"), under 80 chars.- Swap
depends_on :macosfordepends_on macos: :<sym>when the app needs a newer floor.brew audit --cask --online --fix <token>derives it from the bundle, but only for casks with noon_*blocks. Symbol table: the reference.
3) Architecture
Check the binary, not vendor marketing:
lipo -archs "/Volumes/<Vol>/<AppName>.app/Contents/MacOS/<AppName>"
arm64only: adddepends_on arch: :arm64, or Intel users install an app they can't run.- Universal: no arch gate.
- Per-CPU downloads, same version:
arch arm: ..., intel: ...plussha256 arm: ..., intel: .... - Per-CPU versions:
on_arm/on_intelblocks.
4) uninstall and zap
uninstallis required forpkgandinstaller(pkgutil:,launchctl:, ...).uninstall quit:runs on uninstall, upgrade and reinstall; Homebrew reopens the app after an upgrade.signal:is skipped on upgrade unlesson_upgrade: :signal.- An app can ignore
quit:when a modal window (a first-run permissions panel) blocks its run loop. CI's zap-check launches the app on a fresh runner, so it hits this where a granted local install does not; CI then fails with "Some launch jobs were not unloaded".signal:does not help on macOS 26: Homebrew finds processes by launchd label, and the label now ends in a UUID (application.<id>.<n>.<n>.<UUID>) that its pattern rejects. Uselaunchctl: "application.<bundle-id>.*"besidequit:(precedent:shutter-encoder,cmux); removing the job ends the process. launchctl:checks each job again withsudo, so a local uninstall prompts for a password even for a user-level job. The non-sudo pass has already removed it; cancelling the prompt is safe. CI's sudo is passwordless.- An app with helper processes (
Contents/Helpers/, orpgrep -lf <AppName>while running) needs every bundle ID inquit:. A wildcard works if the ID keeps at least 3 dot-separated parts ("com.vendor.*"). zapis optional for audit but expected by reviewers for new casks:- Install, launch and use the app (log in, real work) - some paths
(
~/Library/HTTPStorages/<id>, session caches) only appear after use. - Run
brew generate-zap <token>(or--name "<App Name>"before the cask exists). If it errors asking for Full Disk Access, grant it to the terminal and rerun. Review the output; it includes noise. generate-zapcovers~/Libraryand~/.<app>dotfolders, not XDG paths. If state survives--zap+ reinstall, grep upstream source foros.homedir(),env-paths,xdg. It also matches only the app name, so it reports "No zap stanza required" when state is named after the CLI or token (~/Library/Caches/<cli>). Search~/Libraryfor the token and bundle ID too, and grep upstream source for path joins; some directories only appear once a feature is used.- After opening the PR, read CI's zap-check job summary for paths it thinks are missing.
- Install, launch and use the app (log in, real work) - some paths
(
- Keystone/GoogleUpdater-style shared components go in
zaponly, neveruninstall.
5) livecheck
- Omit
livecheckwhen the default check finds the version. Add a block only for a demonstrated need (pre-releases, releases without assets, wrong source). - For a Sparkle app, find its feed with
brew find-appcast <path>.app. :github_latest/:github_releasesare opt-in only; use them when Git tags or an upstream feed won't work. They matchtag_name, not asset names.strategy :extract_plistandversion :latestare excluded from autobump automatically; nono_autobump!needed.
6) Cross-platform (macOS + Linux AppImage)
- Per-OS strings live in top-level
arch(intel: on_system_conditional(macos: "x64", linux: "x86_64")),os, or anon_system_conditionallocal - all beforeversion. - One top-level
sha256keyedarm:,intel:,arm64_linux:,x86_64_linux:(only the keys that exist). Never nestsha256inon_macos/on_linux. on_macos/on_linuxblocks go aftersha256, beforeurl.app_image "<file>", target: "<App>.AppImage"- the target must not contain a version.
Templates (four-arch, single-arch Linux, universal macOS), the depends_on macos:
symbol table and app_image behaviour are in
references/homebrew-cask-contribution-workflow.md.
7) Validate
Run from a local homebrew/cask checkout (setup: the reference):
brew style --fix <token>
brew audit --cask --online --os=all --arch=all <token>
brew audit --cask --new <token> # new casks; implies --strict --online
brew lgtm --online # final gate; stage the cask first
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --cask <token>
brew uninstall --cask <token>
brew auditis silent on success.brew lgtmdiffs against the localmainbranch, notorigin/main. In a stale checkout it audits every cask upstream changed since (downloading their artifacts). Firstgit fetch origin && git rebase origin/main, thengit branch -f main origin/main;git diff --name-only mainshould list only your files.- Plain
--onlineaudits only the host OS/arch;--os=all --arch=allcoverson_linuxfrom a Mac. - Install and uninstall by token, never by file path.
- On a TTY (tmux, agent PTY),
brew installasks for confirmation when it pulls dependencies; pass-y.
Validate zap with the app running:
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --cask <token>
open "/Applications/<AppName>.app" # log in, use it
brew uninstall --zap --cask <token>
pgrep -lf <AppName> # empty, or add bundle IDs to uninstall quit:
Reinstall after plain uninstall should keep the login; after --zap it should
not. That confirms zap targets the real user state.
uninstall --zap uses the stanzas recorded at install time
(Caskroom/<token>/.metadata/), not your working copy. After editing zap:
uninstall, install, then uninstall --zap.
8) PR
- Version bump of an existing cask:
brew bump --open-pr <token>(orbrew bump-cask-pr <token> --version <new>). The manual flow is for new casks and stanza changes. - One cask per PR, minimal diff, no drive-by formatting. Base branch
main. - Commit subject (<=50 chars):
token 1.2.3 (new cask),token 1.2.3, ortoken: description. - One commit per cask when opening. After opening, push review and CI fixes as
new commits (homebrew-cask
AGENTS.md). Squash only when a maintainer asks; CONTRIBUTING.md and the docs describe squashing, so expect that request. - PR body: keep the template. Add one prose sentence above the checklist ("Adds a cask for App, a ..."), not a bare URL. Tick only what was done. No verbose logs or AI analysis.
9) AI disclosure
Follow Responsible AI Usage and the template:
- The human ticks the AI checkbox only after reviewing the output, including
zappaths. - Below it, briefly: the tool/model, how it was used, and what the human verified
by hand (install, login, use, zap derivation, running-app uninstall). Mention
anything non-obvious testing surfaced, such as a helper needing a second
quit:ID. - No
Co-Authored-By,Assisted-byor similar AI trailers on commits. - The human answers maintainer questions and review comments without AI. The agent does not draft or post them.
- Non-maintainers may have only one AI-assisted PR open at a time.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/connorads/dotfiles/homebrew-cask-authoring">View homebrew-cask-authoring on skillZs</a>