[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6R7406FFTQ8076P8Y52Y30E":3,"skill-same:01M6R7406FFTQ8076P8Y52Y30E":58},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":31,"linkOnly":32,"markdownContent":33,"markdownBody":34,"frontMatter":35,"refName":38,"commitSha":39,"skillDirectory":40,"forksCount":13,"repositoryHtmlUrl":41,"repositoryHomepageUrl":6,"ownerHtmlUrl":42,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M6R7406FFTQ8076P8Y52Y30E","release-process",null,"Step-by-step release checklist for Squad — prevents v0.8.22-style disasters","barichter\u002Fsquad","barichter","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F96797186?v=4","01M6R712K8ESMDF089BFENBR16","01M6R712R74BSQQSG2GTXBWR8P",0,"MIT","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002F.copilot\u002Fskills\u002Frelease-process\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30],"release process","release","process","squad","team","decision","management","v0","checklist","style","release checklist","high","for","2026-11-10 10:12:30",false,"---\nname: \"release-process\"\ndescription: \"Step-by-step release checklist for Squad — prevents v0.8.22-style disasters\"\ndomain: \"release-management\"\nconfidence: \"high\"\nsource: \"team-decision\"\n---\n\n## Context\n\nThis is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag).\n\n**Rule:** No agent releases Squad without following this checklist. No exceptions. No improvisation.\n\n---\n\n## Pre-Release Validation\n\nBefore starting ANY release work, validate the following:\n\n### 1. Version Number Validation\n\n**Rule:** Only 3-part semver (major.minor.patch) or prerelease (major.minor.patch-tag.N) are valid. 4-part versions (0.8.21.4) are NOT valid semver and npm will mangle them.\n\n```bash\n# Check version is valid semver\nnode -p \"require('semver').valid('0.8.22')\"\n# Output: '0.8.22' = valid\n# Output: null = INVALID, STOP\n\n# For prerelease versions\nnode -p \"require('semver').valid('0.8.23-preview.1')\"\n# Output: '0.8.23-preview.1' = valid\n```\n\n**If `semver.valid()` returns `null`:** STOP. Fix the version. Do NOT proceed.\n\n### 2. NPM_TOKEN Verification\n\n**Rule:** NPM_TOKEN must be an **Automation token** (no 2FA required). User tokens with 2FA will fail in CI with EOTP errors.\n\n```bash\n# Check token type (requires npm CLI authenticated)\nnpm token list\n```\n\nLook for:\n- ✅ `read-write` tokens with NO 2FA requirement = Automation token (correct)\n- ❌ Tokens requiring OTP = User token (WRONG, will fail in CI)\n\n**How to create an Automation token:**\n1. Go to npmjs.com → Settings → Access Tokens\n2. Click \"Generate New Token\"\n3. Select **\"Automation\"** (NOT \"Publish\")\n4. Copy token and save as GitHub secret: `NPM_TOKEN`\n\n**If using a User token:** STOP. Create an Automation token first.\n\n### 3. Branch and Tag State\n\n**Rule:** Release from `main` branch. Ensure clean state, no uncommitted changes, latest from origin.\n\n```bash\n# Ensure on main and clean\ngit checkout main\ngit pull origin main\ngit status  # Should show: \"nothing to commit, working tree clean\"\n\n# Check tag doesn't already exist\ngit tag -l \"v0.8.22\"\n# Output should be EMPTY. If tag exists, release already done or collision.\n```\n\n**If tag exists:** STOP. Either release was already done, or there's a collision. Investigate before proceeding.\n\n### 4. Disable bump-build.mjs\n\n**Rule:** `bump-build.mjs` is for dev builds ONLY. It must NOT run during release builds (it increments build numbers, creating 4-part versions).\n\n```bash\n# Set env var to skip bump-build.mjs\nexport SKIP_BUILD_BUMP=1\n\n# Verify it's set\necho $SKIP_BUILD_BUMP\n# Output: 1\n```\n\n**For Windows PowerShell:**\n```powershell\n$env:SKIP_BUILD_BUMP = \"1\"\n```\n\n**If not set:** `bump-build.mjs` will run and mutate versions. This causes disasters (see v0.8.22).\n\n---\n\n## Release Workflow\n\n### Step 1: Version Bump\n\nUpdate version in all 3 package.json files (root + both workspaces) in lockstep.\n\n```bash\n# Set target version (no 'v' prefix)\nVERSION=\"0.8.22\"\n\n# Validate it's valid semver BEFORE proceeding\nnode -p \"require('semver').valid('$VERSION')\"\n# Must output the version string, NOT null\n\n# Update all 3 package.json files\nnpm version $VERSION --workspaces --include-workspace-root --no-git-tag-version\n\n# Verify all 3 match\ngrep '\"version\"' package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\n# All 3 should show: \"version\": \"0.8.22\"\n```\n\n**Checkpoint:** All 3 package.json files have identical versions. Run `semver.valid()` one more time to be sure.\n\n### Step 2: Commit and Tag\n\n```bash\n# Commit version bump\ngit add package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\ngit commit -m \"chore: bump version to $VERSION\n\nCo-authored-by: Copilot \u003C223556219+Copilot@users.noreply.github.com>\"\n\n# Create tag (with 'v' prefix)\ngit tag -a \"v$VERSION\" -m \"Release v$VERSION\"\n\n# Push commit and tag\ngit push origin main\ngit push origin \"v$VERSION\"\n```\n\n**Checkpoint:** Tag created and pushed. Verify with `git tag -l \"v$VERSION\"`.\n\n### Step 3: Create GitHub Release\n\n**CRITICAL:** Release must be **published**, NOT draft. Draft releases don't trigger `publish.yml` workflow.\n\n```bash\n# Create GitHub Release (NOT draft)\ngh release create \"v$VERSION\" \\\n  --title \"v$VERSION\" \\\n  --notes \"Release notes go here\" \\\n  --latest\n\n# Verify release is PUBLISHED (not draft)\ngh release view \"v$VERSION\"\n# Output should NOT contain \"(draft)\"\n```\n\n**If output contains `(draft)`:** STOP. Delete the release and recreate without `--draft` flag.\n\n```bash\n# If you accidentally created a draft, fix it:\ngh release edit \"v$VERSION\" --draft=false\n```\n\n**Checkpoint:** Release is published (NOT draft). The `release: published` event fired and triggered `publish.yml`.\n\n### Step 4: Monitor Workflow\n\nThe `publish.yml` workflow should start automatically within 10 seconds of release creation.\n\n```bash\n# Watch workflow runs\ngh run list --workflow=publish.yml --limit 1\n\n# Get detailed status\ngh run view --log\n```\n\n**Expected flow:**\n1. `publish-sdk` job runs → publishes `@bradygaster\u002Fsquad-sdk`\n2. Verify step runs with retry loop (up to 5 attempts, 15s interval) to confirm SDK on npm registry\n3. `publish-cli` job runs → publishes `@bradygaster\u002Fsquad-cli`\n4. Verify step runs with retry loop to confirm CLI on npm registry\n\n**If workflow fails:** Check the logs. Common issues:\n- EOTP error = wrong NPM_TOKEN type (use Automation token)\n- Verify step timeout = npm propagation delay (retry loop should handle this, but propagation can take up to 2 minutes in rare cases)\n- Version mismatch = package.json version doesn't match tag\n\n**Checkpoint:** Both jobs succeeded. Workflow shows green checkmarks.\n\n### Step 5: Verify npm Publication\n\nManually verify both packages are on npm with correct `latest` dist-tag.\n\n```bash\n# Check SDK\nnpm view @bradygaster\u002Fsquad-sdk version\n# Output: 0.8.22\n\nnpm dist-tag ls @bradygaster\u002Fsquad-sdk\n# Output should show: latest: 0.8.22\n\n# Check CLI\nnpm view @bradygaster\u002Fsquad-cli version\n# Output: 0.8.22\n\nnpm dist-tag ls @bradygaster\u002Fsquad-cli\n# Output should show: latest: 0.8.22\n```\n\n**If versions don't match:** Something went wrong. Check workflow logs. DO NOT proceed with GitHub Release announcement until npm is correct.\n\n**Checkpoint:** Both packages show correct version. `latest` dist-tags point to the new version.\n\n### Step 6: Test Installation\n\nVerify packages can be installed from npm (real-world smoke test).\n\n```bash\n# Create temp directory\nmkdir \u002Ftmp\u002Fsquad-release-test && cd \u002Ftmp\u002Fsquad-release-test\n\n# Test SDK installation\nnpm init -y\nnpm install @bradygaster\u002Fsquad-sdk\nnode -p \"require('@bradygaster\u002Fsquad-sdk\u002Fpackage.json').version\"\n# Output: 0.8.22\n\n# Test CLI installation\nnpm install -g @bradygaster\u002Fsquad-cli\nsquad --version\n# Output: 0.8.22\n\n# Cleanup\ncd -\nrm -rf \u002Ftmp\u002Fsquad-release-test\n```\n\n**If installation fails:** npm registry issue or package metadata corruption. DO NOT announce release until this works.\n\n**Checkpoint:** Both packages install cleanly. Versions match.\n\n### Step 7: Sync dev to Next Preview\n\nAfter main release, sync dev to the next preview version.\n\n```bash\n# Checkout dev\ngit checkout dev\ngit pull origin dev\n\n# Bump to next preview version (e.g., 0.8.23-preview.1)\nNEXT_VERSION=\"0.8.23-preview.1\"\n\n# Validate semver\nnode -p \"require('semver').valid('$NEXT_VERSION')\"\n# Must output the version string, NOT null\n\n# Update all 3 package.json files\nnpm version $NEXT_VERSION --workspaces --include-workspace-root --no-git-tag-version\n\n# Commit\ngit add package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\ngit commit -m \"chore: bump dev to $NEXT_VERSION\n\nCo-authored-by: Copilot \u003C223556219+Copilot@users.noreply.github.com>\"\n\n# Push\ngit push origin dev\n```\n\n**Checkpoint:** dev branch now shows next preview version. Future dev builds will publish to `@preview` dist-tag.\n\n---\n\n## Manual Publish (Fallback)\n\nIf `publish.yml` workflow fails or needs to be bypassed, use `workflow_dispatch` to manually trigger publish.\n\n```bash\n# Trigger manual publish\ngh workflow run publish.yml -f version=\"0.8.22\"\n\n# Monitor the run\ngh run watch\n```\n\n**Rule:** Only use this if automated publish failed. Always investigate why automation failed and fix it for next release.\n\n---\n\n## Rollback Procedure\n\nIf a release is broken and needs to be rolled back:\n\n### 1. Unpublish from npm (Nuclear Option)\n\n**WARNING:** npm unpublish is time-limited (24 hours) and leaves the version slot burned. Only use if version is critically broken.\n\n```bash\n# Unpublish (requires npm owner privileges)\nnpm unpublish @bradygaster\u002Fsquad-sdk@0.8.22\nnpm unpublish @bradygaster\u002Fsquad-cli@0.8.22\n```\n\n### 2. Deprecate on npm (Preferred)\n\n**Preferred approach:** Mark version as deprecated, publish a hotfix.\n\n```bash\n# Deprecate broken version\nnpm deprecate @bradygaster\u002Fsquad-sdk@0.8.22 \"Broken release, use 0.8.22.1 instead\"\nnpm deprecate @bradygaster\u002Fsquad-cli@0.8.22 \"Broken release, use 0.8.22.1 instead\"\n\n# Publish hotfix version\n# (Follow this runbook with version 0.8.22.1)\n```\n\n### 3. Delete GitHub Release and Tag\n\n```bash\n# Delete GitHub Release\ngh release delete \"v0.8.22\" --yes\n\n# Delete tag locally and remotely\ngit tag -d \"v0.8.22\"\ngit push origin --delete \"v0.8.22\"\n```\n\n### 4. Revert Commit on main\n\n```bash\n# Revert version bump commit\ngit checkout main\ngit revert HEAD\ngit push origin main\n```\n\n**Checkpoint:** Tag and release deleted. main branch reverted. npm packages deprecated or unpublished.\n\n---\n\n## Common Failure Modes\n\n### EOTP Error (npm OTP Required)\n\n**Symptom:** Workflow fails with `EOTP` error.  \n**Root cause:** NPM_TOKEN is a User token with 2FA enabled. CI can't provide OTP.  \n**Fix:** Replace NPM_TOKEN with an Automation token (no 2FA). See \"NPM_TOKEN Verification\" above.\n\n### Verify Step 404 (npm Propagation Delay)\n\n**Symptom:** Verify step fails with 404 even though publish succeeded.  \n**Root cause:** npm registry propagation delay (5-30 seconds).  \n**Fix:** Verify step now has retry loop (5 attempts, 15s interval). Should auto-resolve. If not, wait 2 minutes and re-run workflow.\n\n### Version Mismatch (package.json ≠ tag)\n\n**Symptom:** Verify step fails with \"Package version (X) does not match target version (Y)\".  \n**Root cause:** package.json version doesn't match the tag version.  \n**Fix:** Ensure all 3 package.json files were updated in Step 1. Re-run `npm version` if needed.\n\n### 4-Part Version Mangled by npm\n\n**Symptom:** Published version on npm doesn't match package.json (e.g., 0.8.21.4 became 0.8.2-1.4).  \n**Root cause:** 4-part versions are NOT valid semver. npm's parser misinterprets them.  \n**Fix:** NEVER use 4-part versions. Only 3-part (0.8.22) or prerelease (0.8.23-preview.1). Run `semver.valid()` before ANY commit.\n\n### Draft Release Didn't Trigger Workflow\n\n**Symptom:** Release created but `publish.yml` never ran.  \n**Root cause:** Release was created as a draft. Draft releases don't emit `release: published` event.  \n**Fix:** Edit release and change to published: `gh release edit \"v$VERSION\" --draft=false`. Workflow should trigger immediately.\n\n---\n\n## Validation Checklist\n\nBefore starting ANY release, confirm:\n\n- [ ] Version is valid semver: `node -p \"require('semver').valid('VERSION')\"` returns the version string (NOT null)\n- [ ] NPM_TOKEN is an Automation token (no 2FA): `npm token list` shows `read-write` without OTP requirement\n- [ ] Branch is clean: `git status` shows \"nothing to commit, working tree clean\"\n- [ ] Tag doesn't exist: `git tag -l \"vVERSION\"` returns empty\n- [ ] `SKIP_BUILD_BUMP=1` is set: `echo $SKIP_BUILD_BUMP` returns `1`\n\nBefore creating GitHub Release:\n\n- [ ] All 3 package.json files have matching versions: `grep '\"version\"' package.json packages\u002F*\u002Fpackage.json`\n- [ ] Commit is pushed: `git log origin\u002Fmain..main` returns empty\n- [ ] Tag is pushed: `git ls-remote --tags origin vVERSION` returns the tag SHA\n\nAfter GitHub Release:\n\n- [ ] Release is published (NOT draft): `gh release view \"vVERSION\"` output doesn't contain \"(draft)\"\n- [ ] Workflow is running: `gh run list --workflow=publish.yml --limit 1` shows \"in_progress\"\n\nAfter workflow completes:\n\n- [ ] Both jobs succeeded: Workflow shows green checkmarks\n- [ ] SDK on npm: `npm view @bradygaster\u002Fsquad-sdk version` returns correct version\n- [ ] CLI on npm: `npm view @bradygaster\u002Fsquad-cli version` returns correct version\n- [ ] `latest` tags correct: `npm dist-tag ls @bradygaster\u002Fsquad-sdk` shows `latest: VERSION`\n- [ ] Packages install: `npm install @bradygaster\u002Fsquad-cli` succeeds\n\nAfter dev sync:\n\n- [ ] dev branch has next preview version: `git show dev:package.json | grep version` shows next preview\n\n---\n\n## Post-Mortem Reference\n\nThis skill was created after the v0.8.22 release disaster. Full retrospective: `.squad\u002Fdecisions\u002Finbox\u002Fkeaton-v0822-retrospective.md`\n\n**Key learnings:**\n1. No release without a runbook = improvisation = disaster\n2. Semver validation is mandatory — 4-part versions break npm\n3. NPM_TOKEN type matters — User tokens with 2FA fail in CI\n4. Draft releases are a footgun — they don't trigger automation\n5. Retry logic is essential — npm propagation takes time\n\n**Never again.**\n","## Context\n\nThis is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag).\n\n**Rule:** No agent releases Squad without following this checklist. No exceptions. No improvisation.\n\n---\n\n## Pre-Release Validation\n\nBefore starting ANY release work, validate the following:\n\n### 1. Version Number Validation\n\n**Rule:** Only 3-part semver (major.minor.patch) or prerelease (major.minor.patch-tag.N) are valid. 4-part versions (0.8.21.4) are NOT valid semver and npm will mangle them.\n\n```bash\n# Check version is valid semver\nnode -p \"require('semver').valid('0.8.22')\"\n# Output: '0.8.22' = valid\n# Output: null = INVALID, STOP\n\n# For prerelease versions\nnode -p \"require('semver').valid('0.8.23-preview.1')\"\n# Output: '0.8.23-preview.1' = valid\n```\n\n**If `semver.valid()` returns `null`:** STOP. Fix the version. Do NOT proceed.\n\n### 2. NPM_TOKEN Verification\n\n**Rule:** NPM_TOKEN must be an **Automation token** (no 2FA required). User tokens with 2FA will fail in CI with EOTP errors.\n\n```bash\n# Check token type (requires npm CLI authenticated)\nnpm token list\n```\n\nLook for:\n- ✅ `read-write` tokens with NO 2FA requirement = Automation token (correct)\n- ❌ Tokens requiring OTP = User token (WRONG, will fail in CI)\n\n**How to create an Automation token:**\n1. Go to npmjs.com → Settings → Access Tokens\n2. Click \"Generate New Token\"\n3. Select **\"Automation\"** (NOT \"Publish\")\n4. Copy token and save as GitHub secret: `NPM_TOKEN`\n\n**If using a User token:** STOP. Create an Automation token first.\n\n### 3. Branch and Tag State\n\n**Rule:** Release from `main` branch. Ensure clean state, no uncommitted changes, latest from origin.\n\n```bash\n# Ensure on main and clean\ngit checkout main\ngit pull origin main\ngit status  # Should show: \"nothing to commit, working tree clean\"\n\n# Check tag doesn't already exist\ngit tag -l \"v0.8.22\"\n# Output should be EMPTY. If tag exists, release already done or collision.\n```\n\n**If tag exists:** STOP. Either release was already done, or there's a collision. Investigate before proceeding.\n\n### 4. Disable bump-build.mjs\n\n**Rule:** `bump-build.mjs` is for dev builds ONLY. It must NOT run during release builds (it increments build numbers, creating 4-part versions).\n\n```bash\n# Set env var to skip bump-build.mjs\nexport SKIP_BUILD_BUMP=1\n\n# Verify it's set\necho $SKIP_BUILD_BUMP\n# Output: 1\n```\n\n**For Windows PowerShell:**\n```powershell\n$env:SKIP_BUILD_BUMP = \"1\"\n```\n\n**If not set:** `bump-build.mjs` will run and mutate versions. This causes disasters (see v0.8.22).\n\n---\n\n## Release Workflow\n\n### Step 1: Version Bump\n\nUpdate version in all 3 package.json files (root + both workspaces) in lockstep.\n\n```bash\n# Set target version (no 'v' prefix)\nVERSION=\"0.8.22\"\n\n# Validate it's valid semver BEFORE proceeding\nnode -p \"require('semver').valid('$VERSION')\"\n# Must output the version string, NOT null\n\n# Update all 3 package.json files\nnpm version $VERSION --workspaces --include-workspace-root --no-git-tag-version\n\n# Verify all 3 match\ngrep '\"version\"' package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\n# All 3 should show: \"version\": \"0.8.22\"\n```\n\n**Checkpoint:** All 3 package.json files have identical versions. Run `semver.valid()` one more time to be sure.\n\n### Step 2: Commit and Tag\n\n```bash\n# Commit version bump\ngit add package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\ngit commit -m \"chore: bump version to $VERSION\n\nCo-authored-by: Copilot \u003C223556219+Copilot@users.noreply.github.com>\"\n\n# Create tag (with 'v' prefix)\ngit tag -a \"v$VERSION\" -m \"Release v$VERSION\"\n\n# Push commit and tag\ngit push origin main\ngit push origin \"v$VERSION\"\n```\n\n**Checkpoint:** Tag created and pushed. Verify with `git tag -l \"v$VERSION\"`.\n\n### Step 3: Create GitHub Release\n\n**CRITICAL:** Release must be **published**, NOT draft. Draft releases don't trigger `publish.yml` workflow.\n\n```bash\n# Create GitHub Release (NOT draft)\ngh release create \"v$VERSION\" \\\n  --title \"v$VERSION\" \\\n  --notes \"Release notes go here\" \\\n  --latest\n\n# Verify release is PUBLISHED (not draft)\ngh release view \"v$VERSION\"\n# Output should NOT contain \"(draft)\"\n```\n\n**If output contains `(draft)`:** STOP. Delete the release and recreate without `--draft` flag.\n\n```bash\n# If you accidentally created a draft, fix it:\ngh release edit \"v$VERSION\" --draft=false\n```\n\n**Checkpoint:** Release is published (NOT draft). The `release: published` event fired and triggered `publish.yml`.\n\n### Step 4: Monitor Workflow\n\nThe `publish.yml` workflow should start automatically within 10 seconds of release creation.\n\n```bash\n# Watch workflow runs\ngh run list --workflow=publish.yml --limit 1\n\n# Get detailed status\ngh run view --log\n```\n\n**Expected flow:**\n1. `publish-sdk` job runs → publishes `@bradygaster\u002Fsquad-sdk`\n2. Verify step runs with retry loop (up to 5 attempts, 15s interval) to confirm SDK on npm registry\n3. `publish-cli` job runs → publishes `@bradygaster\u002Fsquad-cli`\n4. Verify step runs with retry loop to confirm CLI on npm registry\n\n**If workflow fails:** Check the logs. Common issues:\n- EOTP error = wrong NPM_TOKEN type (use Automation token)\n- Verify step timeout = npm propagation delay (retry loop should handle this, but propagation can take up to 2 minutes in rare cases)\n- Version mismatch = package.json version doesn't match tag\n\n**Checkpoint:** Both jobs succeeded. Workflow shows green checkmarks.\n\n### Step 5: Verify npm Publication\n\nManually verify both packages are on npm with correct `latest` dist-tag.\n\n```bash\n# Check SDK\nnpm view @bradygaster\u002Fsquad-sdk version\n# Output: 0.8.22\n\nnpm dist-tag ls @bradygaster\u002Fsquad-sdk\n# Output should show: latest: 0.8.22\n\n# Check CLI\nnpm view @bradygaster\u002Fsquad-cli version\n# Output: 0.8.22\n\nnpm dist-tag ls @bradygaster\u002Fsquad-cli\n# Output should show: latest: 0.8.22\n```\n\n**If versions don't match:** Something went wrong. Check workflow logs. DO NOT proceed with GitHub Release announcement until npm is correct.\n\n**Checkpoint:** Both packages show correct version. `latest` dist-tags point to the new version.\n\n### Step 6: Test Installation\n\nVerify packages can be installed from npm (real-world smoke test).\n\n```bash\n# Create temp directory\nmkdir \u002Ftmp\u002Fsquad-release-test && cd \u002Ftmp\u002Fsquad-release-test\n\n# Test SDK installation\nnpm init -y\nnpm install @bradygaster\u002Fsquad-sdk\nnode -p \"require('@bradygaster\u002Fsquad-sdk\u002Fpackage.json').version\"\n# Output: 0.8.22\n\n# Test CLI installation\nnpm install -g @bradygaster\u002Fsquad-cli\nsquad --version\n# Output: 0.8.22\n\n# Cleanup\ncd -\nrm -rf \u002Ftmp\u002Fsquad-release-test\n```\n\n**If installation fails:** npm registry issue or package metadata corruption. DO NOT announce release until this works.\n\n**Checkpoint:** Both packages install cleanly. Versions match.\n\n### Step 7: Sync dev to Next Preview\n\nAfter main release, sync dev to the next preview version.\n\n```bash\n# Checkout dev\ngit checkout dev\ngit pull origin dev\n\n# Bump to next preview version (e.g., 0.8.23-preview.1)\nNEXT_VERSION=\"0.8.23-preview.1\"\n\n# Validate semver\nnode -p \"require('semver').valid('$NEXT_VERSION')\"\n# Must output the version string, NOT null\n\n# Update all 3 package.json files\nnpm version $NEXT_VERSION --workspaces --include-workspace-root --no-git-tag-version\n\n# Commit\ngit add package.json packages\u002Fsquad-sdk\u002Fpackage.json packages\u002Fsquad-cli\u002Fpackage.json\ngit commit -m \"chore: bump dev to $NEXT_VERSION\n\nCo-authored-by: Copilot \u003C223556219+Copilot@users.noreply.github.com>\"\n\n# Push\ngit push origin dev\n```\n\n**Checkpoint:** dev branch now shows next preview version. Future dev builds will publish to `@preview` dist-tag.\n\n---\n\n## Manual Publish (Fallback)\n\nIf `publish.yml` workflow fails or needs to be bypassed, use `workflow_dispatch` to manually trigger publish.\n\n```bash\n# Trigger manual publish\ngh workflow run publish.yml -f version=\"0.8.22\"\n\n# Monitor the run\ngh run watch\n```\n\n**Rule:** Only use this if automated publish failed. Always investigate why automation failed and fix it for next release.\n\n---\n\n## Rollback Procedure\n\nIf a release is broken and needs to be rolled back:\n\n### 1. Unpublish from npm (Nuclear Option)\n\n**WARNING:** npm unpublish is time-limited (24 hours) and leaves the version slot burned. Only use if version is critically broken.\n\n```bash\n# Unpublish (requires npm owner privileges)\nnpm unpublish @bradygaster\u002Fsquad-sdk@0.8.22\nnpm unpublish @bradygaster\u002Fsquad-cli@0.8.22\n```\n\n### 2. Deprecate on npm (Preferred)\n\n**Preferred approach:** Mark version as deprecated, publish a hotfix.\n\n```bash\n# Deprecate broken version\nnpm deprecate @bradygaster\u002Fsquad-sdk@0.8.22 \"Broken release, use 0.8.22.1 instead\"\nnpm deprecate @bradygaster\u002Fsquad-cli@0.8.22 \"Broken release, use 0.8.22.1 instead\"\n\n# Publish hotfix version\n# (Follow this runbook with version 0.8.22.1)\n```\n\n### 3. Delete GitHub Release and Tag\n\n```bash\n# Delete GitHub Release\ngh release delete \"v0.8.22\" --yes\n\n# Delete tag locally and remotely\ngit tag -d \"v0.8.22\"\ngit push origin --delete \"v0.8.22\"\n```\n\n### 4. Revert Commit on main\n\n```bash\n# Revert version bump commit\ngit checkout main\ngit revert HEAD\ngit push origin main\n```\n\n**Checkpoint:** Tag and release deleted. main branch reverted. npm packages deprecated or unpublished.\n\n---\n\n## Common Failure Modes\n\n### EOTP Error (npm OTP Required)\n\n**Symptom:** Workflow fails with `EOTP` error.  \n**Root cause:** NPM_TOKEN is a User token with 2FA enabled. CI can't provide OTP.  \n**Fix:** Replace NPM_TOKEN with an Automation token (no 2FA). See \"NPM_TOKEN Verification\" above.\n\n### Verify Step 404 (npm Propagation Delay)\n\n**Symptom:** Verify step fails with 404 even though publish succeeded.  \n**Root cause:** npm registry propagation delay (5-30 seconds).  \n**Fix:** Verify step now has retry loop (5 attempts, 15s interval). Should auto-resolve. If not, wait 2 minutes and re-run workflow.\n\n### Version Mismatch (package.json ≠ tag)\n\n**Symptom:** Verify step fails with \"Package version (X) does not match target version (Y)\".  \n**Root cause:** package.json version doesn't match the tag version.  \n**Fix:** Ensure all 3 package.json files were updated in Step 1. Re-run `npm version` if needed.\n\n### 4-Part Version Mangled by npm\n\n**Symptom:** Published version on npm doesn't match package.json (e.g., 0.8.21.4 became 0.8.2-1.4).  \n**Root cause:** 4-part versions are NOT valid semver. npm's parser misinterprets them.  \n**Fix:** NEVER use 4-part versions. Only 3-part (0.8.22) or prerelease (0.8.23-preview.1). Run `semver.valid()` before ANY commit.\n\n### Draft Release Didn't Trigger Workflow\n\n**Symptom:** Release created but `publish.yml` never ran.  \n**Root cause:** Release was created as a draft. Draft releases don't emit `release: published` event.  \n**Fix:** Edit release and change to published: `gh release edit \"v$VERSION\" --draft=false`. Workflow should trigger immediately.\n\n---\n\n## Validation Checklist\n\nBefore starting ANY release, confirm:\n\n- [ ] Version is valid semver: `node -p \"require('semver').valid('VERSION')\"` returns the version string (NOT null)\n- [ ] NPM_TOKEN is an Automation token (no 2FA): `npm token list` shows `read-write` without OTP requirement\n- [ ] Branch is clean: `git status` shows \"nothing to commit, working tree clean\"\n- [ ] Tag doesn't exist: `git tag -l \"vVERSION\"` returns empty\n- [ ] `SKIP_BUILD_BUMP=1` is set: `echo $SKIP_BUILD_BUMP` returns `1`\n\nBefore creating GitHub Release:\n\n- [ ] All 3 package.json files have matching versions: `grep '\"version\"' package.json packages\u002F*\u002Fpackage.json`\n- [ ] Commit is pushed: `git log origin\u002Fmain..main` returns empty\n- [ ] Tag is pushed: `git ls-remote --tags origin vVERSION` returns the tag SHA\n\nAfter GitHub Release:\n\n- [ ] Release is published (NOT draft): `gh release view \"vVERSION\"` output doesn't contain \"(draft)\"\n- [ ] Workflow is running: `gh run list --workflow=publish.yml --limit 1` shows \"in_progress\"\n\nAfter workflow completes:\n\n- [ ] Both jobs succeeded: Workflow shows green checkmarks\n- [ ] SDK on npm: `npm view @bradygaster\u002Fsquad-sdk version` returns correct version\n- [ ] CLI on npm: `npm view @bradygaster\u002Fsquad-cli version` returns correct version\n- [ ] `latest` tags correct: `npm dist-tag ls @bradygaster\u002Fsquad-sdk` shows `latest: VERSION`\n- [ ] Packages install: `npm install @bradygaster\u002Fsquad-cli` succeeds\n\nAfter dev sync:\n\n- [ ] dev branch has next preview version: `git show dev:package.json | grep version` shows next preview\n\n---\n\n## Post-Mortem Reference\n\nThis skill was created after the v0.8.22 release disaster. Full retrospective: `.squad\u002Fdecisions\u002Finbox\u002Fkeaton-v0822-retrospective.md`\n\n**Key learnings:**\n1. No release without a runbook = improvisation = disaster\n2. Semver validation is mandatory — 4-part versions break npm\n3. NPM_TOKEN type matters — User tokens with 2FA fail in CI\n4. Draft releases are a footgun — they don't trigger automation\n5. Retry logic is essential — npm propagation takes time\n\n**Never again.**\n",{"name":5,"domain":36,"source":37,"confidence":29,"description":7},"release-management","team-decision","dev","ec19f5e92325e634e3c6eff500e3cefa56131cc9",".copilot\u002Fskills\u002Frelease-process","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad","https:\u002F\u002Fgithub.com\u002Fbarichter","2026-04-13 22:53:46",{"source":8,"skillName":5,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add barichter\u002Fsquad --skill release-process",{"tool":50,"command":51},"bunx","bunx skills add barichter\u002Fsquad --skill release-process",{"tool":53,"command":54},"pnpm","pnpm dlx skills add barichter\u002Fsquad --skill release-process","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002F.copilot\u002Fskills\u002Frelease-process\u002FSKILL.md",true,[],[59,75,83,98,120,126],{"skillNo":60,"name":61,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":69,"publishedAt":31},"01M6R7VE8SZD1E37WWJN4ZFPWB","My Skill","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fmy-skill\u002FSKILL.md",[64],{"categoryNo":65,"categoryName":66,"taxonomyType":67,"taxonomyTypeDesc":68},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[70,71,72,73,74],"my","my skill","tester","vitest","testing",{"skillNo":76,"name":77,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":31},"01M6R7VD19M4TMAA74XGD6QSZX","bad-skill","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fbad-skill\u002FSKILL.md",[],[81,82],"bad skill","bad",{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":31},"01M6R7V9TYTX6Z621V6RWA51G6","squad-conventions","Core conventions and patterns used in the Squad codebase","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fsquad-conventions\u002FSKILL.md",[],[90,21,91,92,93,94,95,96,29,97],"squad conventions","conventions","project-conventions","core","patterns","project","manual","codebase",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":31},"01M6R7TTF0ABMGSVWASVYF6D51","rework-rate","Measure and interpret PR rework rate — the emerging 5th DORA metric","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Frework-rate\u002FSKILL.md",[],[105,106,107,108,109,110,111,112,113,29,21,114,115,116,117,22,118,119,96],"rate","rework rate","metric","efficiency","prs","when","pr","review","code quality","code","code-review","metrics","health","analyze","quality",{"skillNo":121,"name":122,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":31},"01M6R7TRZPET44JRCSQF08EEA8","nap","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fnap\u002FSKILL.md",[],[122],{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":133,"publishedAt":31},"01M6R7TK10WCT77A52E27GR5R3","{skill-name}","{what this skill teaches agents}","https:\u002F\u002Fgithub.com\u002Fbarichter\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskill.md",[132],{"categoryNo":65,"categoryName":66,"taxonomyType":67,"taxonomyTypeDesc":68},[134,135,136,137,138,139,140,141,142,143,96,29,74],"{skill name}","skill name","name","design","api","how","error-handling","learned","error","api-design"]