关于 homebrew-cask-authoring
这是一项用于编写 Homebrew Cask 贡献的技能,补充样式检查无法判断的事项。它涵盖资格评估、Cask 结构、验证、清理规则及拉取请求流程。
主要功能
- 01Cask 资格与令牌命名
- 02安装及清理配置指导
- 03架构与操作系统专属 Cask
- 04审计、安装和 zap 验证
- 05拉取请求与 AI 披露规范
适用场景
- 01评估软件是否符合新增 Cask 的条件
- 02为 macOS 和 Linux 制品起草 Cask
- 03在审查前检查卸载和 zap 行为
- 04准备 Homebrew Cask 拉取请求
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ connorads/ dotfiles --skill homebrew-cask-authoring安装后在 Claude Code 中输入/homebrew-cask-authoring确认已加载。
附带文件references/homebrew-cask-contribution-workflow.md
详细介绍
Homebrew Cask 编写
Homebrew Cask 维护者会在不追问的情况下合并这项更改吗?
Homebrew 的 cops 和审计会强制执行布局、顺序和大多数语法要求。本技能涵盖它们无法处理的内容:资格、命名、清理路径、测试和 PR 行为。如果此处的规则与 brew style/brew audit 不一致,以工具为准——工具会跟进 Homebrew 的当前版本,而本文档不会。
操作规则
- 提交 PR 前,获取 homebrew-cask 自身的 Agent 政策并遵循:
gh api repos/Homebrew/homebrew-cask/contents/AGENTS.md -H 'Accept: application/vnd.github.raw'。 官方文档:Cask Cookbook、 Acceptable Casks。 - 保持 cask 精简:仅包含正确安装、卸载和清理所需的 stanza。
- 绝不要写
url ..., verified:。此写法已弃用且会被忽略;编辑任何 cask 时都应将其移除。 - 仅支持一种操作系统的 cask 必须在顶层声明
depends_on :macos(或带版本的depends_on macos: :<sym>)或depends_on :linux。制品类型不再隐含操作系统。 - 跨平台 cask 不应声明顶层操作系统依赖。应在
on_macos(app、pkg、suite等)或on_linux(app_image)中限定特定操作系统的制品;binary可跨平台使用。将depends_on macos:放在on_macos内——放在顶层会导致 Linux 不适用。 - 执行任何
rm、tap 或系统更改前,都要明确说明。测试后恢复 Homebrew 的标准状态,除非用户要求保留覆盖设置。
预检(新 cask)
- 知名度(政策): GitHub 项目的 fork 数或关注者数低于 30,或 star 数低于 75,很可能会被拒绝;如果 PR 作者拥有上游仓库,则门槛提高至 3 倍(90/90/225)。仅限 Linux 和 AppImage cask 不享有豁免。
- 存在时间:仓库和主页域名都必须至少存在 30 天,否则无论 cask 质量如何,
brew audit --new都会失败。 - Gatekeeper:macOS 制品必须经过签名和公证
(
spctl -a -vv <App>.app)。未签名的应用不符合资格;绝不要建议使用--no-quarantine或停用 Gatekeeper 作为变通方法。 - Rosetta:当 macOS 27 成为最新稳定版 macOS 后,新的
requires_rosetta/ 仅支持 x86_64 的 macOS cask 将不再符合资格。起草此类 cask 前请先确认。仅限 Linux 的 cask 不受此限制。 - 正确的仓库:没有已编译应用的开源 CLI 应归入 homebrew/core。被 homebrew/core 拒绝并不意味着它就符合 cask 的资格。
- 先例:搜索已关闭但未合并的 PR 和开放的 PR,查找该 token。 不要因无法解决的原因再次提交已被拒绝的内容。
- Linux 构建:检查上游是否提供 AppImage。审核者会要求新 cask 提供它,因此若存在就应一并加入。
- 预发布版本:如果上游将每个 GitHub 版本都标记为预发布版本,在线审计会失败,并显示
<tag> is a GitHub pre-release。在同一提交中,将"<token>": "all"加入audit_exceptions/github_prerelease_allowlist.json(先例:agent-tars、duplicati);如果之后出现非预发布版本,"all"也会报错。将其插入相邻条目旁——该文件并未严格排序,因此重新排序会产生与当前更改无关的 diff。请在 PR 正文中说明理由。
工作流
1) 令牌
先运行 brew generate-cask-token "<App Name>.app",再应用它未涵盖的判断规则:
- 除非该应用不是移植版,且「Mac」与名称不可分割(
playonmac),否则删除「Mac」。 - 默认删除「Desktop」。一位维护者为桌面应用接受了
executor,之后 Homebrew/core 中的 CLI 使用了executor-cli。哪个组件先进入 Homebrew,裸名称就归哪个组件。 - 仅当「Desktop」是品牌名称(
docker-desktop、ltx-desktop),或 Homebrew 中已经存在以裸名称命名的同系列项目时,才保留「Desktop」。仅存在于上游(npm、crates.io)的 CLI 不构成理由。 cask token mentions desktop审计仅在严格模式下运行(即使用--new时触发)。无论如何选择,都要在 PR 正文中说明理由。- 变体:
@beta、@nightly、@latest、@<major>。
写入文件前,先让用户确认令牌。
2) 起草
使用 brew create --cask <url> --set-name <token> 创建模板,然后精简为:
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:描述事实,不含营销内容,不出现平台相关措辞(如「适用于 macOS」),少于 80 个字符。- 如果应用需要更新的最低系统版本,将
depends_on :macos替换为depends_on macos: :<sym>。brew audit --cask --online --fix <token>会从应用包中推导该值,但仅适用于没有on_*块的 cask。符号表:请参阅参考资料。
3) 架构
检查二进制文件,而非厂商宣传:
lipo -archs "/Volumes/<Vol>/<AppName>.app/Contents/MacOS/<AppName>"
- 仅支持
arm64:添加depends_on arch: :arm64,否则 Intel 用户会安装无法运行的应用。 - 通用版:无需架构限制。
- 不同 CPU 提供不同下载、但版本相同:使用
arch arm: ..., intel: ...,并配合sha256 arm: ..., intel: ...。 - 不同 CPU 提供不同版本:使用
on_arm/on_intel块。
4)卸载与清理
pkg和installer(pkgutil:、launchctl:等)必须使用uninstall。uninstall quit:会在卸载、升级和重新安装时运行;Homebrew 会在升级后重新打开应用。除非设置on_upgrade: :signal,否则升级时会跳过signal:。- 如果模态窗口(例如首次运行时的权限面板)阻塞了应用的运行循环,应用可能会忽略
quit:。CI 的 zap-check 会在全新运行器上启动应用,因此会遇到这个问题,而已授予权限的本地安装则不会;随后 CI 会因“Some launch jobs were not unloaded”而失败。signal:在 macOS 26 上不起作用:Homebrew 会通过 launchd 标签查找进程,而标签现在以 UUID 结尾(application.<id>.<n>.<n>.<UUID>),会被其模式拒绝。请在quit:旁使用launchctl: "application.<bundle-id>.*"(先例:shutter-encoder、cmux);移除任务即可结束进程。 launchctl:会再次使用sudo检查每个任务,因此即使是用户级任务,本地卸载也会提示输入密码。非 sudo 检查已将其移除;取消密码提示是安全的。CI 的 sudo 无需密码。- 如果应用有辅助进程(
Contents/Helpers/,或运行时执行pgrep -lf <AppName>能查到),quit:中必须包含每个 bundle ID。只要 ID 至少包含 3 个以点分隔的部分,就可以使用通配符("com.vendor.*")。 zap对审核而言是可选项,但评审者期望新 cask 包含此项:- 安装、启动并使用应用(登录、实际操作)——某些路径(
~/Library/HTTPStorages/<id>、会话缓存)只有使用后才会出现。 - 运行
brew generate-zap <token>(如果 cask 尚不存在,则使用--name "<App Name>")。如果出现提示要求授予完全磁盘访问权限的错误,请将权限授予终端后重试。检查输出;其中包含无关内容。 generate-zap会涵盖~/Library和~/.<app>点目录,不包括 XDG 路径。如果执行--zap并重新安装后状态仍然保留,请在上游源码中搜索os.homedir()、env-paths、xdg。 它也只会匹配应用名称,因此当状态以 CLI 或 token 命名时(~/Library/Caches/<cli>),会报告“无需 zap 段落”。还应在~/Library中搜索 token 和 bundle ID,并在上游源码中搜索路径拼接代码;有些目录只有在使用某项功能后才会出现。- 提交 PR 后,查看 CI 的 zap-check 作业摘要,了解它认为缺失的路径。
- 安装、启动并使用应用(登录、实际操作)——某些路径(
- Keystone/GoogleUpdater 风格的共享组件只能放在
zap中,绝不能放在uninstall中。
5)livecheck
- 如果默认检查能找到版本,就省略
livecheck。只有确实有需求时(预发布版本、没有资源文件的发布版本、来源有误)才添加代码块。 - 对于 Sparkle 应用,使用
brew find-appcast <path>.app查找其 feed。 :github_latest/:github_releases仅在选择启用时使用;Git 标签或上游 feed 不可用时才使用。它们匹配的是tag_name,而不是资源文件名。strategy :extract_plist和version :latest会自动从 autobump 中排除;无需使用no_autobump!。
6)跨平台(macOS + Linux AppImage)
- 每个操作系统对应的字符串应放在顶层
arch(intel: on_system_conditional(macos: "x64", linux: "x86_64"))、os或局部on_system_conditional中——都必须放在version之前。 - 使用一个顶层
sha256,并按arm:、intel:、arm64_linux:、x86_64_linux:键控(只包含实际存在的键)。绝不要将sha256嵌套在on_macos/on_linux中。 on_macos/on_linux代码块放在sha256之后、url之前。app_image "<file>", target: "<App>.AppImage"——目标中不得包含版本号。
四架构、单架构 Linux、通用 macOS 的模板,depends_on macos: 符号表以及 app_image 的行为,参见
references/homebrew-cask-contribution-workflow.md。
7) 验证
从本地的 homebrew/cask 检出目录运行(设置方法:参考资料):
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 audit不会输出任何内容。 brew lgtm会与本地main分支而不是origin/main比较差异。在过期的检出目录中,它会审计上游更改过的所有 cask(并下载其制品)。先运行git fetch origin && git rebase origin/main,然后运行git branch -f main origin/main;git diff --name-only main应只列出你的文件。- 仅使用
--online时只审计主机 OS/架构;--os=all --arch=all则可在 Mac 上覆盖on_linux。 - 按 token 安装和卸载,切勿使用文件路径。
- 在 TTY(tmux、Agent PTY)中,如果
brew install要拉取依赖项,会要求确认;请传入-y。
在应用运行时验证 zap:
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:
普通 uninstall 后重新安装应保留登录状态;使用 --zap 后则不应保留。这可以确认 zap 针对的是真实用户状态。
uninstall --zap 使用安装时记录的段落(Caskroom/<token>/.metadata/),而不是你的工作副本。编辑 zap 后:先卸载,再安装,然后运行 uninstall --zap。
8) PR
- 为现有 cask 更新版本:
brew bump --open-pr <token>(或brew bump-cask-pr <token> --version <new>)。手动流程适用于新建 cask 和更改段落。 - 每个 PR 提交一个 cask,尽量缩小差异,不顺手调整格式。基准分支为
main。 - 提交主题(不超过 50 个字符):
token 1.2.3 (new cask)、token 1.2.3或token: description。 - 开 PR 时,每个 cask 只提交一个提交。开 PR 后,将审查和 CI 修复作为新提交推送(参见 homebrew-cask
AGENTS.md)。仅在维护者要求时才压缩提交;CONTRIBUTING.md 和文档介绍了压缩提交,因此请预期会收到此要求。 - PR 正文:保留模板。在检查清单上方添加一句说明文字(“为 App 添加一个 cask,……”),不要只放一个 URL。仅勾选已完成的项目。 不要添加冗长日志或 AI 分析。
9) AI 使用披露
遵循 负责任地使用 AI 和模板:
- 人类只有在审查输出(包括
zap路径)后,才勾选 AI 复选框。 - 在其下方简要说明:使用的工具/模型、使用方式,以及人类手动验证的内容(安装、登录、使用、推导 zap、应用运行时卸载)。提及测试中发现的任何不明显问题,例如某个辅助程序需要第二个
quit:ID。 - 提交中不要添加
Co-Authored-By、Assisted-by或类似的 AI 尾注。 - 人类应不借助 AI 回答维护者的问题和审查意见。Agent 不会起草或发布这些回复。
- 非维护者同一时间最多只能有一个 AI 辅助的 PR 处于打开状态。