首页
/ caveman caveman-commit:只写意图的 Conventional Commits 技能全解

caveman caveman-commit:只写意图的 Conventional Commits 技能全解

2026-09-06 15:57:58作者:戚魁泉Nursing

caveman-commit 是 caveman 仓库中专职生成提交信息的技能:它把 Conventional Commits 规则压缩成一套“只写 why、不写 what”的最小规则集,并以 slash 命令、自然语言短语两种入口驱动 Agent 产出即贴即用的 commit message。读完本文,你将掌握该技能的完整规则体系(subject/body/禁写清单)、Auto-Clarity 强制场景、边界行为(绝不代你执行 git commit),以及它在仓库中如何被注册为 /caveman-commit 命令、被 UserPromptSubmit hook 拦截并切换 commit 模式的完整链路。

技能定位:一条规则集,不碰 git 状态

技能的 canonical 定义位于 skills/caveman-commit/SKILL.md,配套的人类可读说明在 skills/caveman-commit/README.md。SKILL.md 以 YAML frontmatter 声明身份与触发条件:

name: caveman-commit
description: >
  Write a Conventional Commits message compressed to intent only. Use for
  "write a commit", "commit message", /commit or /caveman-commit.

frontmatter 之后的第一行是全部指令的纲领:

Write commit messages terse and exact. Conventional Commits format. No fluff. Why over what.

即:简洁、精确、Conventional Commits 格式、不灌水、意图优先于描述。技能在 docs/technical/skills-hooks-and-plugins.md 的能力总表中被登记为“Terse Conventional Commit message”,并明确标注其边界:Does not stage, commit, or amend(不暂存、不提交、不 amend)。

Subject line 规则:逐条完整继承

SKILL.md 的 Rules 一节对 subject 行给出六条硬性约束,是技能的核心产出契约:

  1. 格式<type>(<scope>): <imperative summary>,其中 <scope> 可选;
  2. type 白名单featfixrefactorperfdocstestchorebuildcistylerevert,共 11 种;
  3. 祈使语气:用 "add"、"fix"、"remove",禁止 "added"、"adds"、"adding";
  4. 长度:尽量 ≤50 字符,硬上限 72 字符;
  5. 句尾不加句号
  6. 冒号后的大小写跟随项目既有约定(match project convention for capitalization after the colon)。

第 6 条值得注意:技能并不强制某一种大小写风格,而是要求先观察项目已有提交再对齐——这让生成的 message 在历史中不突兀。仓库为 Gemini CLI 准备的等价压缩版 prompt 同样内嵌了这些约束,见 commands/caveman-commit.toml

description = "Generate terse caveman-style commit message"
prompt = "Generate a terse commit message for the current staged changes. Conventional Commits format. Subject: ≤50 chars, imperative, lowercase after type. Body: only when 'why' isn't obvious from subject. Why over what. No period on subject."

注意 TOML 版的 prompt 把作用对象明确为 current staged changes(当前暂存改动),与 SKILL.md 的 Boundaries 一节呼应:技能只读暂存区来写 message,绝不主动 stage。

Body 规则:默认不写,四类情况必写

Body 的默认策略是跳过

  • Subject 自明时(self-explanatory)完全不加 body;
  • 仅当存在以下四类内容时才添加 body:非显然的 why(non-obvious why)、破坏性变更(breaking changes)、迁移说明(migration notes)、关联 issue(linked issues);
  • body 按 72 字符折行;
  • 列表用 - 而不是 *
  • issue/PR 引用放在结尾,格式为 Closes #42Refs #17

禁写清单:这些内容永远不出现在 message 里

SKILL.md 的 "What NEVER goes in" 一节定义了一条负面清单,这是该技能与普通 commit message 生成器拉开差距的地方:

禁写内容 替代方案
"This commit does X"、"I"、"we"、"now"、"currently" 删掉——diff 已经说明了 what
"As requested by ..." 使用 Co-authored-by trailer
"Generated with Claude Code" 或任何 AI 署名 不加;除非用户自己的规则要求 Assisted-by/AI 署名 trailer,此时以 trailer 形式追加
Emoji 不加(除非项目约定要求)
复述 scope 已经表达过的文件名 删掉,scope 已承载该信息

其中 AI 署名条款值得单独说明:默认零署名,但给用户规则留了后路——若用户项目规范本身要求 AI 署名,则以 trailer 而非 body 叙述的形式出现,避免污染意图正文。

两个完整示例:为什么比怎么写更重要

SKILL.md 给出两段带 diff 语境的对照示例,完整保留如下。

示例一:diff 是“新增用户 profile 端点,且 body 解释 why”。

  • ❌ 反例:feat: add a new endpoint to get user profile information from the database
  • ✅ 正例:
feat(api): add GET /users/:id/profile

Mobile client needs profile data without the full user payload
to reduce LTE bandwidth on cold-launch screens.

Closes #128

subject 只说“加了什么端点”,body 回答“为什么要单独拆一个端点”(移动端冷启动场景下省流量),结尾挂 issue 引用。反例的问题在于它把 diff 里已经可见的 what 又复述了一遍。

示例二:diff 是破坏性 API 重命名。

feat(api)!: rename /v1/orders to /v1/checkout

BREAKING CHANGE: clients on /v1/orders must migrate to /v1/checkout
before 2026-06-01. Old route returns 410 after that date.

要点:! 标记破坏性变更;BREAKING CHANGE: footer 给出迁移截止日和旧路由的失效行为(410 Gone)。

Auto-Clarity:四类变更禁止压缩成单行 subject

