[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C7GR5PB0Z3XWN0RFRBJWDR":3,"skill-same:01M6C7GR5PB0Z3XWN0RFRBJWDR":54},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":33,"commitSha":34,"skillDirectory":35,"forksCount":36,"repositoryHtmlUrl":37,"repositoryHomepageUrl":6,"ownerHtmlUrl":38,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":39,"install":40,"resources":53},"01M6C7GR5PB0Z3XWN0RFRBJWDR","release",null,"Create versioned releases - bump version via PR, tag, create GitHub release. CI publishes to npm.","lepahc\u002Fkynetic-spec","lepahc","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F255431765?v=4","01M6C7E6Z0C8SE1X6PJ2F9Q1CX","01M6C7E744QKNYBVZ7KV7Z69GF",1,"MIT","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frelease\u002FSKILL.md",[],[5,18,19,20,21,22,23,24,25,26,27],"github","bump version","pr","create","npm","ci","github release","version","bump","releases","2026-11-10 10:12:30",false,"---\nname: release\ndescription: Create versioned releases - bump version via PR, tag, create GitHub\n  release. CI publishes to npm.\n---\n\u003C!-- kspec-managed -->\n\n# Release Skill\n\nCreate versioned releases with proper git tagging and GitHub release creation. The workflow is:\n\n1. **Bump version** via PR (respects branch protection)\n2. **Create tag** on the merged commit\n3. **Create GitHub release** with notes\n4. **CI publishes** to npm automatically\n\n## When to Use\n\n- After completing features\u002Ffixes ready for release\n- When creating patch\u002Fminor\u002Fmajor version bumps\n- For pre-release versions (alpha, beta, rc)\n- When auditing what changes would be in a release (`--dry-run`)\n\n**Prerequisites:**\n- All related kspec tasks should be completed before release\n- Run `npm test` locally to verify tests pass\n- Ensure you're on `main` with a clean working tree\n\n## Arguments\n\n```\n\u002Frelease [patch|minor|major|X.Y.Z] [options]\n```\n\n| Argument | Description |\n|----------|-------------|\n| `patch` | Bug fixes, backwards-compatible (0.1.1 -> 0.1.2) |\n| `minor` | New features, backwards-compatible (0.1.1 -> 0.2.0) |\n| `major` | Breaking changes (0.1.1 -> 1.0.0) |\n| `X.Y.Z` | Explicit version number |\n| (none) | Auto-detect from commits since last tag |\n\n| Option | Description |\n|--------|-------------|\n| `--dry-run` | Preview only - NO changes to git, tags, PRs, or GitHub |\n| `--prerelease \u003Ctype>` | Create prerelease (alpha, beta, rc) |\n\n## Workflow\n\n### Phase 1: Detect Context\n\nGather information about current state:\n\n```bash\n# Get current branch\ngit branch --show-current\n\n# Check for uncommitted changes\ngit status --porcelain\n\n# Get current version from package.json\nnode -p \"require('.\u002Fpackage.json').version\"\n\n# Get last tag\ngit describe --tags --abbrev=0 2>\u002Fdev\u002Fnull || echo \"no-tags\"\n\n# Get commits since last tag\ngit log $(git describe --tags --abbrev=0 2>\u002Fdev\u002Fnull)..HEAD --oneline\n```\n\n**Context to gather:**\n- Current branch (must be `main`)\n- Working tree status (must be clean)\n- Current version in package.json\n- Last tag (e.g., v0.1.1)\n- Commits since last tag (count and list)\n\n### Phase 2: Validate Constraints\n\nAll constraints must pass before proceeding:\n\n| Constraint | Check | Error Message |\n|------------|-------|---------------|\n| On main branch | `git branch --show-current` = main | \"Must be on main branch. Currently on: {branch}\" |\n| Clean working tree | `git status --porcelain` is empty | \"Working tree must be clean. Commit or stash changes first.\" |\n| Up to date with origin | After `git fetch`, local matches remote | \"Local main is behind origin. Run: git pull\" |\n| Has releasable changes | At least one commit since last tag | \"No changes since last tag {tag}. Nothing to release.\" |\n| Tag doesn't exist | `git tag -l v{version}` is empty | \"Tag v{version} already exists.\" |\n\n**Dry-run behavior:** In dry-run mode, validation failures are reported but the preview continues. In normal mode, ANY validation failure stops execution immediately.\n\n### Phase 3: Determine Version\n\nIf version type not specified, auto-detect from ALL commits since last tag:\n\n```bash\n# Get all commit messages since last tag (not just merges)\ngit log $(git describe --tags --abbrev=0)..HEAD --pretty=format:\"%s%n%b\"\n```\n\n**Auto-detection rules (conventional commits):**\n\n| Pattern | Bump | Notes |\n|---------|------|-------|\n| `BREAKING CHANGE:` in body | major | Check commit body, not just subject |\n| `feat!:` or `fix!:` (with `!`) | major | The `!` suffix indicates breaking |\n| `feat:` or `feat(scope):` | minor | Scope is ignored for detection |\n| `fix:`, `perf:`, `refactor:`, `chore:` | patch | Any maintenance work |\n\n**Resolution order:**\n1. If ANY commit has breaking change indicator -> major\n2. Else if ANY commit starts with `feat:` -> minor\n3. Else -> patch\n\n**Prerelease handling (`--prerelease \u003Ctype>`):**\n\n| Current | Flag | Result | Rule |\n|---------|------|--------|------|\n| 0.1.1 | `--prerelease alpha` | 0.1.2-alpha.0 | Bump patch, add prerelease |\n| 0.1.2-alpha.0 | `--prerelease alpha` | 0.1.2-alpha.1 | Same type: increment counter |\n| 0.1.2-alpha.1 | `--prerelease beta` | 0.1.2-beta.0 | New type: reset counter to 0 |\n| 0.1.2-rc.0 | (no flag) | 0.1.2 | Stable release: drop prerelease suffix |\n\n**Prerelease rules:**\n1. Same prerelease type -> increment counter (alpha.0 -> alpha.1)\n2. Different prerelease type -> reset counter (alpha.1 -> beta.0)\n3. No prerelease flag on prerelease version -> promote to stable\n\n### Phase 4: Analyze Changes for Release Notes\n\nParse commits and categorize them for user-friendly release notes.\n\n**Commit selection:**\n- Prefer merge commits (contain `(#N)` PR reference) to avoid duplicates\n- If no merge commits, include all commits matching conventional patterns\n- Deduplicate by checking if a commit's changes are already in a merge commit\n\n**Categorization (commit type -> section):**\n\n| Commit Type | Release Notes Section |\n|-------------|----------------------|\n| `feat:` | Features & Additions |\n| `fix:` | Bug Fixes |\n| `perf:` | Performance |\n| `refactor:`, `chore:`, `build:` | Other Changes |\n| `test:`, `ci:`, `docs:` | (excluded unless user-facing) |\n\n**kspec integration:**\n```bash\n# Extract completed task references from commit trailers\ngit log $(git describe --tags --abbrev=0)..HEAD --pretty=format:\"%b\" | grep -E \"^Task: @\" | sort -u\n```\n\nCompleted tasks provide context for what was accomplished in this release.\n\n### Phase 5: Preview (--dry-run)\n\nFor `--dry-run`, show comprehensive preview. **No changes are made** - no PRs, no tags, no releases.\n\n```\n## Release Preview (DRY RUN)\n\n**Version bump:** 0.1.1 -> 0.1.2 (patch)\n**Detection:** Auto-detected from 5 commits (3 fix, 2 chore)\n\n### Validation\n- [x] On main branch\n- [x] Working tree clean\n- [x] Up to date with origin\n- [x] Has 5 commits since v0.1.1\n- [x] Tag v0.1.2 does not exist\n\n### Release Notes Preview\n\nBug fixes and improvements for kspec CLI.\n\n#### Features & Additions\n- Add JSON output mode for task list\n\n#### Bug Fixes\n- Fix author attribution for auto-generated notes\n- Increase timeout for ref resolution\n\n### Actions (dry-run: NOT executed)\n1. Create version bump PR (package.json -> 0.1.2)\n2. Regenerate kspec-agents.md with new version\n3. Wait for CI, then merge PR\n4. Create tag: v0.1.2\n5. Push tag to origin\n6. Create GitHub release with notes above\n7. CI will publish to npm\n\nTo execute: run `\u002Frelease` without --dry-run\n```\n\n### Phase 6: Bump Version (PR)\n\n**Before creating the tag**, update package.json via PR:\n\n```bash\nVERSION=\"0.1.2\"  # calculated version\n\n# Create branch for version bump\ngit checkout -b release\u002Fv$VERSION\n\n# Update version without creating a tag\nnpm version $VERSION --no-git-tag-version\n\n# Regenerate kspec-agents.md so the version header stays in sync\n# For self-hosting (releasing kspec itself), use: npm run dev -- agents generate\nkspec agents generate\n\n# Commit and push\ngit add package.json package-lock.json kspec-agents.md\ngit commit -m \"chore: bump version to $VERSION\"\ngit push -u origin release\u002Fv$VERSION\n\n# Create PR\ngh pr create --title \"chore: bump version to $VERSION\" --body \"Prepare release v$VERSION\"\n\n# Wait for CI to pass, then merge\ngh pr merge --merge --delete-branch\n```\n\n**Why version bump first?**\n- The tagged commit has the correct version in package.json\n- CI publishes exactly what's in package.json\n- No out-of-sync state between git tag and package version\n\n**Why regenerate kspec-agents.md?**\n- The freshness comment includes the kspec version (`Generated by kspec vX.Y.Z`)\n- Regenerating after the version bump keeps the header in sync with the release\n- **Self-hosting note:** When releasing kspec itself, the installed `kspec` binary still has the old version. Use `npm run dev -- agents generate` instead so the dev build reads the bumped version from the local package.json\n\n### Phase 7: Create Tag and Release\n\nAfter the version PR is merged:\n\n```bash\n# Pull the merged version bump\ngit checkout main && git pull\n\n# Create annotated tag (v prefix is convention for npm\u002Fsemver)\ngit tag -a \"v$VERSION\" -m \"Release v$VERSION\"\n\n# Push tag to origin\ngit push origin \"v$VERSION\"\n\n# Create GitHub release (gh uses current repo automatically)\ngh release create \"v$VERSION\" \\\n  --title \"v$VERSION\" \\\n  --notes \"$(cat \u003C\u003C'EOF'\nBrief summary of this release.\n\n### Features & Additions\n- Feature description\n\n### Bug Fixes\n- Fix description\n\n### Other Changes\n- Change description\n\n**Full Changelog**: compare\u002Fv{previous}...v{version}\nEOF\n)\"\n```\n\n**Tag naming:** Always use `v` prefix (e.g., `v0.1.2`) for consistency with npm versioning conventions and GitHub release detection.\n\n**CI behavior:**\n- Triggers on `release.published` event (within 1-2 minutes)\n- Runs tests and publishes to npm with provenance\n- Monitor progress at the repo's Actions tab\n\n### Phase 8: Report Summary\n\nAfter successful release:\n\n```\n## Release Complete\n\n**Version:** v0.1.2\n**Tag:** v0.1.2\n**Commit:** abc1234\n\n### Completed\n- [x] Version PR created and merged\n- [x] kspec-agents.md regenerated with new version\n- [x] Tag created and pushed\n- [x] GitHub release created\n- [ ] CI publishing to npm... (check Actions tab)\n\n**Release:** {repo}\u002Freleases\u002Ftag\u002Fv0.1.2\n**CI Status:** {repo}\u002Factions\n```\n\n## Release Notes Format\n\nGenerate **friendly, user-facing release notes** (not raw commit dumps):\n\n```markdown\nBrief high-level summary of what this release brings (1-2 sentences).\n\n### Features & Additions\n- Feature description in plain language\n- Another feature\n\n### Bug Fixes\n- Fixed issue with X when Y happened\n- Resolved problem where Z\n\n### Performance\n- Improved speed of X operation\n\n### Other Changes\n- Updated internal handling of Y\n- Refactored Z for maintainability\n\n**Full Changelog**: {repo}\u002Fcompare\u002Fv0.1.1...v0.1.2\n```\n\n**Writing guidelines:**\n- Write in past tense (\"Fixed\", \"Added\", \"Improved\")\n- Focus on user impact, not implementation details\n- Group related changes together\n- Omit test-only and CI-only changes\n- Use repo-relative URLs (GitHub auto-links them)\n\n## Error Handling\n\n| Error | Recovery |\n|-------|----------|\n| Not on main | `git checkout main && git pull` |\n| Dirty working tree | Commit or stash changes first |\n| Behind origin | `git pull origin main` |\n| No changes | Nothing to release since last tag |\n| Tag exists | Choose different version or `git tag -d v{version}` then `git push origin --delete v{version}` |\n| PR merge fails | Check CI status, fix issues, retry merge |\n| `gh` not installed | Install GitHub CLI: https:\u002F\u002Fcli.github.com\u002F |\n| `gh` not authenticated | Run `gh auth login` |\n| `gh` API rate limit | Wait and retry, or use `--limit` flag |\n\n### Rollback Procedure\n\nIf something goes wrong after partial release:\n\n**If tag was pushed but release failed:**\n```bash\n# Delete remote tag\ngit push origin --delete v$VERSION\n# Delete local tag\ngit tag -d v$VERSION\n# Fix issue and retry\n```\n\n**If release was created but CI publish failed:**\n```bash\n# Option 1: Delete and retry\ngh release delete v$VERSION --yes\ngit push origin --delete v$VERSION\ngit tag -d v$VERSION\n# Fix issue and retry from Phase 6\n\n# Option 2: Recover the existing published release through Actions\n# Prerequisite: v$VERSION already names a published, non-draft GitHub release.\n# In Actions > \"Publish to npm\" > \"Run workflow\", set:\n#   release-tag: v$VERSION\n#   dry-run: true        # default; reruns every gate without publishing\n# Review the dry-run result first. To actually recover npm publication, rerun\n# with the same release-tag and explicitly set dry-run: false.\n#\n# Both runs fail closed unless the remote tag still resolves to the immutable\n# release commit selected by preflight. Never move or recreate the tag during\n# recovery; a moved tag requires a new version-first release instead.\n```\n\n**If version PR was merged but you need to abort:**\n```bash\n# Revert the version bump\ngit revert HEAD\ngit push origin main\n# The tag was never created, so nothing else to clean up\n```\n\n## Examples\n\n### Standard patch release\n```\nUser: \u002Frelease patch\nAgent: [Validates state]\nAgent: [Creates version bump PR, waits for CI, merges]\nAgent: [Creates v0.1.2 tag, pushes, creates GH release]\n\nRelease v0.1.2 created successfully.\n- Version PR: #122 (merged)\n- Tag: v0.1.2\n- Release: {repo}\u002Freleases\u002Ftag\u002Fv0.1.2\n- CI publishing to npm...\n```\n\n### Auto-detect version\n```\nUser: \u002Frelease\nAgent: [Analyzes 5 commits: 2 feat, 3 fix]\nDetected: feat commits present -> minor bump (0.1.1 -> 0.2.0)\n[Proceeds with release]\n```\n\n### Preview only\n```\nUser: \u002Frelease --dry-run\nAgent: [Shows full preview, makes NO changes]\n```\n\n### Pre-release\n```\nUser: \u002Frelease minor --prerelease alpha\nAgent: [Creates v0.2.0-alpha.0]\n```\n\n### Explicit version\n```\nUser: \u002Frelease 1.0.0\nAgent: [Creates v1.0.0 - useful for major milestones]\n```\n\n## Maintaining release notes\n\nThe `RELEASE_NOTES.md` file at the repository root is the single source of\ntruth for kspec release notes. It is human-authored, reviewed by humans, and\nshipped in the published npm package so `kspec release-notes` and\n`kspec upgrade` can print it directly. There is no generator — edit the file\nby hand as part of the normal change flow.\n\n### Where the file lives\n\n- Path: `RELEASE_NOTES.md` at the repository root (the same directory as\n  `package.json`).\n- Packaged: listed in `package.json#files` so the published tarball\n  includes it. The CLI resolves it relative to its own install location.\n\n### File layout\n\n- A short top-of-file preamble explains the file.\n- Each release is a level-2 heading (`## vX.Y.Z`) with most-recent first.\n- An optional `## Unreleased` heading collects changes staged for the next\n  release. It lives above the top versioned section. Promote it to a\n  versioned heading as part of the release workflow (see below).\n\n### Required per-version subsections\n\nEvery versioned section must contain the following level-3 subsections, in\nthis order. Use the exact headings below — the CLI and release tests rely\non them:\n\n1. `### New or changed configuration` — name every new config key and\n   describe what it controls. If there are none, write a single line\n   `- No new configuration keys.`\n2. `### Breaking changes` — call out behavior changes that require\n   consumer action. If there are none, write `- None.`\n\nOptional additional subsections (use the ones that apply): `### Features &\nAdditions`, `### Bug Fixes`, `### Performance`, `### Documentation`,\n`### CI`, `### Other Changes`. Match the tone and writing guidelines in\n[Release Notes Format](#release-notes-format) above.\n\n### Adding an entry\n\nDuring normal work, edit the `## Unreleased` section to append bullet\npoints describing the change. Put each item in the right subsection (new\nconfig under `### New or changed configuration`, breaking changes under\n`### Breaking changes`, everything else under the appropriate optional\nsubsection). If a required subsection isn't present yet, add it.\n\nFor cross-version aggregation, keep the most recent entries near the top of\neach subsection. Don't worry about chronological ordering within a section.\n\n### Promoting Unreleased at release time\n\nWhen starting a release:\n\n1. Rename the `## Unreleased` heading to `## vX.Y.Z` with the version\n   number being released.\n2. Make sure both required subsections are present and non-empty (write\n   `- None.` \u002F `- No new configuration keys.` if there's nothing to say).\n3. Add a fresh empty `## Unreleased` section at the top for the next\n   release cycle. Leaving it off is fine, but having a placeholder makes\n   the next change's diff smaller.\n\n### Pre-release check\n\nBefore running the rest of the release workflow (Phase 5 onwards), verify\nthe notes for the version being released are present and non-empty. The\nexact check is:\n\n```bash\nVERSION=\"0.1.2\"  # the version you are about to release\nawk -v v=\"$VERSION\" '\n  $0 ~ \"^## v?\" v \"([^0-9.]|$)\" { in_section = 1; body = \"\"; next }\n  \u002F^## \u002F && in_section { exit }\n  in_section { body = body $0 \"\\n\" }\n  END {\n    gsub(\u002F[[:space:]]\u002F, \"\", body)\n    if (!in_section) { print \"error: no section for v\" v \" in RELEASE_NOTES.md\"; exit 1 }\n    if (body == \"\") { print \"error: section for v\" v \" is empty\"; exit 1 }\n  }\n' RELEASE_NOTES.md\n```\n\nIf the command exits non-zero, stop and author the missing notes before\ncontinuing. The release notes must be written and reviewed before the\nversion bump PR is created — not as a follow-up commit — so the tagged\ncommit and published tarball carry the notes users will read when they\nupgrade.\n\n## Key Principles\n\n- **Version bump first**: PR before tag ensures package.json matches release\n- **Validation first**: Check all constraints before any changes\n- **Dry-run is safe**: Preview makes zero changes\n- **Friendly release notes**: Write for users, not developers\n- **Branch protection compatible**: All changes via PR\n- **CI handles publishing**: Skill creates release, CI publishes to npm\n- **kspec integration**: Complete tasks before release, reference them in commits\n- **Release notes in the file**: Every released version has a non-empty\n  entry in `RELEASE_NOTES.md` — verified by the pre-release check above\n\n## Troubleshooting\n\n### npm Trusted Publishers OIDC Failures\n\nIf npm publish fails with \"Access token expired or revoked\" + 404:\n\n**Root cause:** Older npm versions (10.8.x bundled with Node 18) have bugs with OIDC authentication for trusted publishers.\n\n**Fix:** Ensure the publish workflow installs `npm@latest`:\n```yaml\n- name: Install latest npm\n  run: npm install -g npm@latest && npm --version\n```\n\nnpm 11.x+ has the necessary fixes.\n\n### PR Merge Blocked\n\nIf the version bump PR can't merge:\n\n1. Check CI status - tests must pass\n2. Check for merge conflicts - rebase if needed\n3. Check branch protection rules - ensure you have merge permissions\n\n### Tag Already Exists\n\nIf you need to re-release the same version:\n\n```bash\n# Delete existing tag (local and remote)\ngit tag -d v0.1.2\ngit push origin --delete v0.1.2\n\n# Delete GitHub release if it exists\ngh release delete v0.1.2 --yes\n\n# Now retry the release\n```\n\n## Related Skills\n\n- `\u002Fpr` - Create pull requests (used internally by this skill)\n- `\u002Faudit` - Pre-release codebase review\n- `\u002Fkspec:task-work` - Task lifecycle and completion tracking\n- `\u002Fkspec:help` - Command lookup and workflow help\n","\u003C!-- kspec-managed -->\n\n# Release Skill\n\nCreate versioned releases with proper git tagging and GitHub release creation. The workflow is:\n\n1. **Bump version** via PR (respects branch protection)\n2. **Create tag** on the merged commit\n3. **Create GitHub release** with notes\n4. **CI publishes** to npm automatically\n\n## When to Use\n\n- After completing features\u002Ffixes ready for release\n- When creating patch\u002Fminor\u002Fmajor version bumps\n- For pre-release versions (alpha, beta, rc)\n- When auditing what changes would be in a release (`--dry-run`)\n\n**Prerequisites:**\n- All related kspec tasks should be completed before release\n- Run `npm test` locally to verify tests pass\n- Ensure you're on `main` with a clean working tree\n\n## Arguments\n\n```\n\u002Frelease [patch|minor|major|X.Y.Z] [options]\n```\n\n| Argument | Description |\n|----------|-------------|\n| `patch` | Bug fixes, backwards-compatible (0.1.1 -> 0.1.2) |\n| `minor` | New features, backwards-compatible (0.1.1 -> 0.2.0) |\n| `major` | Breaking changes (0.1.1 -> 1.0.0) |\n| `X.Y.Z` | Explicit version number |\n| (none) | Auto-detect from commits since last tag |\n\n| Option | Description |\n|--------|-------------|\n| `--dry-run` | Preview only - NO changes to git, tags, PRs, or GitHub |\n| `--prerelease \u003Ctype>` | Create prerelease (alpha, beta, rc) |\n\n## Workflow\n\n### Phase 1: Detect Context\n\nGather information about current state:\n\n```bash\n# Get current branch\ngit branch --show-current\n\n# Check for uncommitted changes\ngit status --porcelain\n\n# Get current version from package.json\nnode -p \"require('.\u002Fpackage.json').version\"\n\n# Get last tag\ngit describe --tags --abbrev=0 2>\u002Fdev\u002Fnull || echo \"no-tags\"\n\n# Get commits since last tag\ngit log $(git describe --tags --abbrev=0 2>\u002Fdev\u002Fnull)..HEAD --oneline\n```\n\n**Context to gather:**\n- Current branch (must be `main`)\n- Working tree status (must be clean)\n- Current version in package.json\n- Last tag (e.g., v0.1.1)\n- Commits since last tag (count and list)\n\n### Phase 2: Validate Constraints\n\nAll constraints must pass before proceeding:\n\n| Constraint | Check | Error Message |\n|------------|-------|---------------|\n| On main branch | `git branch --show-current` = main | \"Must be on main branch. Currently on: {branch}\" |\n| Clean working tree | `git status --porcelain` is empty | \"Working tree must be clean. Commit or stash changes first.\" |\n| Up to date with origin | After `git fetch`, local matches remote | \"Local main is behind origin. Run: git pull\" |\n| Has releasable changes | At least one commit since last tag | \"No changes since last tag {tag}. Nothing to release.\" |\n| Tag doesn't exist | `git tag -l v{version}` is empty | \"Tag v{version} already exists.\" |\n\n**Dry-run behavior:** In dry-run mode, validation failures are reported but the preview continues. In normal mode, ANY validation failure stops execution immediately.\n\n### Phase 3: Determine Version\n\nIf version type not specified, auto-detect from ALL commits since last tag:\n\n```bash\n# Get all commit messages since last tag (not just merges)\ngit log $(git describe --tags --abbrev=0)..HEAD --pretty=format:\"%s%n%b\"\n```\n\n**Auto-detection rules (conventional commits):**\n\n| Pattern | Bump | Notes |\n|---------|------|-------|\n| `BREAKING CHANGE:` in body | major | Check commit body, not just subject |\n| `feat!:` or `fix!:` (with `!`) | major | The `!` suffix indicates breaking |\n| `feat:` or `feat(scope):` | minor | Scope is ignored for detection |\n| `fix:`, `perf:`, `refactor:`, `chore:` | patch | Any maintenance work |\n\n**Resolution order:**\n1. If ANY commit has breaking change indicator -> major\n2. Else if ANY commit starts with `feat:` -> minor\n3. Else -> patch\n\n**Prerelease handling (`--prerelease \u003Ctype>`):**\n\n| Current | Flag | Result | Rule |\n|---------|------|--------|------|\n| 0.1.1 | `--prerelease alpha` | 0.1.2-alpha.0 | Bump patch, add prerelease |\n| 0.1.2-alpha.0 | `--prerelease alpha` | 0.1.2-alpha.1 | Same type: increment counter |\n| 0.1.2-alpha.1 | `--prerelease beta` | 0.1.2-beta.0 | New type: reset counter to 0 |\n| 0.1.2-rc.0 | (no flag) | 0.1.2 | Stable release: drop prerelease suffix |\n\n**Prerelease rules:**\n1. Same prerelease type -> increment counter (alpha.0 -> alpha.1)\n2. Different prerelease type -> reset counter (alpha.1 -> beta.0)\n3. No prerelease flag on prerelease version -> promote to stable\n\n### Phase 4: Analyze Changes for Release Notes\n\nParse commits and categorize them for user-friendly release notes.\n\n**Commit selection:**\n- Prefer merge commits (contain `(#N)` PR reference) to avoid duplicates\n- If no merge commits, include all commits matching conventional patterns\n- Deduplicate by checking if a commit's changes are already in a merge commit\n\n**Categorization (commit type -> section):**\n\n| Commit Type | Release Notes Section |\n|-------------|----------------------|\n| `feat:` | Features & Additions |\n| `fix:` | Bug Fixes |\n| `perf:` | Performance |\n| `refactor:`, `chore:`, `build:` | Other Changes |\n| `test:`, `ci:`, `docs:` | (excluded unless user-facing) |\n\n**kspec integration:**\n```bash\n# Extract completed task references from commit trailers\ngit log $(git describe --tags --abbrev=0)..HEAD --pretty=format:\"%b\" | grep -E \"^Task: @\" | sort -u\n```\n\nCompleted tasks provide context for what was accomplished in this release.\n\n### Phase 5: Preview (--dry-run)\n\nFor `--dry-run`, show comprehensive preview. **No changes are made** - no PRs, no tags, no releases.\n\n```\n## Release Preview (DRY RUN)\n\n**Version bump:** 0.1.1 -> 0.1.2 (patch)\n**Detection:** Auto-detected from 5 commits (3 fix, 2 chore)\n\n### Validation\n- [x] On main branch\n- [x] Working tree clean\n- [x] Up to date with origin\n- [x] Has 5 commits since v0.1.1\n- [x] Tag v0.1.2 does not exist\n\n### Release Notes Preview\n\nBug fixes and improvements for kspec CLI.\n\n#### Features & Additions\n- Add JSON output mode for task list\n\n#### Bug Fixes\n- Fix author attribution for auto-generated notes\n- Increase timeout for ref resolution\n\n### Actions (dry-run: NOT executed)\n1. Create version bump PR (package.json -> 0.1.2)\n2. Regenerate kspec-agents.md with new version\n3. Wait for CI, then merge PR\n4. Create tag: v0.1.2\n5. Push tag to origin\n6. Create GitHub release with notes above\n7. CI will publish to npm\n\nTo execute: run `\u002Frelease` without --dry-run\n```\n\n### Phase 6: Bump Version (PR)\n\n**Before creating the tag**, update package.json via PR:\n\n```bash\nVERSION=\"0.1.2\"  # calculated version\n\n# Create branch for version bump\ngit checkout -b release\u002Fv$VERSION\n\n# Update version without creating a tag\nnpm version $VERSION --no-git-tag-version\n\n# Regenerate kspec-agents.md so the version header stays in sync\n# For self-hosting (releasing kspec itself), use: npm run dev -- agents generate\nkspec agents generate\n\n# Commit and push\ngit add package.json package-lock.json kspec-agents.md\ngit commit -m \"chore: bump version to $VERSION\"\ngit push -u origin release\u002Fv$VERSION\n\n# Create PR\ngh pr create --title \"chore: bump version to $VERSION\" --body \"Prepare release v$VERSION\"\n\n# Wait for CI to pass, then merge\ngh pr merge --merge --delete-branch\n```\n\n**Why version bump first?**\n- The tagged commit has the correct version in package.json\n- CI publishes exactly what's in package.json\n- No out-of-sync state between git tag and package version\n\n**Why regenerate kspec-agents.md?**\n- The freshness comment includes the kspec version (`Generated by kspec vX.Y.Z`)\n- Regenerating after the version bump keeps the header in sync with the release\n- **Self-hosting note:** When releasing kspec itself, the installed `kspec` binary still has the old version. Use `npm run dev -- agents generate` instead so the dev build reads the bumped version from the local package.json\n\n### Phase 7: Create Tag and Release\n\nAfter the version PR is merged:\n\n```bash\n# Pull the merged version bump\ngit checkout main && git pull\n\n# Create annotated tag (v prefix is convention for npm\u002Fsemver)\ngit tag -a \"v$VERSION\" -m \"Release v$VERSION\"\n\n# Push tag to origin\ngit push origin \"v$VERSION\"\n\n# Create GitHub release (gh uses current repo automatically)\ngh release create \"v$VERSION\" \\\n  --title \"v$VERSION\" \\\n  --notes \"$(cat \u003C\u003C'EOF'\nBrief summary of this release.\n\n### Features & Additions\n- Feature description\n\n### Bug Fixes\n- Fix description\n\n### Other Changes\n- Change description\n\n**Full Changelog**: compare\u002Fv{previous}...v{version}\nEOF\n)\"\n```\n\n**Tag naming:** Always use `v` prefix (e.g., `v0.1.2`) for consistency with npm versioning conventions and GitHub release detection.\n\n**CI behavior:**\n- Triggers on `release.published` event (within 1-2 minutes)\n- Runs tests and publishes to npm with provenance\n- Monitor progress at the repo's Actions tab\n\n### Phase 8: Report Summary\n\nAfter successful release:\n\n```\n## Release Complete\n\n**Version:** v0.1.2\n**Tag:** v0.1.2\n**Commit:** abc1234\n\n### Completed\n- [x] Version PR created and merged\n- [x] kspec-agents.md regenerated with new version\n- [x] Tag created and pushed\n- [x] GitHub release created\n- [ ] CI publishing to npm... (check Actions tab)\n\n**Release:** {repo}\u002Freleases\u002Ftag\u002Fv0.1.2\n**CI Status:** {repo}\u002Factions\n```\n\n## Release Notes Format\n\nGenerate **friendly, user-facing release notes** (not raw commit dumps):\n\n```markdown\nBrief high-level summary of what this release brings (1-2 sentences).\n\n### Features & Additions\n- Feature description in plain language\n- Another feature\n\n### Bug Fixes\n- Fixed issue with X when Y happened\n- Resolved problem where Z\n\n### Performance\n- Improved speed of X operation\n\n### Other Changes\n- Updated internal handling of Y\n- Refactored Z for maintainability\n\n**Full Changelog**: {repo}\u002Fcompare\u002Fv0.1.1...v0.1.2\n```\n\n**Writing guidelines:**\n- Write in past tense (\"Fixed\", \"Added\", \"Improved\")\n- Focus on user impact, not implementation details\n- Group related changes together\n- Omit test-only and CI-only changes\n- Use repo-relative URLs (GitHub auto-links them)\n\n## Error Handling\n\n| Error | Recovery |\n|-------|----------|\n| Not on main | `git checkout main && git pull` |\n| Dirty working tree | Commit or stash changes first |\n| Behind origin | `git pull origin main` |\n| No changes | Nothing to release since last tag |\n| Tag exists | Choose different version or `git tag -d v{version}` then `git push origin --delete v{version}` |\n| PR merge fails | Check CI status, fix issues, retry merge |\n| `gh` not installed | Install GitHub CLI: https:\u002F\u002Fcli.github.com\u002F |\n| `gh` not authenticated | Run `gh auth login` |\n| `gh` API rate limit | Wait and retry, or use `--limit` flag |\n\n### Rollback Procedure\n\nIf something goes wrong after partial release:\n\n**If tag was pushed but release failed:**\n```bash\n# Delete remote tag\ngit push origin --delete v$VERSION\n# Delete local tag\ngit tag -d v$VERSION\n# Fix issue and retry\n```\n\n**If release was created but CI publish failed:**\n```bash\n# Option 1: Delete and retry\ngh release delete v$VERSION --yes\ngit push origin --delete v$VERSION\ngit tag -d v$VERSION\n# Fix issue and retry from Phase 6\n\n# Option 2: Recover the existing published release through Actions\n# Prerequisite: v$VERSION already names a published, non-draft GitHub release.\n# In Actions > \"Publish to npm\" > \"Run workflow\", set:\n#   release-tag: v$VERSION\n#   dry-run: true        # default; reruns every gate without publishing\n# Review the dry-run result first. To actually recover npm publication, rerun\n# with the same release-tag and explicitly set dry-run: false.\n#\n# Both runs fail closed unless the remote tag still resolves to the immutable\n# release commit selected by preflight. Never move or recreate the tag during\n# recovery; a moved tag requires a new version-first release instead.\n```\n\n**If version PR was merged but you need to abort:**\n```bash\n# Revert the version bump\ngit revert HEAD\ngit push origin main\n# The tag was never created, so nothing else to clean up\n```\n\n## Examples\n\n### Standard patch release\n```\nUser: \u002Frelease patch\nAgent: [Validates state]\nAgent: [Creates version bump PR, waits for CI, merges]\nAgent: [Creates v0.1.2 tag, pushes, creates GH release]\n\nRelease v0.1.2 created successfully.\n- Version PR: #122 (merged)\n- Tag: v0.1.2\n- Release: {repo}\u002Freleases\u002Ftag\u002Fv0.1.2\n- CI publishing to npm...\n```\n\n### Auto-detect version\n```\nUser: \u002Frelease\nAgent: [Analyzes 5 commits: 2 feat, 3 fix]\nDetected: feat commits present -> minor bump (0.1.1 -> 0.2.0)\n[Proceeds with release]\n```\n\n### Preview only\n```\nUser: \u002Frelease --dry-run\nAgent: [Shows full preview, makes NO changes]\n```\n\n### Pre-release\n```\nUser: \u002Frelease minor --prerelease alpha\nAgent: [Creates v0.2.0-alpha.0]\n```\n\n### Explicit version\n```\nUser: \u002Frelease 1.0.0\nAgent: [Creates v1.0.0 - useful for major milestones]\n```\n\n## Maintaining release notes\n\nThe `RELEASE_NOTES.md` file at the repository root is the single source of\ntruth for kspec release notes. It is human-authored, reviewed by humans, and\nshipped in the published npm package so `kspec release-notes` and\n`kspec upgrade` can print it directly. There is no generator — edit the file\nby hand as part of the normal change flow.\n\n### Where the file lives\n\n- Path: `RELEASE_NOTES.md` at the repository root (the same directory as\n  `package.json`).\n- Packaged: listed in `package.json#files` so the published tarball\n  includes it. The CLI resolves it relative to its own install location.\n\n### File layout\n\n- A short top-of-file preamble explains the file.\n- Each release is a level-2 heading (`## vX.Y.Z`) with most-recent first.\n- An optional `## Unreleased` heading collects changes staged for the next\n  release. It lives above the top versioned section. Promote it to a\n  versioned heading as part of the release workflow (see below).\n\n### Required per-version subsections\n\nEvery versioned section must contain the following level-3 subsections, in\nthis order. Use the exact headings below — the CLI and release tests rely\non them:\n\n1. `### New or changed configuration` — name every new config key and\n   describe what it controls. If there are none, write a single line\n   `- No new configuration keys.`\n2. `### Breaking changes` — call out behavior changes that require\n   consumer action. If there are none, write `- None.`\n\nOptional additional subsections (use the ones that apply): `### Features &\nAdditions`, `### Bug Fixes`, `### Performance`, `### Documentation`,\n`### CI`, `### Other Changes`. Match the tone and writing guidelines in\n[Release Notes Format](#release-notes-format) above.\n\n### Adding an entry\n\nDuring normal work, edit the `## Unreleased` section to append bullet\npoints describing the change. Put each item in the right subsection (new\nconfig under `### New or changed configuration`, breaking changes under\n`### Breaking changes`, everything else under the appropriate optional\nsubsection). If a required subsection isn't present yet, add it.\n\nFor cross-version aggregation, keep the most recent entries near the top of\neach subsection. Don't worry about chronological ordering within a section.\n\n### Promoting Unreleased at release time\n\nWhen starting a release:\n\n1. Rename the `## Unreleased` heading to `## vX.Y.Z` with the version\n   number being released.\n2. Make sure both required subsections are present and non-empty (write\n   `- None.` \u002F `- No new configuration keys.` if there's nothing to say).\n3. Add a fresh empty `## Unreleased` section at the top for the next\n   release cycle. Leaving it off is fine, but having a placeholder makes\n   the next change's diff smaller.\n\n### Pre-release check\n\nBefore running the rest of the release workflow (Phase 5 onwards), verify\nthe notes for the version being released are present and non-empty. The\nexact check is:\n\n```bash\nVERSION=\"0.1.2\"  # the version you are about to release\nawk -v v=\"$VERSION\" '\n  $0 ~ \"^## v?\" v \"([^0-9.]|$)\" { in_section = 1; body = \"\"; next }\n  \u002F^## \u002F && in_section { exit }\n  in_section { body = body $0 \"\\n\" }\n  END {\n    gsub(\u002F[[:space:]]\u002F, \"\", body)\n    if (!in_section) { print \"error: no section for v\" v \" in RELEASE_NOTES.md\"; exit 1 }\n    if (body == \"\") { print \"error: section for v\" v \" is empty\"; exit 1 }\n  }\n' RELEASE_NOTES.md\n```\n\nIf the command exits non-zero, stop and author the missing notes before\ncontinuing. The release notes must be written and reviewed before the\nversion bump PR is created — not as a follow-up commit — so the tagged\ncommit and published tarball carry the notes users will read when they\nupgrade.\n\n## Key Principles\n\n- **Version bump first**: PR before tag ensures package.json matches release\n- **Validation first**: Check all constraints before any changes\n- **Dry-run is safe**: Preview makes zero changes\n- **Friendly release notes**: Write for users, not developers\n- **Branch protection compatible**: All changes via PR\n- **CI handles publishing**: Skill creates release, CI publishes to npm\n- **kspec integration**: Complete tasks before release, reference them in commits\n- **Release notes in the file**: Every released version has a non-empty\n  entry in `RELEASE_NOTES.md` — verified by the pre-release check above\n\n## Troubleshooting\n\n### npm Trusted Publishers OIDC Failures\n\nIf npm publish fails with \"Access token expired or revoked\" + 404:\n\n**Root cause:** Older npm versions (10.8.x bundled with Node 18) have bugs with OIDC authentication for trusted publishers.\n\n**Fix:** Ensure the publish workflow installs `npm@latest`:\n```yaml\n- name: Install latest npm\n  run: npm install -g npm@latest && npm --version\n```\n\nnpm 11.x+ has the necessary fixes.\n\n### PR Merge Blocked\n\nIf the version bump PR can't merge:\n\n1. Check CI status - tests must pass\n2. Check for merge conflicts - rebase if needed\n3. Check branch protection rules - ensure you have merge permissions\n\n### Tag Already Exists\n\nIf you need to re-release the same version:\n\n```bash\n# Delete existing tag (local and remote)\ngit tag -d v0.1.2\ngit push origin --delete v0.1.2\n\n# Delete GitHub release if it exists\ngh release delete v0.1.2 --yes\n\n# Now retry the release\n```\n\n## Related Skills\n\n- `\u002Fpr` - Create pull requests (used internally by this skill)\n- `\u002Faudit` - Pre-release codebase review\n- `\u002Fkspec:task-work` - Task lifecycle and completion tracking\n- `\u002Fkspec:help` - Command lookup and workflow help\n",{"name":5,"description":7},"main","c4b0de3035f8512bba7eb0a9b4e39ea2fbd3f08e",".claude\u002Fskills\u002Frelease",2,"https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec","https:\u002F\u002Fgithub.com\u002Flepahc","2026-07-22 18:57:40",{"source":8,"skillName":5,"commands":41,"prompt":51,"zipAvailable":52},[42,45,48],{"tool":43,"command":44},"npx","npx skills add lepahc\u002Fkynetic-spec --skill release",{"tool":46,"command":47},"bunx","bunx skills add lepahc\u002Fkynetic-spec --skill release",{"tool":49,"command":50},"pnpm","pnpm dlx skills add lepahc\u002Fkynetic-spec --skill release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frelease\u002FSKILL.md",true,[],[55,73,79,87,98,106],{"skillNo":56,"name":57,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":58,"categories":59,"keywords":70,"publishedAt":28},"01M6C7KCZE43MDZ74FV3A5TDCQ","writing-specs","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Fwriting-specs\u002FSKILL.md",[60,65],{"categoryNo":61,"categoryName":62,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000018","写作与文案","SCENARIO","使用场景",{"categoryNo":66,"categoryName":67,"taxonomyType":68,"taxonomyTypeDesc":69},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[71,72],"writing","writing specs",{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":28},"01M6C7KAK9CBJ87PX3BCW7B7YG","triage","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Ftriage\u002FSKILL.md",[],[75],{"skillNo":80,"name":81,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":28},"01M6C7K89VN6FJCT8M86K56EE8","triage-inbox","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Ftriage-inbox\u002FSKILL.md",[],[75,85,86],"inbox","triage inbox",{"skillNo":88,"name":89,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":95,"publishedAt":28},"01M6C7K6F2342AC1TJCN9PM0ZB","triage-automation","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Ftriage-automation\u002FSKILL.md",[92],{"categoryNo":93,"categoryName":94,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000023","Skill与智能体开发",[75,96,97],"automation","triage automation",{"skillNo":99,"name":100,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":28},"01M6C7K3TFQ88QQBW3PXYDHQG2","task-work","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Ftask-work\u002FSKILL.md",[],[104,105],"work","task work",{"skillNo":107,"name":108,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":28},"01M6C7K168CH3XJCC3PDGA9H6C","review","https:\u002F\u002Fgithub.com\u002Flepahc\u002Fkynetic-spec\u002Fblob\u002Fmain\u002Ftemplates\u002Fskills\u002Freview\u002FSKILL.md",[],[108]]