首页
/ Penpot create-commit 技能:AI 代理提交代码的暂存审查、消息规范与安全约束

Penpot create-commit 技能:AI 代理提交代码的暂存审查、消息规范与安全约束

2026-09-06 22:08:08作者:平淮齐Percy

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-by trailer。

第二条揭示了该技能的输入契约: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-by trailer 只写纯模型名(如 mimo-v2.5deepseek-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 列表):

  1. 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).+[^.]$")
    
  2. Subject ≤ 90 chars —— 主题行长度上限 90 字符(注意:这比 CONTRIBUTING.md 文本中建议的 70 字符宽松,70 是书写规范、90 是硬校验线,两者并不矛盾——写 70 以内自然通过 90 的检查);
  3. No trailing period —— 主题行不能以 . 结尾;
  4. Subject capitalized —— 去掉 emoji 前缀后首字符必须是大写字母(Merge/Revert/Reapply 类豁免);
  5. Blank line after subject —— 主题与正文之间必须有空行。

另外,check_signed_off_by 函数还实现了 DCO 检查:代码类提交必须包含 Signed-off-by: 行(可用 git commit -s 自动添加),这与 CONTRIBUTING.md 的 DCO 章节一致——所有代码补丁(文档除外)必须签署,且签名须与提交作者真实姓名匹配。

emoji 白名单:脚本的 VALID_EMOJIS(第 24–29 行)合并自 CI 工作流正则与贡献指南,包括 lipstickglobe_with_meridianswrenchbooksarrow_uparrow_downzapambulanceconstructionboomfirewhalebugsparklespapercliptadarecyclerewindconstruction_workerrocket。对照 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

值得注意:脚本白名单中还有 rewindconstruction_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 校验器,构成了"提交前可预期、提交后可验证"的闭环。

登录后查看全文
热门项目推荐
相关项目推荐