SKILL.md 的 Auto-Clarity 一节是一条覆盖性规则:

Always include body for: breaking changes, security fixes, data migrations, anything reverting a prior commit. Never compress these into subject-only — future debuggers need the context.

即以下四类变更永远必须带 body,不允许压成 subject-only:

  1. 破坏性变更(breaking changes)
  2. 安全修复(security fixes)
  3. 数据迁移(data migrations)
  4. 对先前提交的回滚(revert)

其理由写得很直白:未来的排障者需要上下文。这与 Body 规则中“默认跳过”形成互补——常规改动享受极简,高风险改动强制保留推理链。

边界与退出:只产出文本,随时可退回详细模式

SKILL.md 的 Boundaries 一节划定了技能的行为边界:

  • 只生成 commit message:不执行 git commit、不 stage 文件、不 amend;
  • 输出形态:以代码块形式输出,可直接复制粘贴;
  • 退出机制:说 "stop caveman-commit" 或 "normal mode" 即退回冗长(verbose)提交风格。

README.md 对同一边界做了复述:Outputs only the message. Does not stage, commit, or amend. 这意味着该技能可以安全地放进任何提交流程——它没有 git 副作用,唯一产出物是待粘贴的文本。

注册链路:/caveman-commit 如何恰好注册一次

技能被声明为可由 /caveman-commit slash 命令触发,但“slash 命令能解析”本身在这个仓库里是被测试守护的契约。tests/installer/slash-commands.test.mjs 针对 issue #470 与 #571 断言每个对外文档化的命令都必须满足双通道注册:

  • Gemini 通道commands/<name>.toml 必须存在(Gemini CLI 扩展只读 TOML 命令)——对应 commands/caveman-commit.toml
  • Claude Code 通道skills/<name>/SKILL.mdcommands/<name>.md 二者恰好其一。Claude Code 会把 commands/*.md 当作与 skills/*/SKILL.md 同一命名空间的扁平技能加载,两者同时存在会让同一 slash 命令注册两次,3 行 stub 与真正的规则集竞争(测试注释中记录了 claude plugin details 曾列出重复项的现场)。

caveman-commit 而言,Claude Code 侧的唯一提供方就是 skills/caveman-commit/SKILL.md,测试中 DOCUMENTED_COMMANDS 白名单包含它,保证这条命令在 Claude Code 里不会被解析成 "Unknown command"。

另外从 skills/registry.jsonpreserved_skill_ids 列表(含 caveman-commit)与 skills/compile.mjs 的校验逻辑看:caveman-commit 属于“保留技能”——它不进入编译器的 skills 数组(不注入 native pack / CLI 生成物),而是以独立的 skills/caveman-commit/ 目录形式随插件分发,由宿主(Claude Code 等)直接发现;compile.mjs 在比对 canonical 技能目录时会显式豁免这些保留 id。这解释了为什么它没有出现在 registry 的 skills 数组里却仍然是可安装、可触发的正式技能。

拦截与模式状态:从输入框到 [CAVEMAN:COMMIT] 徽章

输入 /caveman-commit 后,仓库的 hook 链路会把它识别为一个“独立一次性模式”。关键证据在 src/hooks/caveman-parse.js

// Modes handled by their own slash commands (/caveman-commit, etc.) — not
// selectable via /caveman <arg>.
const INDEPENDENT_MODES = new Set(['commit', 'review', 'compress']);

commit 是独立模式:不能通过 /caveman commit 选择,只能经由它自己的 slash 命令进入;用户在自然语言路径误触时会被明确告知而非静默切换。解析主体在 src/hooks/caveman-parse.js

if (prompt.startsWith('/caveman')) {
  const parts = prompt.split(/\s+/);
  const cmd = parts[0]; // /caveman, /caveman-commit, /caveman-review, etc.
  ...
  if (cmd === '/caveman-commit' || cmd === '/caveman:caveman-commit') {
    return { action: 'set', mode: 'commit' };
  }

注意它同时接受 /caveman-commit 与插件命名空间形式 /caveman:caveman-commit(marketplace 插件安装下的呈现形态)。模式判定后,UserPromptSubmit hook src/hooks/caveman-mode-tracker.jscommit 写入模式标志文件;src/hooks/README.md 记录了该模式的 statusline 徽章:

  • /caveman-commit[CAVEMAN:COMMIT]

mode tracker 还维护了一个 .caveman-active.prev 标志:commit 这类独立模式是 one-shot 的,它记住被顶替掉的原生话风模式,下一个普通 prompt 到来时恢复,且恢复逻辑按会话隔离——两个窗口各自运行 /caveman-commit,退出时各回各的话风等级。这与 SKILL.md 中 "stop caveman-commit" / "normal mode" 的退出条款在实现层面对应:退出后 Agent 恢复常规(verbose)提交风格。

实战使用方式

在已安装 caveman 的 Claude Code 会话中:

  1. 暂存你要提交的改动(git add 由你执行——技能本身不 stage);
  2. 输入 /caveman-commit,或用自然语言触发("write a commit"、"commit message"、"/commit" 均在 frontmatter 声明的触发短语内);
  3. Agent 按本文前述规则集产出 message 代码块,复制粘贴后自行执行 git commit 并填入。

需要退回详细提交风格时,说 "stop caveman-commit" 或 "normal mode" 即可。技能的全部行为约束——规则集在 skills/caveman-commit/SKILL.md,注册契约在 tests/installer/slash-commands.test.mjs,模式解析在 src/hooks/caveman-parse.js——都在这三处可以复核。

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