Files
.pouch/skills/builder

builder

按统一契约完成项目的 DEB 包、Docker 镜像、Android APK / iOS IPA 构建和发布, 或把产物拷到目录 / 容器。规范本体见 references/contract.md,scripts/check.py 是契约的 可执行校验器。

构建执行位置使用共享 .pouch/agent.yaml 的任意 builder.<name> binding 配置;本地 Android、远程 Mac iOS 或未来其它平台都可以各自绑定 environment/project/path/profile。

什么时候使用

  • "用 builder 初始化这个项目"
  • "帮我构建这个项目的 DEB / Docker 镜像 / APK"
  • "把 1.2.3 发布到包仓库 / 镜像仓库 / File Browser"
  • "检查这个项目的 makefile.builder 是否符合 builder 契约"
  • "看看项目现在的发布流程"

只构建不上传时明确说明即可;上传永远需要你显式授权。

安装

pouch add builder          # 当前项目
pouch add builder -g       # 全局

不要 pouch init builder。对新项目说「用 builder 初始化」。

使用前准备

  • Python 3 和 make。
  • DEB 轨道需要 dpkg-deb;Docker 轨道需要 Docker 和 buildx。
  • 发布时在项目根 .env.builder 填写仓库地址和 token(不要写进 .env,也不要进 git)。
  • 正式版本号由 releaser 打 annotated tag;builder 只读当前 HEAD。
  • 脏工作树默认拒绝发布。

项目接入契约

对新项目说「用 builder 初始化」。Agent 会探测轨道、按 templates/makefile.builder 写出项目根 makefile.builder,并列出缺的发布配置。 不改用户已有的 Makefile 或 .env。

配置跟随 makefile.builder 所在的 Git 根。如果 APK/IPA 位于 Git submodule, 就在 submodule 内配置 .env.builder 和 .pouch/builder/;父仓库只固定 submodule commit 并负责上层编排。

  1. makefile.builder 目标:help/build/clean/version + 条件 deb/docker/push*, 变量 ARCHES/ARCH/VERSION/DIST_DIR/PROJECT_NAME。 VERSION 通过 include <builder>/scripts/version.mk 从 Git 推导。 多架构清单是 ARCHES,见下方「多架构」。
  2. 运行 python3 -I -S <builder>/scripts/check.py . --ready 直到构建项 PASS。 缺发布键只挡住上传,不挡住构建。
  3. 在项目根 .env.builder 配置发布环境变量(不要写进 .env)。项目内 APK/IPA 分发脚本的路径写在 makefile.builder 的 COPY_SCRIPT,脚本接收产物路径作为位置参数; 未配置项目脚本时使用 COPY_DEST 的本地目录或容器目录后备逻辑:
DEB_SERVER_URL=https://deb.example.com
DEB_REPOSITORY=main
DEB_TOKEN=<token>            # 只放 .env.builder 或密钥系统,不进 git
DOCKER_REGISTRY=registry.example.com
COPY_DEST=file-server:/srv
COPY_AS=latest.apk
# COPY_SCRIPT=                 # 仅外部/临时脚本覆盖;项目内脚本写 makefile.builder
  1. 日常发布就是两条命令: make -f makefile.builder deb && make -f makefile.builder push-deb、 make -f makefile.builder push-docker。 写了 ARCHES=amd64 arm64 时,这两条会打出并上传两个 DEB;镜像一次推多平台。

跨机器或需要继续查看的构建先用 agent-runtime 精确解析 binding 和 Orca worktree; builder 只在授权后执行对应 makefile.builder target,不自动上传。

多架构

项目要发哪些 CPU 架构,写在已提交的 makefile.builder 里,不要写进 .env.builder(那是密钥,换机器会丢)。

ARCHES ?= amd64 arm64

ARCH 是「这一次」:默认等于清单第一项。不传 ARCH= 时,deb / push-deb 按清单逐个做完;push-docker 把清单映射成 linux/amd64,linux/arm64。 只做其中一个:make -f makefile.builder deb ARCH=arm64。

合法值只有 amd64 和 arm64(空格分隔)。不要默认写成双架构:本机编不出 另一边时,只留一项。

make -s -f makefile.builder arches    # 打印清单,例如 amd64 arm64
make -f makefile.builder deb          # 打出两个 .deb
make -f makefile.builder push-deb     # 两个都上传(需你授权发布)
make -f makefile.builder push-docker  # 一次 buildx 推两个平台

产物:

dist/<name>_<version>_amd64.deb
dist/<name>_<version>_arm64.deb

build 配方必须用 $(ARCH),否则两个包内容会一样。初始化时 Agent 按仓库里 已有命令来写(Go 一般是 GOOS=linux GOARCH=$(ARCH) go build …),不另做一套 运行时探测脚本。看不出交叉编法就不要写双架构。

packaging/DEBIAN/control 的 Architecture: 必须随 $(ARCH) 变,不要写死 amd64。模板会先拷到 dist/packaging-$(ARCH) 再改这一行。

本机临时只推一个平台,可以在 .env.builder 设 PLATFORMS=linux/amd64,这是 覆盖不是清单。项目清单始终以 ARCHES 为准。

存量 makefile.builder 没有 ARCHES 时行为与以前相同(默认 amd64, ARCH=arm64 仍合法)。要改成双架构:加上面那一行,确认 build 吃 $(ARCH), 再跑 python3 -I -S <builder>/scripts/check.py . --ready。

版本号

产物版本从 当前 HEAD 的 Git 祖先 推导,不调用 releaser。 正式 tag 仍由 releaser 创建;builder 只读取。完整规则见 contract.md「版本号」。

