Penpot create-commit 技能:AI 代理提交代码的暂存审查、消息规范与安全约束
Penpot 仓库通过 .opencode/skills/create-commit/SKILL.md 定义了一个专供 AI 代理使用的提交流程技能,它规定了从暂存文件、审查 diff 到按项目惯例撰写提交消息的完整工作流,并附带一组防止误操作的硬性安全约束。本文基于该技能文件逐节展开,并结合仓库中的 提交校验脚本、贡献指南 和 AI 代理总规则,讲清 Penpot 提交规范在自动化场景下的落地方式。
技能定位:只管提交,不管实现与推送
SKILL.md 的 frontmatter 声明了技能名称与职责:
name: create-commit
description: Stage, review, and commit files following Penpot commit conventions.
文档开篇就划定了边界:该技能负责提交格式、暂存审查与安全校验三件事,明确声明它"不实现功能、不执行 push"(it does not implement features or push)。从 implement-plan 命令 的定义可以看到它在工作流中的位置:implement-plan 按顺序执行"创建 issue → 建分支 issue-NNNN → 实施计划 → 调用 create-commit 技能提交"四步,实施阶段明确写着"Do not commit — the commit happens in step 4",即代码改动与提交动作被刻意解耦,提交环节完全交给 create-commit 技能处理。
这种"单一职责"的设计让 AI 代理在提交这一高危环节有统一的行为契约:无论改动来自哪个任务,最终提交都走同一条审查与格式流程。
适用时机(When to Use)
文档列出了两种触发场景:
- 代码改动完成、需要提交时——作为人工或自动化流程的收尾动作;
- 被工作流步骤委派时——例如 implement-plan 在实现完成后,将"简要说明改了什么、为什么改、issue 编号(
issue-NNNN)、当前运行的模型名称"一并交给 create-commit 技能,其中模型名称用于正确填写AI-assisted-bytrailer。
第二条揭示了该技能的输入契约:AI-assisted-by 的值由调用方上下文提供(工作流第 4 步明确要求"provide a brief summary … and the model name you are running as"),技能本身只负责原样使用,不做推断。
必读前置:creating-commits 记忆文档
技能规定,在起草任何提交之前必须通读 mem:workflow/creating-commits 记忆文档——它是提交消息格式、emoji 菜单、主题/正文长度限制以及 AI-assisted-by trailer 的权威来源,"Follow it exactly"。按照 AGENTS.md 中说明的记忆映射规则,mem:foo/bar 对应文件 .serena/memories/workflow/creating-commits.md,其核心内容如下:
消息格式模板:
:emoji: Subject line (imperative, capitalized, no period, <=70 chars)
Body explaining what changed and why.
Wrap lines at 72 characters — git log and tooling
render long lines poorly. Keep each line concise.
AI-assisted-by: model-name
关键约束:
- 主题行使用祈使语气、首字母大写、不以句号结尾、长度不超过 70 字符;
- 正文每行在 72 字符处折行——理由是
git log等工具对长行渲染不佳; AI-assisted-bytrailer 只写纯模型名(如mimo-v2.5、deepseek-v4-flash),不要加opencode-go/之类前缀;- 关联 issue 使用
Closes #NNNN,而非Fixes #NNNN; - 提交前执行
git status,排除与本次任务无关的用户改动; - 绝不猜测或编造 git 作者信息(Name/Email),也不传
--author,身份从本地 git config 自动读取。
此外 AGENTS.md 将其列为硬性规则:"执行 git commit 之前必须先读 mem:workflow/creating-commits",且"不要从上一个提交/issue/PR 的标题推断格式——记忆文档才是 source of truth"。这说明 Penpot 把"格式规则的单一事实源"作为 AI 协作的基础设施来管理,技能文件只是对该规则的引用与执行层。
四步工作流详解
第 1 步:暂存指定文件,不询问确认
按调用上下文指定的文件执行 git add,不向用户请求确认。这与 creating-commits 记忆 中"commit only on explicit request"的原则呼应:调用上下文本身就是显式请求,避免代理反复打断自动化流程。
第 2 步:git diff --staged 内容审查,命中敏感内容即 STOP
暂存后必须运行:
git diff --staged
审查规则:一旦发现以下任一类内容,立即停止并在提交前告知用户:
- 秘密信息:API keys、tokens、密码、私钥、
.env值; - 调试打印(debug prints);
- 任何与声明意图(stated intent)不符的改动。
这是把"人工 code review"中最关键的安全检查前置到了自动化提交路径上——尤其当改动部分由 AI 生成时,暂存区可能混入实验性代码,diff 审查是提交前最后一道人工可见的关卡。
第 3 步:按格式起草消息并提交
消息须遵循记忆文档的格式,正文按 72 字符折行,然后用标准 git 命令提交:
git commit -m "<subject>" -m "<body>"
技能还给出一个实用变体:当正文包含特殊字符、双参数 -m 容易出问题时,改用:
git commit -F -
即从标准输入读取完整消息。对于含多段 trailer、Closes #NNNN 的较长消息,git commit -F - 配合 here-doc 是最不易出错的写法。
第 4 步:AI-assisted-by trailer 原样使用
AI-assisted-by 的值由调用上下文提供,逐字使用(use it verbatim),不自行拼写或加前缀——这与记忆文档中"only the model name, do NOT add prefixes"的规则一致,保证 trailer 值在 git log 中可聚合、可检索。
安全约束(Constraints)逐条解析
技能文件列出了六条"不做"约束,每一条都能在 AGENTS.md 的 HARD RULES 中找到对应的项目级依据:
| 约束 | 说明 | 项目级依据 |
|---|---|---|
| 不 push | 推送是独立工作流,由用户处理 | AGENTS.md:Never git push, force-push, or modify git origin;implement-plan 末尾同样写明 "Do not push. Pushing is handled separately by the user." |
禁止 git reset / git checkout / git restore / git clean / rm |
防止代理误删工作区或暂存区状态 | 属于提交环节的最小权限原则,代理只应"加法"(stage + commit) |
不传 --author |
作者身份来自本地 git config | creating-commits 记忆:Never include the --author flag … assume the local environment is already configured |
| 不 amend 非本会话创建的提交 | 除非用户明确要求 | AGENTS.md:Never amend a commit that has been pushed unless the user explicitly asks |
不绕过 pre-commit hooks(--no-verify) |
除非明确要求 | hooks 是格式与安全检查的执行点,绕过即破坏校验闭环 |
| 不添加本会话之外产生的未跟踪文件 | 防止把用户本地文件误提交进仓库 | 对应"排除无关用户改动"的记忆规则 |
这套约束的共同意图是:把 AI 代理在提交环节的权限收窄到"暂存指定文件 + 写一条合规提交"的最小集合,所有破坏性、身份性、远端性操作都交还给用户。
源码佐证:scripts/check-commit 校验器
仓库提供了可本地运行的提交校验脚本 scripts/check-commit,它把 CI 正则与贡献指南中的格式规则合并在一个 Python 校验器中实现,可视为"技能产出的提交是否合规"的客观判定依据。
命令行用法:
./scripts/check-commit # 默认检查 HEAD
./scripts/check-commit --commit HEAD~1
./scripts/check-commit -c abc1234
脚本实现的校验项(main() 中的 validators 列表):
- Regex pattern —— 主题行必须匹配两种模式之一:
:emoji: <大写开头的主题,不以句号结尾>,其中 emoji 必须来自白名单;Merge|Revert|Reapply ...开头的合并/回滚类提交。 核心正则定义在脚本第 35–39 行:
COMMIT_PATTERN = re.compile( r"^((:(" + VALID_EMOJIS + r"):\s[A-Z].*[^.]))$" ) MERGE_PATTERN = re.compile(r"^(Merge|Revert|Reapply).+[^.]$") - Subject ≤ 90 chars —— 主题行长度上限 90 字符(注意:这比 CONTRIBUTING.md 文本中建议的 70 字符宽松,70 是书写规范、90 是硬校验线,两者并不矛盾——写 70 以内自然通过 90 的检查);
- No trailing period —— 主题行不能以
.结尾; - Subject capitalized —— 去掉 emoji 前缀后首字符必须是大写字母(Merge/Revert/Reapply 类豁免);
- Blank line after subject —— 主题与正文之间必须有空行。
另外,check_signed_off_by 函数还实现了 DCO 检查:代码类提交必须包含 Signed-off-by: 行(可用 git commit -s 自动添加),这与 CONTRIBUTING.md 的 DCO 章节一致——所有代码补丁(文档除外)必须签署,且签名须与提交作者真实姓名匹配。
emoji 白名单:脚本的 VALID_EMOJIS(第 24–29 行)合并自 CI 工作流正则与贡献指南,包括 lipstick、globe_with_meridians、wrench、books、arrow_up、arrow_down、zap、ambulance、construction、boom、fire、whale、bug、sparkles、paperclip、tada、recycle、rewind、construction_worker、rocket。对照 CONTRIBUTING.md 的 Commit types 表,其语义映射为:
| Emoji | 含义 | Emoji | 含义 |
|---|---|---|---|
:bug: |
Bug fix | :ambulance: |
Critical bug fix |
:sparkles: |
Improvement / enhancement | :boom: |
Breaking change |
:tada: |
New feature | :wrench: |
Configuration update |
:recycle: |
Refactor | :zap: |
Performance improvement |
:lipstick: |
Cosmetic changes | :whale: |
Docker-related change |
:books: |
Documentation | :paperclip: |
Other non-relevant changes |
:construction: |
Work in progress | :arrow_up: / :arrow_down: |
Dependency upgrade / downgrade |
:fire: |
Removal of code or files | :globe_with_meridians: |
Add or update translations |
:rocket: |
Epic or highlight |
值得注意:脚本白名单中还有 rewind 与 construction_worker 两个 emoji 未出现在贡献指南的表格中,从源码结构看,正则白名单是实际执行口径,写提交时以 creating-commits 记忆 的 emoji 速查行(与指南表格一致)为准最稳妥。
贡献指南给出的标准示例:
:bug: Fix unexpected error on launching modal
:sparkles: Enable new modal for profile
:zap: Improve performance of dashboard navigation
:ambulance: Fix critical bug on user registration process
:tada: Add new approach for user registration
端到端示例:一次合规的 AI 辅助提交
综合技能文件与记忆文档,一次典型流程如下:
# 1. 暂存调用上下文指定的文件
git add frontend/src/app/main/workspace/viewport.cljs
# 2. 审查暂存 diff,确认无秘密、无调试打印、无无关改动
git diff --staged
# 3. 提交(消息按 72 字符折行,包含 Closes 与 AI-assisted-by trailer)
git commit -m ":sparkles: Enable tile rendering in workspace viewport" -m "$(cat <<'EOF'
Enable tile rendering in workspace viewport to reduce
canvas repaint cost on large files.
Closes #1234
AI-assisted-by: deepseek-v4-flash
EOF
)"
# 4. 本地自检(可选但推荐)
./scripts/check-commit
校验脚本输出 All checks passed. 即表示该提交满足正则、长度、大写、空行等全部硬性规则。
小结
create-commit 技能 的价值在于把 Penpot 的提交规范(CONTRIBUTING.md + creating-commits 记忆)翻译成了 AI 代理可直接执行的四步流程与六条禁令:暂存指定文件 → git diff --staged 安全审查 → 按 72 字符折行格式提交 → 原样使用调用方提供的 AI-assisted-by 值;全程不 push、不破坏工作区、不改作者身份、不绕过 hooks。对于在 Penpot 仓库上工作的 AI 工具链而言,这套契约加上可本地运行的 scripts/check-commit 校验器,构成了"提交前可预期、提交后可验证"的闭环。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00