swain-release
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<!-- swain-model-hint: sonnet, effort: medium -->
<!-- swain-model-hint: sonnet, effort: medium -->
Release
版本发布
Cut a release by detecting the project's versioning context, generating a changelog, bumping versions, and tagging. Works across any repo by reading context from git history and project structure rather than hardcoding assumptions.
通过检测项目的版本控制上下文、生成变更日志、升级版本号并打标签来完成版本发布。该技能适用于所有代码仓库,它通过读取Git历史和项目结构获取上下文,而非依赖硬编码的预设配置。
Override file
覆盖配置文件
Before starting, read if it exists. This is a freeform markdown file authored by the project owner whose instructions layer on top of this skill — its contents take precedence where they conflict. It can narrow defaults, specify version file locations, set tag formats, add pre/post-release steps, or anything else.
.agents/release.override.skill.mdIf no override exists, proceed with context detection alone.
开始操作前,如果存在文件,请先读取该文件。这是项目所有者编写的自由格式Markdown文件,其指令会覆盖本技能的默认逻辑——当内容冲突时,该文件的内容优先级更高。它可用于缩小默认范围、指定版本文件位置、设置标签格式、添加发布前/后步骤等。
.agents/release.override.skill.md如果不存在覆盖配置文件,则仅通过上下文检测来执行操作。
Workflow
工作流程
1. Gather context
1. 收集上下文
Infer the project's release conventions from what already exists. Do all of these checks up front before proposing anything to the user.
Tag history:
bash
git tag --sort=-v:refname | head -20From existing tags, infer:
- Tag format — ,
v1.2.3,1.2.3, or something elsename-v1.2.3 - Versioning scheme — semver, calver, or custom
- Current version — the most recent tag that matches the detected pattern
If there are no tags at all, note that this is the first release and ask the user what format they want.
Commits since last release:
bash
git log <last-tag>..HEAD --oneline --no-decorateIf no tags exist, use all commits (or a reasonable window — ask the user if there are hundreds).
Version files — scan for files that commonly hold version numbers:
bash
undefined从项目现有信息中推断发布约定。在向用户提出任何方案前,先完成以下所有检查。
标签历史:
bash
git tag --sort=-v:refname | head -20从现有标签中推断:
- 标签格式 — 如、
v1.2.3、1.2.3或其他格式name-v1.2.3 - 版本方案 — SemVer、CalVer或自定义方案
- 当前版本 — 与检测到的格式匹配的最新标签
如果没有任何标签,需注明这是首次发布,并询问用户希望使用的格式。
上次发布后的提交记录:
bash
git log <last-tag>..HEAD --oneline --no-decorate如果没有标签,则使用所有提交记录(若提交记录数以百计,需询问用户确认范围)。
版本文件 — 扫描通常存储版本号的文件:
bash
undefinedLook for common version carriers
查找常见的版本存储文件
grep -rl 'version' --include='.json' --include='.toml' --include='.yaml' --include='.yml' -l . 2>/dev/null | head -20
Also check for `VERSION` files, `version:` in SKILL.md frontmatter, `version` fields in `package.json`, `pyproject.toml`, `Cargo.toml`, etc. Don't modify anything yet — just catalog what exists.grep -rl 'version' --include='.json' --include='.toml' --include='.yaml' --include='.yml' -l . 2>/dev/null | head -20
同时检查`VERSION`文件、SKILL.md前置元数据中的`version:`字段、`package.json`、`pyproject.toml`、`Cargo.toml`等文件中的`version`字段。此时仅需记录找到的文件,暂不做任何修改。2. Determine the bump
2. 确定版本升级幅度
Parse commits since the last tag using conventional-commit prefixes to suggest a bump level:
| Commit prefix | Suggests |
|---|---|
| minor bump |
| patch bump |
| patch bump |
| major bump |
The highest-level signal wins (any breaking change = major, any feat = at least minor, otherwise patch).
If commits don't follow conventional-commit format, fall back to listing them and asking the user what bump level feels right.
通过解析上次标签后的提交记录中的约定式提交前缀,建议版本升级幅度:
| 提交前缀 | 建议升级幅度 |
|---|---|
| 次版本号升级(minor bump) |
| 修订号升级(patch bump) |
| 修订号升级(patch bump) |
提交正文中的 | 主版本号升级(major bump) |
优先级最高的信号决定最终升级幅度(任何破坏性变更=主版本号升级,任何新功能=至少次版本号升级,否则为修订号升级)。
如果提交记录未遵循约定式提交格式,则列出所有提交记录,询问用户合适的升级幅度。
3. Propose the release
3. 提出发布方案
Present the user with a release plan before executing anything. Include:
- Current version (from latest tag, or "first release")
- Proposed version (with the detected bump applied)
- Changelog preview (thematic narrative — see step 4)
- Files to update (version files found in step 1, if any)
- Tag to create (using the detected format)
Wait for the user to confirm, adjust the version, or abort. If the user wants a different version than what was suggested, use theirs — the suggestion is a starting point, not a mandate.
在执行任何操作前,先向用户展示发布计划,内容包括:
- 当前版本(来自最新标签,或标注为“首次发布”)
- 建议版本(应用检测到的升级幅度后的版本号)
- 变更日志预览(主题式叙述——见步骤4)
- 待更新文件(步骤1中找到的版本文件,若有)
- 待创建标签(使用检测到的格式)
等待用户确认、调整版本号或终止操作。如果用户希望使用与建议不同的版本号,以用户指定的为准——建议仅作为起点,而非强制要求。
4. Generate the changelog
4. 生成变更日志
Synthesize, don't transcribe. The changelog is for humans reading release notes, not for with extra steps. Dozens of commits should collapse into a few coherent narratives.
git log --onelineBefore writing, read the existing CHANGELOG.md (if any) to match the voice, density, and structure the project already uses. The changelog should read like the same person wrote every entry.
要整合,不要转录。变更日志是供人类阅读的发布说明,而非的升级版。数十条提交记录应整合为若干连贯的主题叙述。
git log --oneline撰写前,先读取现有CHANGELOG.md文件(若存在),以匹配项目已有的语气、密度和结构。变更日志的风格应保持一致。
Thematic sections over commit-type buckets
按主题分类而非提交类型分组
Group by what changed for the user, not by // prefix. A section like "### Docker Sandbox (swain-box)" that tells the story of that feature area is far more useful than scattering its commits across "New Features", "Bug Fixes", and "Documentation".
featfixdocsIdentify the major themes by scanning commits for shared scopes, artifact IDs, and feature areas. Each theme that has 3+ commits gets its own section with a descriptive heading.
###按用户感知的变更内容分组,而非按//等前缀分组。类似“### Docker沙箱(swain-box)”的主题章节,比将相关提交分散到“新功能”“Bug修复”和“文档”中更有用。
featfixdocs通过扫描提交记录中的共享范围、工件ID和功能领域,识别主要主题。包含3条及以上提交记录的主题,应单独创建章节并添加描述性标题。
###Prose for major work, bullets for small work
重大变更用段落,小变更用列表
If a theme represents significant new capability, write a paragraph (or a few) with bold lead-ins explaining what it is and why it matters. The reader should understand the feature without reading the commits.
markdown
undefined如果某个主题代表重要的新功能,撰写段落(或多个段落),并以粗体开头说明功能内容及其价值。读者无需查看提交记录即可理解该功能。
markdown
undefinedTrove Redesign (BREAKING)
Trove重设计(破坏性变更)
"Evidence pool" is now "trove" — a better name for what swain-search produces,
which ranges from research evidence to reference libraries to repo mirrors.
becomes .
evidencewatchtrovewatchHierarchical sources — sources are no longer flattened to . Each
source gets its own directory (), and repository or
documentation-site sources mirror their original tree structure.
001-slug.mdsources/<source-id>/
For smaller themes or isolated changes, a flat bullet list is fine.“证据池”更名为“trove”——这个名称更符合swain-search的产出内容,涵盖研究证据、参考库和仓库镜像等。已更名为。
evidencewatchtrovewatch层级化源文件——源文件不再扁平存储为。每个源文件都有独立目录(),仓库或文档站点源文件将镜像其原始目录结构。
001-slug.mdsources/<source-id>/
对于较小的主题或孤立变更,使用扁平的项目符号列表即可。Supporting Changes catchall
辅助变更汇总章节
Minor fixes, chore commits, refactors, and small improvements that don't fit a theme go in a section at the end — not interspersed with the major stories.
### Supporting Changes次要修复、日常维护提交、重构和小改进等不适合归入主题的内容,应放在末尾的章节中——不要分散到主要主题中。
### 辅助变更What to omit
需省略的内容
Merge commits, lifecycle hash stamps, index refreshes, bookmark advances, and other mechanical commits should be omitted entirely — they add noise without information. Commit-type prefixes (, ) should be stripped from any text that makes it into the changelog.
feat:fix:合并提交、生命周期哈希标记、索引刷新、书签更新等机械性提交应完全省略——这些内容只会增加噪音,无实际信息价值。提交类型前缀(、)应从变更日志的最终文本中移除。
feat:fix:Use commit prefixes for bump detection, not changelog structure
仅用约定式提交前缀检测升级幅度,而非构建变更日志结构
Conventional-commit types determine whether it's a major/minor/patch bump (step 2). After that, forget them — the changelog reader doesn't care that something was a vs .
featdocsWhere to put the changelog:
- If a exists, prepend the new section at the top (below any header)
CHANGELOG.md - If no changelog exists, ask the user whether they want one created, and where
- If the user doesn't want a file, just output it to the conversation
约定式提交类型仅用于判断主/次/修订版本号升级(步骤2)。之后即可忽略它们——变更日志的读者并不关心某条变更是还是。
featdocs变更日志的存储位置:
- 若存在CHANGELOG.md文件,在文件顶部(标题下方)插入新章节
- 若不存在变更日志文件,询问用户是否需要创建,以及存储位置
- 若用户不希望创建文件,直接在对话中输出变更日志内容
5. Bump versions
5. 升级版本号
Update version strings in the files identified in step 1. Be surgical — only change the version value, not surrounding content. For each file type:
- package.json / composer.json: update the field
"version" - pyproject.toml / Cargo.toml: update
version = "..." - SKILL.md frontmatter: update in YAML header
version: - VERSION file: replace contents
If a file has multiple version-like strings and it's ambiguous which one to update, ask the user rather than guessing.
更新步骤1中识别到的文件里的版本号字符串。操作需精准——仅修改版本号值,不改动周围内容。针对不同文件类型:
- package.json / composer.json:更新字段
"version" - pyproject.toml / Cargo.toml:更新
version = "..." - SKILL.md前置元数据:更新YAML头部的字段
version: - VERSION文件:替换文件内容
如果某个文件包含多个类似版本号的字符串,且无法确定应更新哪一个,需询问用户,而非自行猜测。
6. Commit and tag
6. 提交并打标签
Stage the changed files (changelog + version bumps) and commit:
bash
git add <changed-files>
git commit -m "release: v1.5.0"Then create an annotated tag:
bash
git tag -a <tag> -m "Release <tag>"Use the tag format detected in step 1 (or what the user specified).
暂存变更文件(变更日志+版本号更新)并提交:
bash
git add <changed-files>
git commit -m "release: v1.5.0"然后创建带注释的标签:
bash
git tag -a <tag> -m "Release <tag>"使用步骤1中检测到的标签格式(或用户指定的格式)。
7. Offer to push
7. 询问是否推送
Ask the user if they want to push the commit and tag:
bash
git push && git push origin <tag>Push only the specific tag — tries to push every local tag and produces noisy rejections for tags that already exist on the remote.
git push --tagsDon't push without asking — the user may want to review first, or they may have a CI pipeline that triggers on tags.
询问用户是否需要推送提交记录和标签:
bash
git push && git push origin <tag>仅推送指定的标签——会尝试推送所有本地标签,对于已存在于远程仓库的标签会产生大量无用的拒绝信息。
git push --tags未经用户确认不要推送——用户可能希望先进行审查,或者其CI流水线会在检测到标签时触发。
Edge cases
边缘情况
Monorepo with multiple version streams: If the tag history suggests per-package tags (e.g., , ), ask the user which package they're releasing rather than assuming.
frontend-v1.2.0api-v3.1.0Pre-release versions: If the user asks for a pre-release (alpha, beta, rc), append the pre-release suffix to the version: . Follow the existing convention if prior pre-release tags exist.
1.5.0-alpha.1No conventional commits: If the commit history doesn't use conventional prefixes, don't force the grouping. Present a flat list and let the changelog be a simple bullet list of changes.
Dirty working tree: If there are uncommitted changes when is invoked, warn the user and ask whether to proceed (changes won't be included in the release) or abort so they can commit first.
/swain-release多版本流的单体仓库:如果标签历史显示存在按包划分的标签(如、),需询问用户要发布哪个包,而非自行假设。
frontend-v1.2.0api-v3.1.0预发布版本:如果用户要求创建预发布版本(alpha、beta、rc),在版本号后添加预发布后缀:。若存在历史预发布标签,遵循已有的约定。
1.5.0-alpha.1无约定式提交:如果提交历史未使用约定式前缀,不要强制分组。直接展示扁平列表,让变更日志成为简单的变更项目符号列表。
工作区未提交变更:当调用时若存在未提交的变更,需警告用户,并询问是继续执行(变更不会包含在发布中)还是终止操作以便用户先提交变更。
/swain-releaseSession bookmark
会话书签
After a successful release, update the bookmark:
bash "$(find . .claude .agents -path '*/swain-session/scripts/swain-bookmark.sh' -print -quit 2>/dev/null)" "Released v{version}"发布成功后,更新书签:
bash "$(find . .claude .agents -path '*/swain-session/scripts/swain-bookmark.sh' -print -quit 2>/dev/null)" "Released v{version}"