谁 做什么
releaser 选定下一个正式 SemVer,打 annotated tag vX.Y.Z
builder 读 HEAD:落在稳定 tag 上则打正式产物,否则打测试产物
make -f makefile.builder version 输出一行规范版本(无 v 前缀),DEB / Docker 都从它渲染

不要用 git tag \| sort -V \| tail -1 取全仓库最大号,也不要把 git describe --dirty 的原始字符串写进 DEB 或镜像 tag。

正式(HEAD 恰好是稳定 tag v1.4.2)

Git tag      v1.4.2
规范版本     1.4.2
DEB          foo_1.4.2_amd64.deb          Version: 1.4.2
Docker       registry/ns/foo:1.4.2

稳定 tag 仅匹配 v<major>.<minor>.<patch>,不含 -rc、-app-N 等后缀。 不是 exact-match 就不是正式包。

测试(其它任何 commit)

基线 = 祖先上最近的那颗稳定 tag(没有则为 0.0.0)。有基线时测试号把 patch 机械 +1,再加构建时间 YYYYMMDDTHHMM、清洗后的分支名、相对距离、短 SHA。 这是排序键,不是在选定下一正式 SemVer。测试与正式进同一个 apt / Docker 仓库,所以 DEB 必须用 ~ 挂在下一 patch 上:1.4.2 < 1.4.3~20260918T1430… < 1.4.3。已装上一正式版的机器可以升到 bugfix 测试包; 同号正式版仍盖住测试。

分支 feat/login-v2,相对 v1.4.2 第 7 个 commit,SHA abc1234, 构建时间 20260918T1430(带分钟,同一天重建才排得对):

规范 / DEB   1.4.3~20260918T1430.feat-login-v2.7+gabc1234
文件名       foo_1.4.3~20260918T1430.feat-login-v2.7+gabc1234_amd64.deb
Docker       registry/ns/foo:1.4.3-20260918T1430.feat-login-v2.7.gabc1234

Docker tag 由规范版本映射:~ → -,+g → .g(Docker 不允许 ~)。 无参 apt upgrade 会从上一正式版升到下一 patch 的测试包,但不会盖住同号 正式包。生产若不能自动吃到测试包,应拆仓库/组件。构建时间取本机当前本地 时间(含分钟);设了 SOURCE_DATE_EPOCH 则用该时刻的 UTC 时间。+g<sha> 只用于记录 commit、不参与排序:只写到日期时,同一天重复构建的版本只差 +g<sha>,Debian 版本比较把哈希当普通文本比,会把新包判成比旧包小。 注意切换格式当天:Debian 把字母排在标点之前,20260918T1430… 小于旧格式 的 20260918.…,同一天已上传的旧格式包仍会压住新包,需要在仓库里把那些 旧包移除或停用;从第二天起新格式始终更大。

分支名清洗

小写;/、_ 改为 -;去掉其它非法字符;压缩连续 -;过长截断。 detached HEAD 用 detached,CI 可注入 BUILD_BRANCH / CI_COMMIT_BRANCH / GITHUB_REF_NAME。脏工作树不把 -dirty 写进版本(发布本身会拒绝)。

使用示例

用 builder 初始化这个项目。
用 builder 检查这个项目的 makefile.builder 是否符合契约。
用 builder 构建当前版本的 DEB 和镜像,先不要上传。
用 builder 把当前 commit 的产物发布到项目已配置的仓库。
用 builder 发布多平台 linux/amd64,linux/arm64 镜像。
用 builder 把当前版本的 amd64 和 arm64 DEB 打出来并发布。
用 builder 打一份测试 APK 并拷到 File Browser。

Agent 会做什么

  1. 初始化:探测 DEB / Docker / Android / iOS / copy 轨道,写出 makefile.builder 和 .env.builder 骨架,按仓库证据填 ARCHES(不默认双架构),不改你已有的 Makefile 或 .env。
  2. 检查:只跑 scripts/check.py --ready,不改文件。
  3. 构建:走 make -f makefile.builder;只获构建授权时不走会自动上传的目标。
  4. 发布:先校验产物,再上传。缺发布键、未授权、或可能覆盖同版本时停下问你。

Docker 只有你点名镜像时才走。token 不会写进输出、提交或回复。

如何判断完成

  • 初始化:check.py --ready 的构建项 PASS。只缺发布键算部分完成,仍可构建、不能上传。
  • 构建:产物路径、规范版本、架构与 make -f makefile.builder version 一致。
  • 发布:HTTP 成功或远端 digest 对得上;回复里有包名或镜像引用、SHA-256 / digest、源 commit。
  • 测试包不会通过无参 apt upgrade 盖住同号正式包;会作为下一 patch 候选盖住上一正式包。

脚本一览

脚本 用途
scripts/check.py 校验契约(--ready 含工具链与发布键名,--build 实构核对产物)
templates/makefile.builder 初始化用的契约文件骨架,拷到项目根
templates/env.builder 初始化用的 .env.builder 骨架(注释键,不含值)
scripts/version.sh 从 Git 祖先稳定 tag 推导规范版本 / Docker tag
scripts/version.mk makefile.builder include,设置 VERSION 与 IMAGE_TAG
scripts/upload_deb.sh 上传 .deb 到 HTTP 包仓库(multipart package/token/repository_name)
scripts/publish_docker.sh buildx 构建 + 推送镜像,远端 digest 验证
scripts/verify_deb.sh 核对包元数据、内容与 SHA-256
scripts/copy_artifact.sh 按 COPY_SCRIPT 分发产物,未配置时拷到 COPY_DEST
templates/makefile.android.builder Android APK + copy 轨道骨架
templates/makefile.ios.builder iOS IPA + copy 轨道骨架

环境变量契约、脚本解析顺序($BUILDER_SKILL_DIR → ~/.pouch/skills/builder/scripts/)、 脏工作树策略等完整规则见 contract.md。