[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6X1WNKH1S7DZJXMFSZTCRND":3,"skill-same:01M6X1WNKH1S7DZJXMFSZTCRND":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":49,"ownerHtmlUrl":50,"ownerBlogUrl":51,"ownerDescription":52,"updatedAt":53,"install":54,"resources":67},"01M6X1WNKH1S7DZJXMFSZTCRND","ci-validation-gates",null,"Defensive CI\u002FCD patterns: semver validation, token checks, retry logic, and draft detection","github\u002Fsquad","github","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F9919?v=4","01M6AC83DS133TPXFSP1DHNCC6","GitHub","01M6X0MZ6B0WYMMDPK3Q61KER6",3382,"MIT","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fci-validation-gates\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"validation","ci","ci validation gates","gates","draft","lessons","high","retry","CI\u002FCD","defensive","cd","logic","token","incident","patterns","detection","ci-cd","semver","release","2026-11-10 10:12:30",false,"---\nname: \"ci-validation-gates\"\ndescription: \"Defensive CI\u002FCD patterns: semver validation, token checks, retry logic, and draft detection\"\ndomain: \"ci-cd\"\nconfidence: \"high\"\nsource: \"extracted from release and CI incident lessons\"\n---\n\n## Context\n\nCI workflows must be defensive. These patterns capture lessons from prior release incidents;\nthey are maintained as version-agnostic gates rather than claims about a particular repository\nrelease.\n\n## Patterns\n\n### Semver Validation Gate\nEvery publish workflow MUST validate version format before `npm publish`. 4-part versions (e.g., 0.8.21.4) are NOT valid semver — npm mangles them.\n\n```yaml\n- name: Validate semver\n  run: |\n    VERSION=\"${{ github.event.release.tag_name }}\"\n    VERSION=\"${VERSION#v}\"\n    if ! npx semver \"$VERSION\" > \u002Fdev\u002Fnull 2>&1; then\n      echo \"❌ Invalid semver: $VERSION\"\n      echo \"Only 3-part versions (X.Y.Z) or prerelease (X.Y.Z-tag.N) are valid.\"\n      exit 1\n    fi\n    echo \"✅ Valid semver: $VERSION\"\n```\n\n### NPM Token Type Verification\nNPM_TOKEN MUST be an Automation token, not a User token with 2FA:\n- User tokens require OTP — CI can't provide it → EOTP error\n- Create Automation tokens at npmjs.com → Settings → Access Tokens → Automation\n- Verify before first publish in any workflow\n\n### Retry Logic for npm Registry Propagation\nnpm registry uses eventual consistency. After `npm publish` succeeds, the package may not be immediately queryable.\n- Propagation: typically 5-30s, up to 2min in rare cases\n- All verify steps: 5 attempts, 15-second intervals\n- Log each attempt: \"Attempt 1\u002F5: Checking package...\"\n- Exit loop on success, fail after max attempts\n\n```yaml\n- name: Verify package (with retry)\n  run: |\n    MAX_ATTEMPTS=5\n    WAIT_SECONDS=15\n    for attempt in $(seq 1 $MAX_ATTEMPTS); do\n      echo \"Attempt $attempt\u002F$MAX_ATTEMPTS: Checking $PACKAGE@$VERSION...\"\n      if npm view \"$PACKAGE@$VERSION\" version > \u002Fdev\u002Fnull 2>&1; then\n        echo \"✅ Package verified\"\n        exit 0\n      fi\n      [ $attempt -lt $MAX_ATTEMPTS ] && sleep $WAIT_SECONDS\n    done\n    echo \"❌ Failed to verify after $MAX_ATTEMPTS attempts\"\n    exit 1\n```\n\n### Draft Release Detection\nDraft releases don't emit `release: published` event. Workflows MUST:\n- Trigger on `release: published` (NOT `created`)\n- If using workflow_dispatch: verify release is published via GitHub API before proceeding\n\n### Installer and Generated-Artifact Gates\n\n- Pin downloaded scripts and binaries to an immutable release or commit; never execute a moving\n  branch reference.\n- Use `curl -f` (normally `curl -fsSL`) so HTTP failures cannot be interpreted as scripts.\n- Download to a named file before execution when practical, then remove it after a successful\n  install. This leaves a diagnosable artifact if the installer fails.\n- Use `set -euo pipefail` in Bash steps. When a download must feed an extractor, `pipefail`\n  prevents the extractor from masking a failed download.\n- Lint and validate canonical workflow sources and every committed generated\u002Ftemplate mirror.\n  A successful source-only check does not prove the artifact that executes is valid.\n- Keep suppressions narrow: exact tool diagnostic plus exact affected path, and revalidate them\n  when the pinned tool changes.\n\nThe root build invokes `scripts\u002Fbump-build.mjs`, which can mutate package versions. For local\nroot validation, run `SKIP_BUILD_BUMP=1 npm run build`; do not run a bare `npm run build`.\nAlternatively, use an existing CI environment that guarantees no mutation. In either case,\nMUST verify the package manifests and lockfile are unchanged afterward. Prefer an affected\nworkspace build when it covers the check. Never let a validation build rewrite package\nversions or create a version-only diff.\n\n## Known Failure Modes\n\n| # | What Happened | Root Cause | Prevention |\n|---|---------------|-----------|------------|\n| 1 | Invalid version published, registry mangled it | No semver validation gate | `npx semver` check before every publish |\n| 2 | CI failed 5+ times with EOTP | User token with 2FA | Automation token only |\n| 3 | Verify returned false 404 | No retry logic for propagation | 5 attempts, 15s intervals |\n| 4 | Workflow never triggered | Draft release doesn't emit event | Never create draft releases |\n\n## Anti-Patterns\n- ❌ Publishing without semver validation gate\n- ❌ Single-shot verification without retry\n- ❌ Hard-coded secrets in workflows\n- ❌ Silent CI failures — every error needs actionable output with remediation\n- ❌ Assuming npm publish is instantly queryable\n","## Context\n\nCI workflows must be defensive. These patterns capture lessons from prior release incidents;\nthey are maintained as version-agnostic gates rather than claims about a particular repository\nrelease.\n\n## Patterns\n\n### Semver Validation Gate\nEvery publish workflow MUST validate version format before `npm publish`. 4-part versions (e.g., 0.8.21.4) are NOT valid semver — npm mangles them.\n\n```yaml\n- name: Validate semver\n  run: |\n    VERSION=\"${{ github.event.release.tag_name }}\"\n    VERSION=\"${VERSION#v}\"\n    if ! npx semver \"$VERSION\" > \u002Fdev\u002Fnull 2>&1; then\n      echo \"❌ Invalid semver: $VERSION\"\n      echo \"Only 3-part versions (X.Y.Z) or prerelease (X.Y.Z-tag.N) are valid.\"\n      exit 1\n    fi\n    echo \"✅ Valid semver: $VERSION\"\n```\n\n### NPM Token Type Verification\nNPM_TOKEN MUST be an Automation token, not a User token with 2FA:\n- User tokens require OTP — CI can't provide it → EOTP error\n- Create Automation tokens at npmjs.com → Settings → Access Tokens → Automation\n- Verify before first publish in any workflow\n\n### Retry Logic for npm Registry Propagation\nnpm registry uses eventual consistency. After `npm publish` succeeds, the package may not be immediately queryable.\n- Propagation: typically 5-30s, up to 2min in rare cases\n- All verify steps: 5 attempts, 15-second intervals\n- Log each attempt: \"Attempt 1\u002F5: Checking package...\"\n- Exit loop on success, fail after max attempts\n\n```yaml\n- name: Verify package (with retry)\n  run: |\n    MAX_ATTEMPTS=5\n    WAIT_SECONDS=15\n    for attempt in $(seq 1 $MAX_ATTEMPTS); do\n      echo \"Attempt $attempt\u002F$MAX_ATTEMPTS: Checking $PACKAGE@$VERSION...\"\n      if npm view \"$PACKAGE@$VERSION\" version > \u002Fdev\u002Fnull 2>&1; then\n        echo \"✅ Package verified\"\n        exit 0\n      fi\n      [ $attempt -lt $MAX_ATTEMPTS ] && sleep $WAIT_SECONDS\n    done\n    echo \"❌ Failed to verify after $MAX_ATTEMPTS attempts\"\n    exit 1\n```\n\n### Draft Release Detection\nDraft releases don't emit `release: published` event. Workflows MUST:\n- Trigger on `release: published` (NOT `created`)\n- If using workflow_dispatch: verify release is published via GitHub API before proceeding\n\n### Installer and Generated-Artifact Gates\n\n- Pin downloaded scripts and binaries to an immutable release or commit; never execute a moving\n  branch reference.\n- Use `curl -f` (normally `curl -fsSL`) so HTTP failures cannot be interpreted as scripts.\n- Download to a named file before execution when practical, then remove it after a successful\n  install. This leaves a diagnosable artifact if the installer fails.\n- Use `set -euo pipefail` in Bash steps. When a download must feed an extractor, `pipefail`\n  prevents the extractor from masking a failed download.\n- Lint and validate canonical workflow sources and every committed generated\u002Ftemplate mirror.\n  A successful source-only check does not prove the artifact that executes is valid.\n- Keep suppressions narrow: exact tool diagnostic plus exact affected path, and revalidate them\n  when the pinned tool changes.\n\nThe root build invokes `scripts\u002Fbump-build.mjs`, which can mutate package versions. For local\nroot validation, run `SKIP_BUILD_BUMP=1 npm run build`; do not run a bare `npm run build`.\nAlternatively, use an existing CI environment that guarantees no mutation. In either case,\nMUST verify the package manifests and lockfile are unchanged afterward. Prefer an affected\nworkspace build when it covers the check. Never let a validation build rewrite package\nversions or create a version-only diff.\n\n## Known Failure Modes\n\n| # | What Happened | Root Cause | Prevention |\n|---|---------------|-----------|------------|\n| 1 | Invalid version published, registry mangled it | No semver validation gate | `npx semver` check before every publish |\n| 2 | CI failed 5+ times with EOTP | User token with 2FA | Automation token only |\n| 3 | Verify returned false 404 | No retry logic for propagation | 5 attempts, 15s intervals |\n| 4 | Workflow never triggered | Draft release doesn't emit event | Never create draft releases |\n\n## Anti-Patterns\n- ❌ Publishing without semver validation gate\n- ❌ Single-shot verification without retry\n- ❌ Hard-coded secrets in workflows\n- ❌ Silent CI failures — every error needs actionable output with remediation\n- ❌ Assuming npm publish is instantly queryable\n",{"name":5,"domain":35,"source":43,"confidence":25,"description":7},"extracted from release and CI incident lessons","dev","7b731ec97f35346bdc4fa87c3edaf16b808fc0ae","templates\u002Fskills\u002Fci-validation-gates",518,"https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad","https:\u002F\u002Fgithub.github.io\u002Fsquad\u002F","https:\u002F\u002Fgithub.com\u002Fgithub","https:\u002F\u002Fgithub.com\u002Fabout","How people build software.","2026-11-13 01:58:30",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add github\u002Fsquad --skill ci-validation-gates",{"tool":60,"command":61},"bunx","bunx skills add github\u002Fsquad --skill ci-validation-gates",{"tool":63,"command":64},"pnpm","pnpm dlx skills add github\u002Fsquad --skill ci-validation-gates","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fci-validation-gates\u002FSKILL.md",true,[],[69,77,84,91,122,134],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":76},"01M76742ST8ZMSD38226TH61CN","squad-coordinator-init-mode","Squad coordinator only: Init Mode, proposing and casting a new team. Load when team.md is missing or has an empty roster, or when asked to set up or cast a team.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fsquad-coordinator-init-mode\u002FSKILL.md",[],[],"2026-11-12 13:55:43",{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":76},"01M7673KYSME979M20YQTVV8P6","retro-enforcement","Keep retrospectives on schedule and track their action items as GitHub Issues, not markdown checklists","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fretro-enforcement\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":76},"01M7670QCHBSR4W2XSX8XPA2ZB","cli-wiring","Checklist for wiring a new Squad CLI command: route it in cli-entry.ts, add help text, and test that it is reachable","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fcli-wiring\u002FSKILL.md",[],[],{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":102,"publishedAt":38},"01M6X287DVJK1S91END9DSHETN","gh-aw-enlistment","Enlist a repository into Squad by installing the supported GitHub Agentic Workflows (gh-aw) bootstrap — with strict compilation, an explicit safe-update allowlist, and a human-reviewed bootstrap PR. Never auto-merges.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fworkflows\u002Fskills\u002Fgh-aw-enlistment\u002FSKILL.md",[97],{"categoryNo":98,"categoryName":99,"taxonomyType":100,"taxonomyTypeDesc":101},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,20,121],"gh aw enlistment","gh","preflight","guide","identity","compiling","squad","pr creation","Safety","safe","update","human","github cli","lock","workflows","auto","files","agentic workflows","actions",{"skillNo":123,"name":124,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":128,"publishedAt":38},"01M6X27Y5119CSRQFFJCV6432R","My Skill","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fmy-skill\u002FSKILL.md",[127],{"categoryNo":98,"categoryName":99,"taxonomyType":100,"taxonomyTypeDesc":101},[129,130,131,132,133],"my","my skill","tester","testing","vitest",{"skillNo":135,"name":136,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":140,"publishedAt":38},"01M6X27RWAYB2X9ER0MVRRKXGA","bad-skill","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fbad-skill\u002FSKILL.md",[139],{"categoryNo":98,"categoryName":99,"taxonomyType":100,"taxonomyTypeDesc":101},[141,142],"bad","bad skill"]