[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7234CW09V2C87Q39S0X9XY6":3,"skill-same:01M7234CW09V2C87Q39S0X9XY6":49},{"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":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":14,"repositoryHtmlUrl":30,"repositoryHomepageUrl":31,"ownerHtmlUrl":32,"ownerBlogUrl":33,"ownerDescription":34,"updatedAt":35,"install":36,"resources":48},"01M7234CW09V2C87Q39S0X9XY6","skills-release",null,"Use when the user wants to release staging to main. Initializes an ops Governor,\ncalls rks_release (which handles pre-flight checks, ff-merge, tagging, and push).\n$ARGUMENTS can be: patch (default), minor, or major.","ux287\u002Froutekit-shell","ux287","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F3310101?v=4","01M72337JWFBKTK9B0NG4XT1TJ","Vince Mease","01M72337KGT2F0XVBRNJ61A9EK",1,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002Fux287\u002Froutekit-shell\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frelease\u002FSKILL.md",[],[],"2026-11-10 18:39:20",false,"---\nname: skills-release\ndescription: |\n  Use when the user wants to release staging to main. Initializes an ops Governor,\n  calls rks_release (which handles pre-flight checks, ff-merge, tagging, and push).\n  $ARGUMENTS can be: patch (default), minor, or major.\nuser-invocable: true\ndisable-model-invocation: false\nverbosity: heartbeat\n---\n\n# Release Skill\n\nThis skill releases staging to main via `rks_release` under an ops Governor session.\n\n## Purpose\n\nProvides a deterministic release flow:\n1. Initialize ops Governor for token\n2. Write the release notes from the released stories\n3. Call `rks_release` (pre-flight checks + version bump + ff-merge to main + tag + push)\n4. End the Governor session\n5. Report result\n\n## Instructions\n\n### Step 1: Parse arguments\n\nParse `$ARGUMENTS` for the version bump type:\n- `patch` (default if no argument) — **fixing broken behavior** (a bug fix)\n- `minor` — **new or changed intended behavior** (a feature or a deliberate behavior change)\n- `major` — reserved for `1.0` \u002F breaking changes\n\nIf `$ARGUMENTS` is empty or not one of the above, default to `patch`.\n\nWhich to pick (the versioning policy — see the \"Versioning\" section in `README.md`): the intent axis decides, not the surface size. Sharpening test — **changing or adding intended behavior is a minor; fixing broken behavior is a patch.** `rks_release` bumps the root + `packages\u002Fmcp-rks` + `packages\u002Fcli` `package.json` versions in lockstep, so they never drift.\n\n### Step 2: Initialize Governor\n\nCall:\n\n```\nmcp__rks__rks_governor_init({\n  projectId: 'routekit-shell',\n  flowType: 'ops'\n})\n```\n\nStore the returned `token`.\n\n### Step 2b: Write the release notes\n\nRelease notes are required, and they must account for every story the release transitions.\nStart with a dry run, which changes nothing:\n\n```\nmcp__rks__rks_release({\n  projectId: 'routekit-shell',\n  version: '\u003Cparsed version bump>',\n  dryRun: true,\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\n1. Take `notesBrief` from the dry-run result. It is the exact list to write from: the stories this\n   release transitions, grouped `Added`, `Changed`, `Fixed`, `Internal` in that order and sorted\n   within each group. Each item carries its `storyId` (for coverage only, never for the text), its\n   `title` and `desc`, and `leaks`: every story id and denylisted term in that title or desc.\n2. Hand `notesBrief`, unchanged, to a writing agent with this instruction: \"Write one user-facing\n   bullet per item, under its group's `### \u003CGroup>` heading, in the given order, written\n   from the released stories, never from commit subjects. Rephrase every `leaks` entry so no story id or\n   denylisted term survives. Return `changelog`, `notesCoverage` (each storyId mapped to the exact\n   phrase of the bullet that covers it) and `notesExclusions` (a story with no user-facing change,\n   with a reason).\" `notesDraft` and `coverageDraft` are a mechanical starting point the agent may\n   keep or improve.\n3. Call `rks_release` again with `dryRun: true`, `changelog`, `notesCoverage` and\n   `notesExclusions`. Proceed only when every `coverage` list is empty: `unknownStories`,\n   `unaccountedStories`, `phrasesNotFound`, `storyIdLeaks` and `deniedTerms`. Otherwise send the\n   findings back to the writing agent and dry-run again.\n4. Show the lines, the mapping and the exclusions to the user before the real call.\n5. Pass the text as `changelog`, and the mapping and exclusions as `notesCoverage` and\n   `notesExclusions`, in Step 3. `rks_release` writes the text verbatim (trimmed) to\n   `CHANGELOG.md` and to both GitHub Release bodies; the mapping and exclusions are not published.\n\nThe denylist is configured, never written in code: `releaseNotes.denylist` in the project's\n`.rks\u002Fproject.json`, or the machine-local `RKS_RELEASE_NOTES_DENYLIST` (comma-separated, in the\nenvironment or the project's gitignored `.env`) for a term that must never be committed.\n\nA fresh release refuses before anything is changed when a story is neither covered nor excluded,\nor a mapped phrase does not occur in `changelog` (`reason: 'release_notes_incomplete'`, with\n`unaccountedStories` and `phrasesNotFound`); when `notesCoverage` is malformed, names a story the\nrelease does not transition, or names a story also excluded (`reason: 'notes_coverage_invalid'`);\nor when `notesExclusions` is malformed or names a story the release does not transition\n(`reason: 'notes_exclusions_invalid'`). It also refuses published text (the `changelog`, or an\napplied `notesOverride` reason) that contains a story id (`reason: 'release_notes_story_id'`) or a\ndenylisted term in any letter case (`reason: 'release_notes_denied_term'`, identified by source,\nentry and line, never by the term), and a denylist it cannot read or parse\n(`reason: 'release_notes_denylist_invalid'`).\n\n`rks_release` has no git-log fallback. A fresh release with no usable `changelog` (absent,\nempty or whitespace-only) is refused with `reason: 'release_notes_missing'` before anything is\nchanged. The only way to release without notes is `notesOverride: { enabled: true, reason: '...' }`,\nand it requires the user's explicit direction and a reason: never pass it on your own judgement.\nAn applied override writes `Release notes waived: \u003Creason>` and is recorded in the\n`release.complete` telemetry. An invalid override is refused with `reason: 'notes_override_invalid'`.\n\nA resumed release (staging HEAD is already the `chore(release): \u003Cversion>` bump commit) uses the\n`CHANGELOG.md` entry committed in that bump commit and ignores `changelog`, with a warning. If that\nentry is missing it is refused with `reason: 'release_notes_resume_entry_missing'`.\n\nReport every refusal reason verbatim.\n\n### Step 3: Release\n\nCall the MCP tool with the Governor token:\n\n```\nmcp__rks__rks_release({\n  projectId: 'routekit-shell',\n  version: '\u003Cparsed version bump>',\n  changelog: '\u003Cthe release notes written in Step 2b>',\n  notesCoverage: { '\u003CstoryId>': '\u003Cphrase copied from the notes>' },\n  notesExclusions: [],\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\nIf the projectId above is still an unsubstituted template token, resolve it from the projectId declared at the top of `CLAUDE.md`.\n\n`rks_release` handles all pre-flight checks internally:\n- Verifies clean working tree\n- Verifies current branch is staging\n- Verifies staging is in sync with origin\n- Verifies CI is green **for the commit being released** — and FAILS CLOSED if it cannot get a verdict.\n\n  This gate previously passed whenever it could not reach an answer. On 2026-08-17 a local\n  `gh` returning HTTP 404 caused it to be skipped entirely, and v0.39.0 was cut onto `main`\n  while staging CI was red. It now blocks on an unreachable `gh`, a timeout, unreadable\n  output, or no run at all — every one of those is a missing verdict, not a pass.\n\n  When the newest run's `headSha` is not the commit being released, the gate passes only if\n  BOTH: (a) that run is `completed` with conclusion `success`, AND (b) the diff\n  `\u003Crun headSha>..\u003Cintegration HEAD>` touches only paths `.github\u002Fworkflows\u002Fci.yml`\n  `paths-ignore`s. That is what makes an ordinary release work — staging HEAD is routinely a\n  notes-only commit which produces no CI run of its own, and that is normal, not a fault.\n  The range is anchored at the verified run's sha, never at `origin\u002F\u003Cproduction>` or a\n  release tag; both of those span real code on every release and would block everything,\n  including the resume path whose HEAD is the `[skip ci]` bump commit.\n\n### Overriding a blocking CI verdict\n\nIf CI genuinely cannot be reached — GitHub down, `gh` unauthenticated — the gate blocks and\nthat is correct. To release anyway, pass an override **with a reason**:\n\n```js\nmcp__rks__rks_release({\n  projectId: '\u003CprojectId>',\n  version: '\u003Cpatch|minor|major>',\n  changelog: '\u003Cthe release notes written in the write-the-release-notes step>',\n  notesCoverage: { '\u003CstoryId>': '\u003Cphrase copied from the notes>' },\n  enforcementOverride: { enabled: true, reason: 'why you are releasing without a CI verdict' },\n  _governorToken: '\u003Ctoken>',\n})\n```\n\n`enabled` must be literally `true` (it cannot default on) and `reason` must be non-empty —\nan override with a missing or blank reason is REJECTED, not quietly accepted. An applied\noverride is recorded in the `release.complete` telemetry as `ciGateOverridden` plus the\nreason, because an override that leaves no trace is indistinguishable from the fail-open\nthis gate exists to prevent. Supplying an override when the gate is *not* blocking does\nnothing and is not recorded.\n\n`enforcementOverride` waives only the CI gate. It does not waive release notes: a CI-overridden\nrelease still needs `changelog`, or a separate `notesOverride` on the user's explicit direction.\n\nIf any check fails, it returns `{ ok: false, error: '...' }` — report the error.\n\n### Step 3b: End the session\n\nAfter `rks_release` returns — on success AND on failure — end the ops session with the Step 2\ntoken. It is the last MCP call of this flow (backlog.feat.governor-session-end):\n\n```\nmcp__rks__rks_governor_end({\n  projectId: 'routekit-shell',\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\n`ended: false` with `reason: 'session_not_live'` is not an error. `end_blocked` is reported with\nits `blockedBy` and is not retried.\n\n### Step 4: Report result\n\nOn success, report:\n- New version and tag (e.g., `v0.19.5`)\n- Commit SHA\n- Number of stories transitioned to `released`\n- Remind the user to roll the release out to child projects — **two steps**:\n  1. Update the release mirror to the new tag (it's a checkout-only mirror, so `-f` safely discards local lockfile noise):\n     ```\n     cd ..\u002Froutekit-shell-release && git fetch origin --tags && git checkout -f v\u003Cnew-version>\n     ```\n  2. Upgrade **all** registered children **from the release** in one command (run from anywhere):\n     ```\n     routekit project upgrade --all --from-release ..\u002Froutekit-shell-release\n     ```\n     `--from-release` sources the release's hooks\u002Fskills\u002Fprompts\u002Fversion while still resolving children from your normal registry; it repins each child's `.mcp.json` and stamps its `rksVersion`. (For a single child: `routekit project upgrade --id \u003Cchild> --from-release ..\u002Froutekit-shell-release`.)\n  Then restart the MCP server in each child (snacks, concourse-prototype, etc.) to pick up the update.\n\nOn failure, report the error from `rks_release` and suggest diagnostics.\n\n## Notes\n\n- Uses ops flow Governor for token authorization\n- `rks_release` handles: version bump commit on staging, ff-merge main, tag on main, push\n- The tag is created on main after the ff-merge (not on staging)\n- Works for any registered project — replace the projectId above with the target projectId\n","# Release Skill\n\nThis skill releases staging to main via `rks_release` under an ops Governor session.\n\n## Purpose\n\nProvides a deterministic release flow:\n1. Initialize ops Governor for token\n2. Write the release notes from the released stories\n3. Call `rks_release` (pre-flight checks + version bump + ff-merge to main + tag + push)\n4. End the Governor session\n5. Report result\n\n## Instructions\n\n### Step 1: Parse arguments\n\nParse `$ARGUMENTS` for the version bump type:\n- `patch` (default if no argument) — **fixing broken behavior** (a bug fix)\n- `minor` — **new or changed intended behavior** (a feature or a deliberate behavior change)\n- `major` — reserved for `1.0` \u002F breaking changes\n\nIf `$ARGUMENTS` is empty or not one of the above, default to `patch`.\n\nWhich to pick (the versioning policy — see the \"Versioning\" section in `README.md`): the intent axis decides, not the surface size. Sharpening test — **changing or adding intended behavior is a minor; fixing broken behavior is a patch.** `rks_release` bumps the root + `packages\u002Fmcp-rks` + `packages\u002Fcli` `package.json` versions in lockstep, so they never drift.\n\n### Step 2: Initialize Governor\n\nCall:\n\n```\nmcp__rks__rks_governor_init({\n  projectId: 'routekit-shell',\n  flowType: 'ops'\n})\n```\n\nStore the returned `token`.\n\n### Step 2b: Write the release notes\n\nRelease notes are required, and they must account for every story the release transitions.\nStart with a dry run, which changes nothing:\n\n```\nmcp__rks__rks_release({\n  projectId: 'routekit-shell',\n  version: '\u003Cparsed version bump>',\n  dryRun: true,\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\n1. Take `notesBrief` from the dry-run result. It is the exact list to write from: the stories this\n   release transitions, grouped `Added`, `Changed`, `Fixed`, `Internal` in that order and sorted\n   within each group. Each item carries its `storyId` (for coverage only, never for the text), its\n   `title` and `desc`, and `leaks`: every story id and denylisted term in that title or desc.\n2. Hand `notesBrief`, unchanged, to a writing agent with this instruction: \"Write one user-facing\n   bullet per item, under its group's `### \u003CGroup>` heading, in the given order, written\n   from the released stories, never from commit subjects. Rephrase every `leaks` entry so no story id or\n   denylisted term survives. Return `changelog`, `notesCoverage` (each storyId mapped to the exact\n   phrase of the bullet that covers it) and `notesExclusions` (a story with no user-facing change,\n   with a reason).\" `notesDraft` and `coverageDraft` are a mechanical starting point the agent may\n   keep or improve.\n3. Call `rks_release` again with `dryRun: true`, `changelog`, `notesCoverage` and\n   `notesExclusions`. Proceed only when every `coverage` list is empty: `unknownStories`,\n   `unaccountedStories`, `phrasesNotFound`, `storyIdLeaks` and `deniedTerms`. Otherwise send the\n   findings back to the writing agent and dry-run again.\n4. Show the lines, the mapping and the exclusions to the user before the real call.\n5. Pass the text as `changelog`, and the mapping and exclusions as `notesCoverage` and\n   `notesExclusions`, in Step 3. `rks_release` writes the text verbatim (trimmed) to\n   `CHANGELOG.md` and to both GitHub Release bodies; the mapping and exclusions are not published.\n\nThe denylist is configured, never written in code: `releaseNotes.denylist` in the project's\n`.rks\u002Fproject.json`, or the machine-local `RKS_RELEASE_NOTES_DENYLIST` (comma-separated, in the\nenvironment or the project's gitignored `.env`) for a term that must never be committed.\n\nA fresh release refuses before anything is changed when a story is neither covered nor excluded,\nor a mapped phrase does not occur in `changelog` (`reason: 'release_notes_incomplete'`, with\n`unaccountedStories` and `phrasesNotFound`); when `notesCoverage` is malformed, names a story the\nrelease does not transition, or names a story also excluded (`reason: 'notes_coverage_invalid'`);\nor when `notesExclusions` is malformed or names a story the release does not transition\n(`reason: 'notes_exclusions_invalid'`). It also refuses published text (the `changelog`, or an\napplied `notesOverride` reason) that contains a story id (`reason: 'release_notes_story_id'`) or a\ndenylisted term in any letter case (`reason: 'release_notes_denied_term'`, identified by source,\nentry and line, never by the term), and a denylist it cannot read or parse\n(`reason: 'release_notes_denylist_invalid'`).\n\n`rks_release` has no git-log fallback. A fresh release with no usable `changelog` (absent,\nempty or whitespace-only) is refused with `reason: 'release_notes_missing'` before anything is\nchanged. The only way to release without notes is `notesOverride: { enabled: true, reason: '...' }`,\nand it requires the user's explicit direction and a reason: never pass it on your own judgement.\nAn applied override writes `Release notes waived: \u003Creason>` and is recorded in the\n`release.complete` telemetry. An invalid override is refused with `reason: 'notes_override_invalid'`.\n\nA resumed release (staging HEAD is already the `chore(release): \u003Cversion>` bump commit) uses the\n`CHANGELOG.md` entry committed in that bump commit and ignores `changelog`, with a warning. If that\nentry is missing it is refused with `reason: 'release_notes_resume_entry_missing'`.\n\nReport every refusal reason verbatim.\n\n### Step 3: Release\n\nCall the MCP tool with the Governor token:\n\n```\nmcp__rks__rks_release({\n  projectId: 'routekit-shell',\n  version: '\u003Cparsed version bump>',\n  changelog: '\u003Cthe release notes written in Step 2b>',\n  notesCoverage: { '\u003CstoryId>': '\u003Cphrase copied from the notes>' },\n  notesExclusions: [],\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\nIf the projectId above is still an unsubstituted template token, resolve it from the projectId declared at the top of `CLAUDE.md`.\n\n`rks_release` handles all pre-flight checks internally:\n- Verifies clean working tree\n- Verifies current branch is staging\n- Verifies staging is in sync with origin\n- Verifies CI is green **for the commit being released** — and FAILS CLOSED if it cannot get a verdict.\n\n  This gate previously passed whenever it could not reach an answer. On 2026-08-17 a local\n  `gh` returning HTTP 404 caused it to be skipped entirely, and v0.39.0 was cut onto `main`\n  while staging CI was red. It now blocks on an unreachable `gh`, a timeout, unreadable\n  output, or no run at all — every one of those is a missing verdict, not a pass.\n\n  When the newest run's `headSha` is not the commit being released, the gate passes only if\n  BOTH: (a) that run is `completed` with conclusion `success`, AND (b) the diff\n  `\u003Crun headSha>..\u003Cintegration HEAD>` touches only paths `.github\u002Fworkflows\u002Fci.yml`\n  `paths-ignore`s. That is what makes an ordinary release work — staging HEAD is routinely a\n  notes-only commit which produces no CI run of its own, and that is normal, not a fault.\n  The range is anchored at the verified run's sha, never at `origin\u002F\u003Cproduction>` or a\n  release tag; both of those span real code on every release and would block everything,\n  including the resume path whose HEAD is the `[skip ci]` bump commit.\n\n### Overriding a blocking CI verdict\n\nIf CI genuinely cannot be reached — GitHub down, `gh` unauthenticated — the gate blocks and\nthat is correct. To release anyway, pass an override **with a reason**:\n\n```js\nmcp__rks__rks_release({\n  projectId: '\u003CprojectId>',\n  version: '\u003Cpatch|minor|major>',\n  changelog: '\u003Cthe release notes written in the write-the-release-notes step>',\n  notesCoverage: { '\u003CstoryId>': '\u003Cphrase copied from the notes>' },\n  enforcementOverride: { enabled: true, reason: 'why you are releasing without a CI verdict' },\n  _governorToken: '\u003Ctoken>',\n})\n```\n\n`enabled` must be literally `true` (it cannot default on) and `reason` must be non-empty —\nan override with a missing or blank reason is REJECTED, not quietly accepted. An applied\noverride is recorded in the `release.complete` telemetry as `ciGateOverridden` plus the\nreason, because an override that leaves no trace is indistinguishable from the fail-open\nthis gate exists to prevent. Supplying an override when the gate is *not* blocking does\nnothing and is not recorded.\n\n`enforcementOverride` waives only the CI gate. It does not waive release notes: a CI-overridden\nrelease still needs `changelog`, or a separate `notesOverride` on the user's explicit direction.\n\nIf any check fails, it returns `{ ok: false, error: '...' }` — report the error.\n\n### Step 3b: End the session\n\nAfter `rks_release` returns — on success AND on failure — end the ops session with the Step 2\ntoken. It is the last MCP call of this flow (backlog.feat.governor-session-end):\n\n```\nmcp__rks__rks_governor_end({\n  projectId: 'routekit-shell',\n  _governorToken: '\u003Ctoken from step 2>'\n})\n```\n\n`ended: false` with `reason: 'session_not_live'` is not an error. `end_blocked` is reported with\nits `blockedBy` and is not retried.\n\n### Step 4: Report result\n\nOn success, report:\n- New version and tag (e.g., `v0.19.5`)\n- Commit SHA\n- Number of stories transitioned to `released`\n- Remind the user to roll the release out to child projects — **two steps**:\n  1. Update the release mirror to the new tag (it's a checkout-only mirror, so `-f` safely discards local lockfile noise):\n     ```\n     cd ..\u002Froutekit-shell-release && git fetch origin --tags && git checkout -f v\u003Cnew-version>\n     ```\n  2. Upgrade **all** registered children **from the release** in one command (run from anywhere):\n     ```\n     routekit project upgrade --all --from-release ..\u002Froutekit-shell-release\n     ```\n     `--from-release` sources the release's hooks\u002Fskills\u002Fprompts\u002Fversion while still resolving children from your normal registry; it repins each child's `.mcp.json` and stamps its `rksVersion`. (For a single child: `routekit project upgrade --id \u003Cchild> --from-release ..\u002Froutekit-shell-release`.)\n  Then restart the MCP server in each child (snacks, concourse-prototype, etc.) to pick up the update.\n\nOn failure, report the error from `rks_release` and suggest diagnostics.\n\n## Notes\n\n- Uses ops flow Governor for token authorization\n- `rks_release` handles: version bump commit on staging, ff-merge main, tag on main, push\n- The tag is created on main after the ff-merge (not on staging)\n- Works for any registered project — replace the projectId above with the target projectId\n",{"name":5,"verbosity":24,"description":25,"user-invocable":26,"disable-model-invocation":20},"heartbeat","Use when the user wants to release staging to main. Initializes an ops Governor,\ncalls rks_release (which handles pre-flight checks, ff-merge, tagging, and push).\n$ARGUMENTS can be: patch (default), minor, or major.\n",true,"main","6a9c925d922b1e117c7b23879e8e4fa04171760d",".claude\u002Fskills\u002Frelease","https:\u002F\u002Fgithub.com\u002Fux287\u002Froutekit-shell","https:\u002F\u002Froutekit.dev","https:\u002F\u002Fgithub.com\u002Fux287","http:\u002F\u002Fux287.com","Founder, UX287","2026-11-13 02:43:25",{"source":8,"skillName":5,"commands":37,"prompt":47,"zipAvailable":26},[38,41,44],{"tool":39,"command":40},"npx","npx skills add ux287\u002Froutekit-shell --skill skills-release",{"tool":42,"command":43},"bunx","bunx skills add ux287\u002Froutekit-shell --skill skills-release",{"tool":45,"command":46},"pnpm","pnpm dlx skills add ux287\u002Froutekit-shell --skill skills-release","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fux287\u002Froutekit-shell\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Frelease\u002FSKILL.md",[],[]]